summaryrefslogtreecommitdiff
path: root/src/intersim2
diff options
context:
space:
mode:
authorDongdong Li <[email protected]>2013-08-08 00:15:58 -0800
committerAndrew Boktor <[email protected]>2014-08-14 13:50:58 -0700
commit7f49fe9feb174d34efc2a011bad79b38522a360b (patch)
treeab5b7b66e40315a81871acbf386722981020f866 /src/intersim2
parent5f91e7435742bab74dfbeca18afc63e466498f36 (diff)
Intesim2 Integration
Details: See Review 80001 https://gpgpu-sim-code-review.appspot.com/80001/ [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 16747]
Diffstat (limited to 'src/intersim2')
-rw-r--r--src/intersim2/Makefile176
-rw-r--r--src/intersim2/allocators/allocator.cpp481
-rw-r--r--src/intersim2/allocators/allocator.hpp158
-rw-r--r--src/intersim2/allocators/islip.cpp183
-rw-r--r--src/intersim2/allocators/islip.hpp48
-rw-r--r--src/intersim2/allocators/loa.cpp112
-rw-r--r--src/intersim2/allocators/loa.hpp49
-rw-r--r--src/intersim2/allocators/maxsize.cpp210
-rw-r--r--src/intersim2/allocators/maxsize.hpp51
-rw-r--r--src/intersim2/allocators/pim.cpp120
-rw-r--r--src/intersim2/allocators/pim.hpp47
-rw-r--r--src/intersim2/allocators/selalloc.cpp254
-rw-r--r--src/intersim2/allocators/selalloc.hpp55
-rw-r--r--src/intersim2/allocators/separable.cpp86
-rw-r--r--src/intersim2/allocators/separable.hpp61
-rw-r--r--src/intersim2/allocators/separable_input_first.cpp103
-rw-r--r--src/intersim2/allocators/separable_input_first.hpp52
-rw-r--r--src/intersim2/allocators/separable_output_first.cpp103
-rw-r--r--src/intersim2/allocators/separable_output_first.hpp50
-rw-r--r--src/intersim2/allocators/wavefront.cpp111
-rw-r--r--src/intersim2/allocators/wavefront.hpp57
-rw-r--r--src/intersim2/arbiters/arbiter.cpp111
-rw-r--r--src/intersim2/arbiters/arbiter.hpp86
-rw-r--r--src/intersim2/arbiters/matrix_arb.cpp121
-rw-r--r--src/intersim2/arbiters/matrix_arb.hpp71
-rw-r--r--src/intersim2/arbiters/prio_arb.cpp160
-rw-r--r--src/intersim2/arbiters/prio_arb.hpp68
-rw-r--r--src/intersim2/arbiters/roundrobin_arb.cpp80
-rw-r--r--src/intersim2/arbiters/roundrobin_arb.hpp75
-rw-r--r--src/intersim2/arbiters/tree_arb.cpp119
-rw-r--r--src/intersim2/arbiters/tree_arb.hpp71
-rw-r--r--src/intersim2/batchtrafficmanager.cpp220
-rw-r--r--src/intersim2/batchtrafficmanager.hpp75
-rw-r--r--src/intersim2/booksim.hpp43
-rw-r--r--src/intersim2/booksim_config.cpp346
-rw-r--r--src/intersim2/booksim_config.hpp53
-rw-r--r--src/intersim2/buffer.cpp83
-rw-r--r--src/intersim2/buffer.hpp161
-rw-r--r--src/intersim2/buffer_state.cpp676
-rw-r--r--src/intersim2/buffer_state.hpp239
-rw-r--r--src/intersim2/channel.hpp125
-rw-r--r--src/intersim2/config.l54
-rw-r--r--src/intersim2/config.y37
-rw-r--r--src/intersim2/config_utils.cpp447
-rw-r--r--src/intersim2/config_utils.hpp95
-rw-r--r--src/intersim2/credit.cpp79
-rw-r--r--src/intersim2/credit.hpp60
-rw-r--r--src/intersim2/examples/cmeshconfig47
-rw-r--r--src/intersim2/examples/dragonflyconfig79
-rw-r--r--src/intersim2/examples/fattree_config76
-rw-r--r--src/intersim2/examples/flatflyconfig116
-rw-r--r--src/intersim2/examples/mesh88_lat69
-rw-r--r--src/intersim2/examples/mesh88_lat_hotspot82
-rw-r--r--src/intersim2/examples/singleconfig57
-rw-r--r--src/intersim2/examples/torus8840
-rw-r--r--src/intersim2/flit.cpp107
-rw-r--r--src/intersim2/flit.hpp104
-rw-r--r--src/intersim2/flitchannel.cpp91
-rw-r--r--src/intersim2/flitchannel.hpp100
-rw-r--r--src/intersim2/globals.hpp56
-rw-r--r--src/intersim2/gputrafficmanager.cpp676
-rw-r--r--src/intersim2/gputrafficmanager.hpp74
-rw-r--r--src/intersim2/injection.cpp190
-rw-r--r--src/intersim2/injection.hpp68
-rw-r--r--src/intersim2/interconnect_interface.cpp501
-rw-r--r--src/intersim2/interconnect_interface.hpp131
-rw-r--r--src/intersim2/intersim_config.cpp54
-rw-r--r--src/intersim2/intersim_config.hpp39
-rw-r--r--src/intersim2/main.cpp209
-rw-r--r--src/intersim2/misc_utils.cpp52
-rw-r--r--src/intersim2/misc_utils.hpp34
-rw-r--r--src/intersim2/module.cpp88
-rw-r--r--src/intersim2/module.hpp62
-rw-r--r--src/intersim2/networks/anynet.cpp501
-rw-r--r--src/intersim2/networks/anynet.hpp69
-rw-r--r--src/intersim2/networks/cmesh.cpp856
-rw-r--r--src/intersim2/networks/cmesh.hpp95
-rw-r--r--src/intersim2/networks/dragonfly.cpp575
-rw-r--r--src/intersim2/networks/dragonfly.hpp74
-rw-r--r--src/intersim2/networks/fattree.cpp270
-rw-r--r--src/intersim2/networks/fattree.hpp76
-rw-r--r--src/intersim2/networks/flatfly_onchip.cpp1331
-rw-r--r--src/intersim2/networks/flatfly_onchip.hpp88
-rw-r--r--src/intersim2/networks/fly.cpp162
-rw-r--r--src/intersim2/networks/fly.hpp53
-rw-r--r--src/intersim2/networks/kncube.cpp319
-rw-r--r--src/intersim2/networks/kncube.hpp62
-rw-r--r--src/intersim2/networks/network.cpp290
-rw-r--r--src/intersim2/networks/network.hpp118
-rw-r--r--src/intersim2/networks/qtree.cpp187
-rw-r--r--src/intersim2/networks/qtree.hpp69
-rw-r--r--src/intersim2/networks/tree4.cpp289
-rw-r--r--src/intersim2/networks/tree4.hpp72
-rw-r--r--src/intersim2/outputset.cpp153
-rw-r--r--src/intersim2/outputset.hpp66
-rw-r--r--src/intersim2/packet_reply_info.cpp57
-rw-r--r--src/intersim2/packet_reply_info.hpp57
-rw-r--r--src/intersim2/pipefifo.hpp97
-rw-r--r--src/intersim2/power/buffer_monitor.cpp71
-rw-r--r--src/intersim2/power/buffer_monitor.hpp68
-rw-r--r--src/intersim2/power/power_module.cpp532
-rw-r--r--src/intersim2/power/power_module.hpp186
-rw-r--r--src/intersim2/power/switch_monitor.cpp67
-rw-r--r--src/intersim2/power/switch_monitor.hpp66
-rwxr-xr-xsrc/intersim2/power/techfile.txt26
-rw-r--r--src/intersim2/random_utils.hpp61
-rw-r--r--src/intersim2/rng-double.c112
-rw-r--r--src/intersim2/rng.c108
-rw-r--r--src/intersim2/rng_double_wrapper.cpp34
-rw-r--r--src/intersim2/rng_wrapper.cpp34
-rw-r--r--src/intersim2/routefunc.cpp1999
-rw-r--r--src/intersim2/routefunc.hpp48
-rw-r--r--src/intersim2/routers/chaos_router.cpp673
-rw-r--r--src/intersim2/routers/chaos_router.hpp132
-rw-r--r--src/intersim2/routers/event_router.cpp890
-rw-r--r--src/intersim2/routers/event_router.hpp187
-rw-r--r--src/intersim2/routers/iq_router.cpp2385
-rw-r--r--src/intersim2/routers/iq_router.hpp183
-rw-r--r--src/intersim2/routers/router.cpp155
-rw-r--r--src/intersim2/routers/router.hpp202
-rw-r--r--src/intersim2/stats.cpp130
-rw-r--r--src/intersim2/stats.hpp76
-rw-r--r--src/intersim2/timed_module.hpp44
-rw-r--r--src/intersim2/traffic.cpp518
-rw-r--r--src/intersim2/traffic.hpp174
-rw-r--r--src/intersim2/trafficmanager.cpp2287
-rw-r--r--src/intersim2/trafficmanager.hpp322
-rw-r--r--src/intersim2/vc.cpp223
-rw-r--r--src/intersim2/vc.hpp137
129 files changed, 27640 insertions, 0 deletions
diff --git a/src/intersim2/Makefile b/src/intersim2/Makefile
new file mode 100644
index 0000000..a0a04e9
--- /dev/null
+++ b/src/intersim2/Makefile
@@ -0,0 +1,176 @@
+# $Id $
+
+# Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Makefile
+#
+CXX = g++
+CC = gcc
+CREATE_LIBRARY ?= 0
+INTERFACE = interconnect_interface.cpp
+DEBUG ?= 0
+
+LEX = flex
+YACC = bison -y
+DEFINE = #-DTRACK_STALLS -DTRACK_BUFFERS -DTRACK_FLOWS -DTRACK_CREDITS
+INCPATH = -I. -Iarbiters -Iallocators -Irouters -Inetworks -Ipower
+
+ifeq ($(CREATE_LIBRARY),1)
+INCPATH += -I$(GPGPUSIM_ROOT)/src/gpgpu-sim/
+endif
+
+CPPFLAGS += -Wall $(INCPATH) $(DEFINE)
+ifneq ($(DEBUG),1)
+CPPFLAGS += -O3
+endif
+CPPFLAGS += -g
+CPPFLAGS += -fPIC
+LFLAGS +=
+
+
+ifeq ($(SIM_OBJ_FILES_DIR),)
+OBJDIR := obj
+else
+OBJDIR := $(SIM_OBJ_FILES_DIR)/intersim2
+endif
+PROG := booksim
+
+# simulator source files
+CPP_SRCS = \
+ config_utils.cpp \
+ booksim_config.cpp \
+ module.cpp \
+ buffer.cpp \
+ vc.cpp \
+ routefunc.cpp \
+ traffic.cpp \
+ flitchannel.cpp \
+ trafficmanager.cpp \
+ batchtrafficmanager.cpp \
+ packet_reply_info.cpp \
+ buffer_state.cpp \
+ stats.cpp \
+ credit.cpp \
+ outputset.cpp \
+ flit.cpp \
+ injection.cpp\
+ misc_utils.cpp\
+ rng_wrapper.cpp\
+ rng_double_wrapper.cpp\
+ power_module.cpp \
+ switch_monitor.cpp \
+ buffer_monitor.cpp \
+ main.cpp \
+ gputrafficmanager.cpp \
+ intersim_config.cpp
+
+ifeq ($(CREATE_LIBRARY),1)
+CPP_SRCS += $(INTERFACE)
+DEFINE += -DCREATE_LIBRARY
+endif
+
+
+LEX_OBJS = ${OBJDIR}/lex.yy.o
+YACC_OBJS = ${OBJDIR}/y.tab.o
+
+# networks
+NETWORKS:= $(wildcard networks/*.cpp)
+ALLOCATORS:= $(wildcard allocators/*.cpp)
+ARBITERS:= $(wildcard arbiters/*.cpp)
+ROUTERS:= $(wildcard routers/*.cpp)
+POWER:= $(wildcard power/*.cpp)
+
+#--- Make rules ---
+OBJS := $(LEX_OBJS) $(YACC_OBJS)\
+ $(CPP_SRCS:%.cpp=${OBJDIR}/%.o)\
+ $(NETWORKS:networks/%.cpp=${OBJDIR}/%.o)\
+ $(ALLOCATORS:allocators/%.cpp=${OBJDIR}/%.o)\
+ $(ARBITERS:arbiters/%.cpp=${OBJDIR}/%.o)\
+ $(ROUTERS:routers/%.cpp=${OBJDIR}/%.o)\
+ $(POWER:power/%.cpp=${OBJDIR}/%.o)
+
+.PHONY: clean
+
+ifeq ($(CREATE_LIBRARY),1)
+all: $(OBJS)
+else
+all:$(PROG)
+
+$(PROG): $(OBJS)
+ $(CXX) $(LFLAGS) $^ -o $@
+endif
+
+# rules to compile simulator
+
+
+${LEX_OBJS}: lex.yy.c y.tab.h
+ $(CC) $(CPPFLAGS) -c $< -o $@
+
+${YACC_OBJS}: y.tab.c y.tab.h
+ $(CC) $(CPPFLAGS) -c $< -o $@
+
+${OBJDIR}/%.o: %.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+# rules to compile networks
+${OBJDIR}/%.o: networks/%.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+# rules to compile arbiters
+${OBJDIR}/%.o: arbiters/%.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+# rules to compile allocators
+${OBJDIR}/%.o: allocators/%.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+# rules to compile routers
+${OBJDIR}/%.o: routers/%.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+# rules to compile power classes
+${OBJDIR}/%.o: power/%.cpp
+ $(CXX) $(CPPFLAGS) -c $< -o $@
+
+clean:
+ rm -f $(OBJS)
+ rm -f $(PROG)
+ rm -f *~
+ rm -f allocators/*~
+ rm -f arbiters/*~
+ rm -f networks/*~
+ rm -f runfiles/*~
+ rm -f routers/*~
+ rm -f examples/*~
+ rm -f y.tab.c y.tab.h lex.yy.c
+ rm -f moc_bgui.cpp
+
+y.tab.c y.tab.h: config.y
+ $(YACC) -d $<
+
+lex.yy.c: config.l
+ $(LEX) $<
+# DO NOT DELETE
diff --git a/src/intersim2/allocators/allocator.cpp b/src/intersim2/allocators/allocator.cpp
new file mode 100644
index 0000000..5940ac5
--- /dev/null
+++ b/src/intersim2/allocators/allocator.cpp
@@ -0,0 +1,481 @@
+// $Id: allocator.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include "allocator.hpp"
+
+/////////////////////////////////////////////////////////////////////////
+//Allocator types
+#include "maxsize.hpp"
+#include "pim.hpp"
+#include "islip.hpp"
+#include "loa.hpp"
+#include "wavefront.hpp"
+#include "selalloc.hpp"
+#include "separable_input_first.hpp"
+#include "separable_output_first.hpp"
+//
+/////////////////////////////////////////////////////////////////////////
+
+//==================================================
+// Allocator base class
+//==================================================
+
+Allocator::Allocator( Module *parent, const string& name,
+ int inputs, int outputs ) :
+Module( parent, name ), _inputs( inputs ), _outputs( outputs ), _dirty( false )
+{
+ _inmatch.resize(_inputs, -1);
+ _outmatch.resize(_outputs, -1);
+}
+
+void Allocator::Clear( )
+{
+ if(_dirty) {
+ _inmatch.assign(_inputs, -1);
+ _outmatch.assign(_outputs, -1);
+ _dirty = false;
+ }
+}
+
+void Allocator::AddRequest( int in, int out, int label, int in_pri,
+ int out_pri ) {
+
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+ assert( label >= 0 );
+ _dirty = true;
+}
+
+int Allocator::OutputAssigned( int in ) const
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+
+ return _inmatch[in];
+}
+
+int Allocator::InputAssigned( int out ) const
+{
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ return _outmatch[out];
+}
+
+void Allocator::PrintGrants( ostream * os ) const
+{
+ if(!os) os = &cout;
+
+ *os << "Input grants = [ ";
+ for ( int input = 0; input < _inputs; ++input ) {
+ if(_inmatch[input] >= 0) {
+ *os << input << " -> " << _inmatch[input] << " ";
+ }
+ }
+ *os << "], output grants = [ ";
+ for ( int output = 0; output < _outputs; ++output ) {
+ if(_outmatch[output] >= 0) {
+ *os << output << " -> " << _outmatch[output] << " ";
+ }
+ }
+ *os << "]." << endl;
+}
+
+//==================================================
+// DenseAllocator
+//==================================================
+
+DenseAllocator::DenseAllocator( Module *parent, const string& name,
+ int inputs, int outputs ) :
+ Allocator( parent, name, inputs, outputs )
+{
+ _request.resize(_inputs);
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _request[i].resize(_outputs);
+ for ( int j = 0; j < _outputs; ++j ) {
+ _request[i][j].label = -1;
+ }
+ }
+}
+
+void DenseAllocator::Clear( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ for ( int j = 0; j < _outputs; ++j ) {
+ _request[i][j].label = -1;
+ }
+ }
+ Allocator::Clear();
+}
+
+int DenseAllocator::ReadRequest( int in, int out ) const
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ return _request[in][out].label;
+}
+
+bool DenseAllocator::ReadRequest( sRequest &req, int in, int out ) const
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ req = _request[in][out];
+
+ return ( req.label >= 0 );
+}
+
+void DenseAllocator::AddRequest( int in, int out, int label,
+ int in_pri, int out_pri )
+{
+ Allocator::AddRequest(in, out, label, in_pri, out_pri);
+ assert( _request[in][out].label == -1 );
+
+ _request[in][out].label = label;
+ _request[in][out].in_pri = in_pri;
+ _request[in][out].out_pri = out_pri;
+}
+
+void DenseAllocator::RemoveRequest( int in, int out, int label )
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ _request[in][out].label = -1;
+}
+
+bool DenseAllocator::InputHasRequests( int in ) const
+{
+ for(int out = 0; out < _outputs; ++out) {
+ if(_request[in][out].label >= 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DenseAllocator::OutputHasRequests( int out ) const
+{
+ for(int in = 0; in < _inputs; ++in) {
+ if(_request[in][out].label >= 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int DenseAllocator::NumInputRequests( int in ) const
+{
+ int result = 0;
+ for(int out = 0; out < _outputs; ++out) {
+ if(_request[in][out].label >= 0) {
+ ++result;
+ }
+ }
+ return result;
+}
+
+int DenseAllocator::NumOutputRequests( int out ) const
+{
+ int result = 0;
+ for(int in = 0; in < _inputs; ++in) {
+ if(_request[in][out].label >= 0) {
+ ++result;
+ }
+ }
+ return result;
+}
+
+void DenseAllocator::PrintRequests( ostream * os ) const
+{
+ if(!os) os = &cout;
+
+ *os << "Input requests = [ ";
+ for ( int input = 0; input < _inputs; ++input ) {
+ bool print = false;
+ ostringstream ss;
+ for ( int output = 0; output < _outputs; ++output ) {
+ const sRequest & req = _request[input][output];
+ if ( req.label >= 0 ) {
+ print = true;
+ ss << output << "@" << req.in_pri << " ";
+ }
+ }
+ if(print) {
+ *os << input << " -> [ " << ss.str() << "] ";
+ }
+ }
+ *os << "], output requests = [ ";
+ for ( int output = 0; output < _outputs; ++output ) {
+ bool print = false;
+ ostringstream ss;
+ for ( int input = 0; input < _inputs; ++input ) {
+ const sRequest & req = _request[input][output];
+ if ( req.label >= 0 ) {
+ print = true;
+ ss << input << "@" << req.out_pri << " ";
+ }
+ }
+ if(print) {
+ *os << output << " -> [ " << ss.str() << "] ";
+ }
+ }
+ *os << "]." << endl;
+}
+
+//==================================================
+// SparseAllocator
+//==================================================
+
+SparseAllocator::SparseAllocator( Module *parent, const string& name,
+ int inputs, int outputs ) :
+ Allocator( parent, name, inputs, outputs )
+{
+ _in_req.resize(_inputs);
+ _out_req.resize(_outputs);
+}
+
+
+void SparseAllocator::Clear( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ if(!_in_req[i].empty())
+ _in_req[i].clear( );
+ }
+
+ for ( int j = 0; j < _outputs; ++j ) {
+ if(!_out_req[j].empty())
+ _out_req[j].clear( );
+ }
+
+ _in_occ.clear( );
+ _out_occ.clear( );
+
+ Allocator::Clear();
+}
+
+int SparseAllocator::ReadRequest( int in, int out ) const
+{
+ sRequest r;
+
+ if ( ! ReadRequest( r, in, out ) ) {
+ r.label = -1;
+ }
+
+ return r.label;
+}
+
+bool SparseAllocator::ReadRequest( sRequest &req, int in, int out ) const
+{
+ bool found;
+
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ map<int, sRequest>::const_iterator match = _in_req[in].find(out);
+ if ( match != _in_req[in].end( ) ) {
+ req = match->second;
+ found = true;
+ } else {
+ found = false;
+ }
+
+ return found;
+}
+
+void SparseAllocator::AddRequest( int in, int out, int label,
+ int in_pri, int out_pri )
+{
+ Allocator::AddRequest(in, out, label, in_pri, out_pri);
+ assert( _in_req[in].count(out) == 0 );
+ assert( _out_req[out].count(in) == 0 );
+
+ // insert into occupied inputs set if
+ // input is currently empty
+ if ( _in_req[in].empty( ) ) {
+ _in_occ.insert(in);
+ }
+
+ // similarly for the output
+ if ( _out_req[out].empty( ) ) {
+ _out_occ.insert(out);
+ }
+
+ sRequest req;
+ req.port = out;
+ req.label = label;
+ req.in_pri = in_pri;
+ req.out_pri = out_pri;
+
+ _in_req[in][out] = req;
+
+ req.port = in;
+
+ _out_req[out][in] = req;
+}
+
+void SparseAllocator::RemoveRequest( int in, int out, int label )
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) );
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+
+ assert( _in_req[in].count( out ) > 0 );
+ assert( _in_req[in][out].label == label );
+ _in_req[in].erase( out );
+
+ // remove from occupied inputs list if
+ // input is now empty
+ if ( _in_req[in].empty( ) ) {
+ _in_occ.erase(in);
+ }
+
+ // similarly for the output
+ assert( _out_req[out].count( in ) > 0 );
+ assert( _out_req[out][in].label == label );
+ _out_req[out].erase( in );
+
+ if ( _out_req[out].empty( ) ) {
+ _out_occ.erase(out);
+ }
+}
+
+bool SparseAllocator::InputHasRequests( int in ) const
+{
+ return _in_occ.count(in) > 0;
+}
+
+bool SparseAllocator::OutputHasRequests( int out ) const
+{
+ return _out_occ.count(out) > 0;
+}
+
+int SparseAllocator::NumInputRequests( int in ) const
+{
+ return _in_occ.count(in);
+}
+
+int SparseAllocator::NumOutputRequests( int out ) const
+{
+ return _out_occ.count(out);
+}
+
+void SparseAllocator::PrintRequests( ostream * os ) const
+{
+ map<int, sRequest>::const_iterator iter;
+
+ if(!os) os = &cout;
+
+ *os << "Input requests = [ ";
+ for ( int input = 0; input < _inputs; ++input ) {
+ if(!_in_req[input].empty()) {
+ *os << input << " -> [ ";
+ for ( iter = _in_req[input].begin( );
+ iter != _in_req[input].end( ); iter++ ) {
+ *os << iter->second.port << "@" << iter->second.in_pri << " ";
+ }
+ *os << "] ";
+ }
+ }
+ *os << "], output requests = [ ";
+ for ( int output = 0; output < _outputs; ++output ) {
+ if(!_out_req[output].empty()) {
+ *os << output << " -> ";
+ *os << "[ ";
+ for ( iter = _out_req[output].begin( );
+ iter != _out_req[output].end( ); iter++ ) {
+ *os << iter->second.port << "@" << iter->second.out_pri << " ";
+ }
+ *os << "] ";
+ }
+ }
+ *os << "]." << endl;
+}
+
+//==================================================
+// Global allocator allocation function
+//==================================================
+
+Allocator *Allocator::NewAllocator( Module *parent, const string& name,
+ const string &alloc_type,
+ int inputs, int outputs,
+ Configuration const * const config )
+{
+ Allocator *a = 0;
+
+ string alloc_name;
+ string param_str;
+ size_t left = alloc_type.find_first_of('(');
+ if(left == string::npos) {
+ alloc_name = alloc_type;
+ } else {
+ alloc_name = alloc_type.substr(0, left);
+ size_t right = alloc_type.find_last_of(')');
+ if(right == string::npos) {
+ param_str = alloc_type.substr(left+1);
+ } else {
+ param_str = alloc_type.substr(left+1, right-left-1);
+ }
+ }
+ if ( alloc_name == "max_size" ) {
+ a = new MaxSizeMatch( parent, name, inputs, outputs );
+ } else if ( alloc_name == "pim" ) {
+ int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str());
+ a = new PIM( parent, name, inputs, outputs, iters );
+ } else if ( alloc_name == "islip" ) {
+ int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str());
+ a = new iSLIP_Sparse( parent, name, inputs, outputs, iters );
+ } else if ( alloc_name == "loa" ) {
+ a = new LOA( parent, name, inputs, outputs );
+ } else if ( alloc_name == "wavefront" ) {
+ a = new Wavefront( parent, name, inputs, outputs );
+ } else if ( alloc_name == "rr_wavefront" ) {
+ a = new Wavefront( parent, name, inputs, outputs, true );
+ } else if ( alloc_name == "select" ) {
+ int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str());
+ a = new SelAlloc( parent, name, inputs, outputs, iters );
+ } else if (alloc_name == "separable_input_first") {
+ string arb_type = param_str.empty() ? (config ? config->GetStr("arb_type") : "round_robin") : param_str;
+ a = new SeparableInputFirstAllocator( parent, name, inputs, outputs,
+ arb_type );
+ } else if (alloc_name == "separable_output_first") {
+ string arb_type = param_str.empty() ? (config ? config->GetStr("arb_type") : "round_robin") : param_str;
+ a = new SeparableOutputFirstAllocator( parent, name, inputs, outputs,
+ arb_type );
+ }
+
+//==================================================
+// Insert new allocators here, add another else if
+//==================================================
+
+
+ return a;
+}
+
diff --git a/src/intersim2/allocators/allocator.hpp b/src/intersim2/allocators/allocator.hpp
new file mode 100644
index 0000000..ea4441a
--- /dev/null
+++ b/src/intersim2/allocators/allocator.hpp
@@ -0,0 +1,158 @@
+// $Id: allocator.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ALLOCATOR_HPP_
+#define _ALLOCATOR_HPP_
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "module.hpp"
+#include "config_utils.hpp"
+
+class Allocator : public Module {
+protected:
+ const int _inputs;
+ const int _outputs;
+
+ bool _dirty;
+
+ vector<int> _inmatch;
+ vector<int> _outmatch;
+
+public:
+
+ struct sRequest {
+ int port;
+ int label;
+ int in_pri;
+ int out_pri;
+ };
+
+ Allocator( Module *parent, const string& name,
+ int inputs, int outputs );
+
+ virtual void Clear( );
+
+ virtual int ReadRequest( int in, int out ) const = 0;
+ virtual bool ReadRequest( sRequest &req, int in, int out ) const = 0;
+
+ virtual void AddRequest( int in, int out, int label = 1,
+ int in_pri = 0, int out_pri = 0 );
+ virtual void RemoveRequest( int in, int out, int label = 1 ) = 0;
+
+ virtual void Allocate( ) = 0;
+
+ int OutputAssigned( int in ) const;
+ int InputAssigned( int out ) const;
+
+ virtual bool OutputHasRequests( int out ) const = 0;
+ virtual bool InputHasRequests( int in ) const = 0;
+
+ virtual int NumOutputRequests( int out ) const = 0;
+ virtual int NumInputRequests( int in ) const = 0;
+
+ virtual void PrintRequests( ostream * os = NULL ) const = 0;
+ void PrintGrants( ostream * os = NULL ) const;
+
+ static Allocator *NewAllocator( Module *parent, const string& name,
+ const string &alloc_type,
+ int inputs, int outputs,
+ Configuration const * const config = NULL );
+};
+
+//==================================================
+// A dense allocator stores the entire request
+// matrix.
+//==================================================
+
+class DenseAllocator : public Allocator {
+protected:
+ vector<vector<sRequest> > _request;
+
+public:
+ DenseAllocator( Module *parent, const string& name,
+ int inputs, int outputs );
+
+ void Clear( );
+
+ int ReadRequest( int in, int out ) const;
+ bool ReadRequest( sRequest &req, int in, int out ) const;
+
+ void AddRequest( int in, int out, int label = 1,
+ int in_pri = 0, int out_pri = 0 );
+ void RemoveRequest( int in, int out, int label = 1 );
+
+ bool OutputHasRequests( int out ) const;
+ bool InputHasRequests( int in ) const;
+
+ int NumOutputRequests( int out ) const;
+ int NumInputRequests( int in ) const;
+
+ void PrintRequests( ostream * os = NULL ) const;
+
+};
+
+//==================================================
+// A sparse allocator only stores the requests
+// (allows for a more efficient implementation).
+//==================================================
+
+class SparseAllocator : public Allocator {
+protected:
+ set<int> _in_occ;
+ set<int> _out_occ;
+
+ vector<map<int, sRequest> > _in_req;
+ vector<map<int, sRequest> > _out_req;
+
+public:
+ SparseAllocator( Module *parent, const string& name,
+ int inputs, int outputs );
+
+ void Clear( );
+
+ int ReadRequest( int in, int out ) const;
+ bool ReadRequest( sRequest &req, int in, int out ) const;
+
+ void AddRequest( int in, int out, int label = 1,
+ int in_pri = 0, int out_pri = 0 );
+ void RemoveRequest( int in, int out, int label = 1 );
+
+ bool OutputHasRequests( int out ) const;
+ bool InputHasRequests( int in ) const;
+
+ int NumOutputRequests( int out ) const;
+ int NumInputRequests( int in ) const;
+
+ void PrintRequests( ostream * os = NULL ) const;
+
+};
+
+#endif
diff --git a/src/intersim2/allocators/islip.cpp b/src/intersim2/allocators/islip.cpp
new file mode 100644
index 0000000..ab8f53d
--- /dev/null
+++ b/src/intersim2/allocators/islip.cpp
@@ -0,0 +1,183 @@
+// $Id: islip.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+
+#include "islip.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_ISLIP
+
+iSLIP_Sparse::iSLIP_Sparse( Module *parent, const string& name,
+ int inputs, int outputs, int iters ) :
+ SparseAllocator( parent, name, inputs, outputs ),
+ _iSLIP_iter(iters)
+{
+ _gptrs.resize(_outputs, 0);
+ _aptrs.resize(_inputs, 0);
+}
+
+void iSLIP_Sparse::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ map<int, sRequest>::iterator p;
+ bool wrapped;
+
+ for ( int iter = 0; iter < _iSLIP_iter; ++iter ) {
+ // Grant phase
+
+ vector<int> grants(_outputs, -1);
+
+ for ( output = 0; output < _outputs; ++output ) {
+
+ // Skip loop if there are no requests
+ // or the output is already matched
+ if ( ( _out_req[output].empty( ) ) ||
+ ( _outmatch[output] != -1 ) ) {
+ continue;
+ }
+
+ // A round-robin arbiter between input requests
+ input_offset = _gptrs[output];
+
+ p = _out_req[output].begin( );
+ while( ( p != _out_req[output].end( ) ) &&
+ ( p->second.port < input_offset ) ) {
+ p++;
+ }
+
+ wrapped = false;
+ while( (!wrapped) ||
+ ( ( p != _out_req[output].end( ) ) &&
+ ( p->second.port < input_offset ) ) ) {
+ if ( p == _out_req[output].end( ) ) {
+ if ( wrapped ) { break; }
+ // p is valid here because empty lists
+ // are skipped (above)
+ p = _out_req[output].begin( );
+ wrapped = true;
+ }
+
+ input = p->second.port;
+
+ // we know the output is free (above) and
+ // if the input is free, grant request
+ if ( _inmatch[input] == -1 ) {
+ grants[output] = input;
+ break;
+ }
+
+ p++;
+ }
+ }
+
+#ifdef DEBUG_ISLIP
+ cout << "grants: ";
+ for ( int i = 0; i < _outputs; ++i ) {
+ cout << grants[i] << " ";
+ }
+ cout << endl;
+
+ cout << "aptrs: ";
+ for ( int i = 0; i < _inputs; ++i ) {
+ cout << _aptrs[i] << " ";
+ }
+ cout << endl;
+#endif
+
+ // Accept phase
+
+ for ( input = 0; input < _inputs; ++input ) {
+
+ if ( _in_req[input].empty( ) ) {
+ continue;
+ }
+
+ // A round-robin arbiter between output grants
+ output_offset = _aptrs[input];
+
+ p = _in_req[input].begin( );
+ while( ( p != _in_req[input].end( ) ) &&
+ ( p->second.port < output_offset ) ) {
+ p++;
+ }
+
+ wrapped = false;
+ while( (!wrapped) ||
+ ( ( p != _in_req[input].end( ) ) &&
+ ( p->second.port < output_offset ) ) ) {
+ if ( p == _in_req[input].end( ) ) {
+ if ( wrapped ) { break; }
+ // p is valid here because empty lists
+ // are skipped (above)
+ p = _in_req[input].begin( );
+ wrapped = true;
+ }
+
+ output = p->second.port;
+
+ // we know the output is free (above) and
+ // if the input is free, grant request
+ if ( grants[output] == input ) {
+ // Accept
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+
+ // Only update pointers if accepted during the 1st iteration
+ if ( iter == 0 ) {
+ _gptrs[output] = ( input + 1 ) % _inputs;
+ _aptrs[input] = ( output + 1 ) % _outputs;
+ }
+
+ break;
+ }
+
+ p++;
+ }
+ }
+ }
+
+#ifdef DEBUG_ISLIP
+ cout << "input match: ";
+ for ( int i = 0; i < _inputs; ++i ) {
+ cout << _inmatch[i] << " ";
+ }
+ cout << endl;
+
+ cout << "output match: ";
+ for ( int j = 0; j < _outputs; ++j ) {
+ cout << _outmatch[j] << " ";
+ }
+ cout << endl;
+#endif
+}
diff --git a/src/intersim2/allocators/islip.hpp b/src/intersim2/allocators/islip.hpp
new file mode 100644
index 0000000..c0c5d2a
--- /dev/null
+++ b/src/intersim2/allocators/islip.hpp
@@ -0,0 +1,48 @@
+// $Id: islip.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ISLIP_HPP_
+#define _ISLIP_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class iSLIP_Sparse : public SparseAllocator {
+ int _iSLIP_iter;
+
+ vector<int> _gptrs;
+ vector<int> _aptrs;
+
+public:
+ iSLIP_Sparse( Module *parent, const string& name,
+ int inputs, int outputs, int iters );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim2/allocators/loa.cpp b/src/intersim2/allocators/loa.cpp
new file mode 100644
index 0000000..c24bbe3
--- /dev/null
+++ b/src/intersim2/allocators/loa.cpp
@@ -0,0 +1,112 @@
+// $Id: loa.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+
+#include "loa.hpp"
+#include "random_utils.hpp"
+
+LOA::LOA( Module *parent, const string& name,
+ int inputs, int outputs ) :
+ DenseAllocator( parent, name, inputs, outputs )
+{
+ _req.resize(inputs);
+ _counts.resize(outputs);
+
+ _rptr.resize(inputs);
+ _gptr.resize(outputs);
+}
+
+void LOA::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ int lonely;
+ int lonely_cnt;
+
+ // Count phase --- the number of requests
+ // per output is counted
+
+ for ( int j = 0; j < _outputs; ++j ) {
+ _counts[j] = 0;
+ for ( int i = 0; i < _inputs; ++i ) {
+ _counts[j] += ( _request[i][j].label != -1 ) ? 1 : 0;
+ }
+ }
+
+ // Request phase
+ for ( input = 0; input < _inputs; ++input ) {
+
+ // Find the lonely output
+ output_offset = _rptr[input];
+ lonely = -1;
+ lonely_cnt = _inputs + 1;
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ output = ( o + output_offset ) % _outputs;
+
+ if ( ( _request[input][output].label != -1 ) &&
+ ( _counts[output] < lonely_cnt ) ) {
+ lonely = output;
+ lonely_cnt = _counts[output];
+ }
+ }
+
+ // Request the lonely output (-1 for no request)
+ _req[input] = lonely;
+ }
+
+ // Grant phase
+ for ( output = 0; output < _outputs; ++output ) {
+ input_offset = _gptr[output];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ input = ( i + input_offset ) % _inputs;
+
+ if ( _req[input] == output ) {
+ // Grant!
+
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+
+ _rptr[input] = ( _rptr[input] + 1 ) % _outputs;
+ _gptr[output] = ( _gptr[output] + 1 ) % _inputs;
+
+ break;
+ }
+ }
+ }
+
+
+}
+
+
diff --git a/src/intersim2/allocators/loa.hpp b/src/intersim2/allocators/loa.hpp
new file mode 100644
index 0000000..c119c31
--- /dev/null
+++ b/src/intersim2/allocators/loa.hpp
@@ -0,0 +1,49 @@
+// $Id: loa.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _LOA_HPP_
+#define _LOA_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class LOA : public DenseAllocator {
+ vector<int> _counts;
+ vector<int> _req;
+
+ vector<int> _rptr;
+ vector<int> _gptr;
+
+public:
+ LOA( Module *parent, const string& name,
+ int inputs, int outputs );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim2/allocators/maxsize.cpp b/src/intersim2/allocators/maxsize.cpp
new file mode 100644
index 0000000..ce18dae
--- /dev/null
+++ b/src/intersim2/allocators/maxsize.cpp
@@ -0,0 +1,210 @@
+// $Id: maxsize.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ Neither the name of the Stanford University nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+
+#include "maxsize.hpp"
+
+// shortest augmenting path:
+//
+// for all unmatched left nodes,
+// push node onto work stack
+// end
+//
+// for all j,
+// from[j] = undefined
+// end
+//
+// do,
+//
+// while( !stack.empty ),
+//
+// nl = stack.pop
+// for each edge (nl,j),
+// if ( ( lmatch[nl] != j ) && ( from[j] == undefined ) ),
+// if ( rmatch[j] == undefined ),
+// stop // augmenting path found
+// else
+// from[j] = nl
+// newstack.push( rmatch[j] )
+// end
+// end
+// end
+// end
+//
+// stack = newstack
+// end
+//
+
+//#define DEBUG_MAXSIZE
+//#define PRINT_MATCHING
+
+MaxSizeMatch::MaxSizeMatch( Module *parent, const string& name,
+ int inputs, int outputs ) :
+ DenseAllocator( parent, name, inputs, outputs )
+{
+ _from.resize(outputs);
+ _s = new int [inputs];
+ _ns = new int [inputs];
+ _prio = 0;
+}
+
+MaxSizeMatch::~MaxSizeMatch( )
+{
+ delete [] _s;
+ delete [] _ns;
+}
+
+void MaxSizeMatch::Allocate( )
+{
+
+ // augment as many times as possible
+ // (this is an O(N^3) maximum-size matching algorithm)
+ while( _ShortestAugmenting( ) );
+
+ // next time, start at next input to ensure fairness
+ _prio = (_prio + 1) % _inputs;
+}
+
+
+bool MaxSizeMatch::_ShortestAugmenting( )
+{
+ int i, j, jn;
+ int slen, nslen;
+
+ // start with empty stack
+ slen = 0;
+
+ // push all unassigned inputs to the stack
+ for ( i = 0; i < _inputs; ++i ) {
+ j = (i + _prio) % _inputs;
+ if ( _inmatch[j] == -1 ) { // start with unmatched left nodes
+ _s[slen++] = j;
+ }
+ }
+
+ _from.assign(_inputs, -1);
+
+ for ( int iter = 0; iter < _inputs; iter++ ) {
+ nslen = 0;
+
+ for ( int e = 0; e < slen; ++e ) {
+ i = _s[e];
+
+ for ( j = 0; j < _outputs; ++j ) {
+ if ( ( _request[i][j].label != -1 ) && // edge (i,j) exists
+ ( _inmatch[i] != j ) && // (i,j) is not contained in the current matching
+ ( _from[j] == -1 ) ) { // no shorter path to j exists
+
+ _from[j] = i; // how did we get to j?
+
+#ifdef DEBUG_MAXSIZE
+ cout << " got to " << j << " from " << i << endl;
+#endif
+ if ( _outmatch[j] == -1 ) { // j is unmatched -- augmenting path found
+ goto found_augmenting;
+ } else { // j is matched
+ _ns[nslen] = _outmatch[j]; // add the destination of this edge to the leaf nodes
+ nslen++;
+
+#ifdef DEBUG_MAXSIZE
+ cout << " adding " << _outmatch[j] << endl;
+#endif
+ }
+ }
+ }
+ }
+
+ // no augmenting path found yet, swap stacks
+ int * t = _s;
+ _s = _ns;
+ _ns = t;
+ slen = nslen;
+ }
+
+ return false; // no augmenting paths
+
+ found_augmenting:
+
+ // the augmenting path ends at node j on the right
+
+#ifdef DEBUG_MAXSIZE
+ cout << "Found path: " << j << "c <- ";
+#endif
+
+ i = _from[j];
+ _outmatch[j] = i;
+
+#ifdef DEBUG_MAXSIZE
+ cout << i;
+#endif
+
+ while ( _inmatch[i] != -1 ) { // loop until the end of the path
+ jn = _inmatch[i]; // remove previous edge (i,jn) and add (i,j)
+ _inmatch[i] = j;
+
+#ifdef DEBUG_MAXSIZE
+ cout << " <- " << j << "c <- ";
+#endif
+
+ j = jn; // add edge from (jn,in)
+ i = _from[j];
+ _outmatch[j] = i;
+
+#ifdef DEBUG_MAXSIZE
+ cout << i;
+#endif
+ }
+
+#ifdef DEBUG_MAXSIZE
+ cout << endl;
+#endif
+
+ _inmatch[i] = j;
+
+#ifdef PRINT_MATCHING
+ cout << "left matching: ";
+
+ for ( i = 0; i < _inputs; i++ ) {
+ cout << _inmatch[i] << " ";
+ }
+ cout << endl;
+
+ cout << "right matching: ";
+ for ( i = 0; i < _outputs; i++ ) {
+ cout << _outmatch[i] << " ";
+ }
+ cout << endl;
+#endif
+
+ return true;
+}
diff --git a/src/intersim2/allocators/maxsize.hpp b/src/intersim2/allocators/maxsize.hpp
new file mode 100644
index 0000000..3a1afe9
--- /dev/null
+++ b/src/intersim2/allocators/maxsize.hpp
@@ -0,0 +1,51 @@
+// $Id: maxsize.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MAXSIZE_HPP_
+#define _MAXSIZE_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class MaxSizeMatch : public DenseAllocator {
+ vector<int> _from; // array to hold breadth-first tree
+ int *_s; // stack of leaf nodes in tree
+ int *_ns; // next stack
+ int _prio; // priority pointer to ensure fairness
+
+ bool _ShortestAugmenting( );
+
+public:
+ MaxSizeMatch( Module *parent, const string& name,
+ int inputs, int ouputs );
+ ~MaxSizeMatch( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim2/allocators/pim.cpp b/src/intersim2/allocators/pim.cpp
new file mode 100644
index 0000000..487a6d6
--- /dev/null
+++ b/src/intersim2/allocators/pim.cpp
@@ -0,0 +1,120 @@
+// $Id: pim.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+
+#include "pim.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_PIM
+
+PIM::PIM( Module *parent, const string& name,
+ int inputs, int outputs, int iters ) :
+ DenseAllocator( parent, name, inputs, outputs ),
+ _PIM_iter(iters)
+{
+}
+
+PIM::~PIM( )
+{
+}
+
+void PIM::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ for ( int iter = 0; iter < _PIM_iter; ++iter ) {
+ // Grant phase --- outputs randomly choose
+ // between one of their requests
+
+ vector<int> grants(_outputs, -1);
+
+ for ( output = 0; output < _outputs; ++output ) {
+
+ // A random arbiter between input requests
+ input_offset = RandomInt( _inputs - 1 );
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ input = ( i + input_offset ) % _inputs;
+
+ if ( ( _request[input][output].label != -1 ) &&
+ ( _inmatch[input] == -1 ) &&
+ ( _outmatch[output] == -1 ) ) {
+
+ // Grant
+ grants[output] = input;
+ break;
+ }
+ }
+ }
+
+ // Accept phase -- inputs randomly choose
+ // between input_speedup of their grants
+
+ for ( input = 0; input < _inputs; ++input ) {
+
+ // A random arbiter between output grants
+ output_offset = RandomInt( _outputs - 1 );
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ output = ( o + output_offset ) % _outputs;
+
+ if ( grants[output] == input ) {
+
+ // Accept
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG_PIM
+ if ( _outputs == 8 ) {
+ cout << "input match: " << endl;
+ for ( int i = 0; i < _inputs; ++i ) {
+ cout << " from " << i << " to " << _inmatch[i] << endl;
+ }
+ cout << endl;
+ }
+
+ cout << "output match: ";
+ for ( int j = 0; j < _outputs; ++j ) {
+ cout << _outmatch[j] << " ";
+ }
+ cout << endl;
+#endif
+}
+
+
diff --git a/src/intersim2/allocators/pim.hpp b/src/intersim2/allocators/pim.hpp
new file mode 100644
index 0000000..e4d709b
--- /dev/null
+++ b/src/intersim2/allocators/pim.hpp
@@ -0,0 +1,47 @@
+// $Id: pim.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _PIM_HPP_
+#define _PIM_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class PIM : public DenseAllocator {
+ int _PIM_iter;
+
+public:
+ PIM( Module *parent, const string& name,
+ int inputs, int outputs, int iters );
+
+ ~PIM( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim2/allocators/selalloc.cpp b/src/intersim2/allocators/selalloc.cpp
new file mode 100644
index 0000000..df42143
--- /dev/null
+++ b/src/intersim2/allocators/selalloc.cpp
@@ -0,0 +1,254 @@
+// $Id: selalloc.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <iostream>
+
+#include "selalloc.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_SELALLOC
+
+SelAlloc::SelAlloc( Module *parent, const string& name,
+ int inputs, int outputs, int iters ) :
+ SparseAllocator( parent, name, inputs, outputs )
+{
+ _iter = iters;
+
+ _gptrs.resize(outputs, 0);
+ _aptrs.resize(inputs, 0);
+ _outmask.resize(outputs, 0);
+}
+
+void SelAlloc::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ map<int, sRequest>::iterator p;
+ set<int>::iterator outer_iter;
+ bool wrapped;
+
+ int max_index;
+ int max_pri;
+
+ vector<int> grants(_outputs, -1);
+
+ for ( int iter = 0; iter < _iter; ++iter ) {
+ // Grant phase
+
+ for( outer_iter = _out_occ.begin( );
+ outer_iter != _out_occ.end( ); ++outer_iter ) {
+ output = *outer_iter;
+
+ // Skip loop if there are no requests
+ // or the output is already matched or
+ // the output is masked
+ if ( ( _out_req[output].empty( ) ) ||
+ ( _outmatch[output] != -1 ) ||
+ ( _outmask[output] != 0 ) ) {
+ continue;
+ }
+
+ // A round-robin arbiter between input requests
+ input_offset = _gptrs[output];
+
+ p = _out_req[output].begin( );
+ while( ( p != _out_req[output].end( ) ) &&
+ ( p->second.port < input_offset ) ) {
+ p++;
+ }
+
+ max_index = -1;
+ max_pri = 0;
+
+ wrapped = false;
+ while( (!wrapped) ||
+ ( ( p != _out_req[output].end() ) &&
+ ( p->second.port < input_offset ) ) ) {
+ if ( p == _out_req[output].end( ) ) {
+ if ( wrapped ) { break; }
+ // p is valid here because empty lists
+ // are skipped (above)
+ p = _out_req[output].begin( );
+ wrapped = true;
+ }
+
+ input = p->second.port;
+
+ // we know the output is free (above) and
+ // if the input is free, check if request is the
+ // highest priority so far
+ if ( ( _inmatch[input] == -1 ) &&
+ ( ( p->second.out_pri > max_pri ) || ( max_index == -1 ) ) ) {
+ max_pri = p->second.out_pri;
+ max_index = input;
+ }
+
+ p++;
+ }
+
+ if ( max_index != -1 ) { // grant
+ grants[output] = max_index;
+ }
+ }
+
+#ifdef DEBUG_SELALLOC
+ cout << "grants: ";
+ for ( int i = 0; i < _outputs; ++i ) {
+ cout << grants[i] << " ";
+ }
+ cout << endl;
+
+ cout << "aptrs: ";
+ for ( int i = 0; i < _inputs; ++i ) {
+ cout << _aptrs[i] << " ";
+ }
+ cout << endl;
+#endif
+
+ // Accept phase
+
+ for ( outer_iter = _in_occ.begin( );
+ outer_iter != _in_occ.end( ); ++outer_iter ) {
+ input = *outer_iter;
+
+ if ( _in_req[input].empty( ) ) {
+ continue;
+ }
+
+ // A round-robin arbiter between output grants
+ output_offset = _aptrs[input];
+
+ p = _in_req[input].begin( );
+ while( ( p != _in_req[input].end( ) ) &&
+ ( p->second.port < output_offset ) ) {
+ p++;
+ }
+
+ max_index = -1;
+ max_pri = 0;
+
+ wrapped = false;
+ while( (!wrapped) ||
+ ( ( p != _in_req[input].end() ) &&
+ ( p->second.port < output_offset ) ) ) {
+ if ( p == _in_req[input].end( ) ) {
+ if ( wrapped ) { break; }
+ // p is valid here because empty lists
+ // are skipped (above)
+ p = _in_req[input].begin( );
+ wrapped = true;
+ }
+
+ output = p->second.port;
+
+ // we know the output is free (above) and
+ // if the input is free, check if the highest
+ // priroity
+ if ( ( grants[output] == input ) &&
+ ( !_out_req[output].empty( ) ) &&
+ ( ( p->second.in_pri > max_pri ) || ( max_index == -1 ) ) ) {
+ max_pri = p->second.in_pri;
+ max_index = output;
+ }
+
+ p++;
+ }
+
+ if ( max_index != -1 ) {
+ // Accept
+ output = max_index;
+
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+
+ // Only update pointers if accepted during the 1st iteration
+ if ( iter == 0 ) {
+ _gptrs[output] = ( input + 1 ) % _inputs;
+ _aptrs[input] = ( output + 1 ) % _outputs;
+ }
+ }
+ }
+ }
+
+#ifdef DEBUG_SELALLOC
+ cout << "input match: ";
+ for ( int i = 0; i < _inputs; ++i ) {
+ cout << _inmatch[i] << " ";
+ }
+ cout << endl;
+
+ cout << "output match: ";
+ for ( int j = 0; j < _outputs; ++j ) {
+ cout << _outmatch[j] << " ";
+ }
+ cout << endl;
+#endif
+}
+
+void SelAlloc::MaskOutput( int out, int mask )
+{
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+ _outmask[out] = mask;
+}
+
+void SelAlloc::PrintRequests( ostream * os ) const
+{
+ map<int, sRequest>::const_iterator iter;
+
+ if(!os) os = &cout;
+
+ *os << "Input requests = [ ";
+ for ( int input = 0; input < _inputs; ++input ) {
+ *os << input << " -> [ ";
+ for ( iter = _in_req[input].begin( );
+ iter != _in_req[input].end( ); iter++ ) {
+ *os << iter->second.port << " ";
+ }
+ *os << "] ";
+ }
+ *os << "], output requests = [ ";
+ for ( int output = 0; output < _outputs; ++output ) {
+ *os << output << " -> ";
+ if ( _outmask[output] == 0 ) {
+ *os << "[ ";
+ for ( iter = _out_req[output].begin( );
+ iter != _out_req[output].end( ); iter++ ) {
+ *os << iter->second.port << " ";
+ }
+ *os << "] ";
+ } else {
+ *os << "masked ";
+ }
+ }
+ *os << "]." << endl;
+}
+
diff --git a/src/intersim2/allocators/selalloc.hpp b/src/intersim2/allocators/selalloc.hpp
new file mode 100644
index 0000000..9a0fe8c
--- /dev/null
+++ b/src/intersim2/allocators/selalloc.hpp
@@ -0,0 +1,55 @@
+// $Id: selalloc.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SELALLOC_HPP_
+#define _SELALLOC_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class SelAlloc : public SparseAllocator {
+ int _iter;
+
+ vector<int> _aptrs;
+ vector<int> _gptrs;
+
+ vector<int> _outmask;
+
+public:
+ SelAlloc( Module *parent, const string& name,
+ int inputs, int outputs, int iters );
+
+ void Allocate( );
+
+ void MaskOutput( int out, int mask = 1 );
+
+ virtual void PrintRequests( ostream * os = NULL ) const;
+
+};
+
+#endif
diff --git a/src/intersim2/allocators/separable.cpp b/src/intersim2/allocators/separable.cpp
new file mode 100644
index 0000000..dc15da6
--- /dev/null
+++ b/src/intersim2/allocators/separable.cpp
@@ -0,0 +1,86 @@
+// $Id: separable.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableAllocator: Separable Allocator Base Class
+//
+// ----------------------------------------------------------------------
+
+#include "separable.hpp"
+
+#include <sstream>
+
+#include "arbiter.hpp"
+
+SeparableAllocator::SeparableAllocator( Module* parent, const string& name,
+ int inputs, int outputs,
+ const string& arb_type )
+ : SparseAllocator( parent, name, inputs, outputs )
+{
+
+ _input_arb.resize(inputs);
+
+ for (int i = 0; i < inputs; ++i) {
+ ostringstream arb_name("arb_i");
+ arb_name << i;
+ _input_arb[i] = Arbiter::NewArbiter(this, arb_name.str(), arb_type, outputs);
+ }
+
+ _output_arb.resize(outputs);
+
+ for (int i = 0; i < outputs; ++i) {
+ ostringstream arb_name("arb_o");
+ arb_name << i;
+ _output_arb[i] = Arbiter::NewArbiter(this, arb_name.str( ), arb_type, inputs);
+ }
+
+}
+
+SeparableAllocator::~SeparableAllocator() {
+
+ for (int i = 0; i < _inputs; ++i) {
+ delete _input_arb[i];
+ }
+
+ for (int i = 0; i < _outputs; ++i) {
+ delete _output_arb[i];
+ }
+
+}
+
+void SeparableAllocator::Clear() {
+ for ( int i = 0 ; i < _inputs ; i++ ) {
+ if(_input_arb[i]-> _num_reqs)
+ _input_arb[i]->Clear();
+ }
+ for ( int o = 0; o < _outputs; o++ ) {
+ if(_output_arb[o]->_num_reqs)
+ _output_arb[o]->Clear();
+ }
+ SparseAllocator::Clear();
+}
diff --git a/src/intersim2/allocators/separable.hpp b/src/intersim2/allocators/separable.hpp
new file mode 100644
index 0000000..afd1efc
--- /dev/null
+++ b/src/intersim2/allocators/separable.hpp
@@ -0,0 +1,61 @@
+// $Id: separable.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableAllocator: Separable Allocator Base Class
+//
+// ----------------------------------------------------------------------
+
+#ifndef _SEPARABLE_HPP_
+#define _SEPARABLE_HPP_
+
+#include <vector>
+
+#include "allocator.hpp"
+
+class Arbiter;
+
+class SeparableAllocator : public SparseAllocator {
+
+protected:
+
+ vector<Arbiter*> _input_arb ;
+ vector<Arbiter*> _output_arb ;
+
+public:
+
+ SeparableAllocator( Module* parent, const string& name, int inputs,
+ int outputs, const string& arb_type ) ;
+
+ virtual ~SeparableAllocator() ;
+
+ virtual void Clear() ;
+
+} ;
+
+#endif
diff --git a/src/intersim2/allocators/separable_input_first.cpp b/src/intersim2/allocators/separable_input_first.cpp
new file mode 100644
index 0000000..3a682fa
--- /dev/null
+++ b/src/intersim2/allocators/separable_input_first.cpp
@@ -0,0 +1,103 @@
+// $Id: separable_input_first.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableInputFirstAllocator: Separable Input-First Allocator
+//
+// ----------------------------------------------------------------------
+
+#include "separable_input_first.hpp"
+
+#include "booksim.hpp"
+#include "arbiter.hpp"
+
+#include <vector>
+#include <iostream>
+#include <cstring>
+
+SeparableInputFirstAllocator::
+SeparableInputFirstAllocator( Module* parent, const string& name, int inputs,
+ int outputs, const string& arb_type )
+ : SeparableAllocator( parent, name, inputs, outputs, arb_type )
+{}
+
+void SeparableInputFirstAllocator::Allocate() {
+
+ set<int>::const_iterator port_iter = _in_occ.begin();
+ while(port_iter != _in_occ.end()) {
+
+ const int & input = *port_iter;
+
+ // add requests to the input arbiter
+
+ map<int, sRequest>::const_iterator req_iter = _in_req[input].begin();
+ while(req_iter != _in_req[input].end()) {
+
+ const sRequest & req = req_iter->second;
+
+ _input_arb[input]->AddRequest(req.port, req.label, req.in_pri);
+
+ ++req_iter;
+ }
+
+ // Execute the input arbiters and propagate the grants to the
+ // output arbiters.
+
+ int label = -1;
+ const int output = _input_arb[input]->Arbitrate(&label, NULL);
+ assert(output > -1);
+
+ const sRequest & req = _out_req[output][input];
+ assert((req.port == input) && (req.label == label));
+
+ _output_arb[output]->AddRequest(req.port, req.label, req.out_pri);
+
+ ++port_iter;
+ }
+
+ port_iter = _out_occ.begin();
+ while(port_iter != _out_occ.end()) {
+
+ const int & output = *port_iter;
+
+ // Execute the output arbiters.
+
+ const int input = _output_arb[output]->Arbitrate(NULL, NULL);
+
+ if(input > -1) {
+ assert((_inmatch[input] == -1) && (_outmatch[output] == -1));
+
+ _inmatch[input] = output ;
+ _outmatch[output] = input ;
+ _input_arb[input]->UpdateState() ;
+ _output_arb[output]->UpdateState() ;
+ }
+
+ ++port_iter;
+ }
+}
diff --git a/src/intersim2/allocators/separable_input_first.hpp b/src/intersim2/allocators/separable_input_first.hpp
new file mode 100644
index 0000000..c9ded06
--- /dev/null
+++ b/src/intersim2/allocators/separable_input_first.hpp
@@ -0,0 +1,52 @@
+// $Id: separable_input_first.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableInputFirstAllocator: Separable Input-First Allocator
+//
+// ----------------------------------------------------------------------
+
+#ifndef _SEPARABLE_INPUT_FIRST_HPP_
+#define _SEPARABLE_INPUT_FIRST_HPP_
+
+#include <set>
+
+#include "separable.hpp"
+
+class SeparableInputFirstAllocator : public SeparableAllocator {
+
+public:
+
+ SeparableInputFirstAllocator( Module* parent, const string& name, int inputs,
+ int outputs, const string& arb_type ) ;
+
+ virtual void Allocate() ;
+
+} ;
+
+#endif
diff --git a/src/intersim2/allocators/separable_output_first.cpp b/src/intersim2/allocators/separable_output_first.cpp
new file mode 100644
index 0000000..b72658f
--- /dev/null
+++ b/src/intersim2/allocators/separable_output_first.cpp
@@ -0,0 +1,103 @@
+// $Id: separable_output_first.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableOutputFirstAllocator: Separable Output-First Allocator
+//
+// ----------------------------------------------------------------------
+
+#include "separable_output_first.hpp"
+
+#include "booksim.hpp"
+#include "arbiter.hpp"
+
+#include <vector>
+#include <iostream>
+#include <cstring>
+
+SeparableOutputFirstAllocator::
+SeparableOutputFirstAllocator( Module* parent, const string& name, int inputs,
+ int outputs, const string& arb_type )
+ : SeparableAllocator( parent, name, inputs, outputs, arb_type )
+{}
+
+void SeparableOutputFirstAllocator::Allocate() {
+
+ set<int>::const_iterator port_iter = _out_occ.begin();
+ while(port_iter != _out_occ.end()) {
+
+ const int & output = *port_iter;
+
+ // add requests to the output arbiter
+
+ map<int, sRequest>::const_iterator req_iter = _out_req[output].begin();
+ while(req_iter != _out_req[output].end()) {
+
+ const sRequest & req = req_iter->second;
+
+ _output_arb[output]->AddRequest(req.port, req.label, req.out_pri);
+
+ ++req_iter;
+ }
+
+ // Execute the output arbiter and propagate the grants to the
+ // input arbiters.
+
+ int label = -1;
+ const int input = _output_arb[output]->Arbitrate(&label, NULL);
+ assert(input > -1);
+
+ const sRequest & req = _in_req[input][output];
+ assert((req.port == output) && (req.label == label));
+
+ _input_arb[input]->AddRequest(req.port, req.label, req.in_pri);
+
+ ++port_iter;
+ }
+
+ port_iter = _in_occ.begin();
+ while(port_iter != _in_occ.end()) {
+
+ const int & input = *port_iter;
+
+ // Execute the input arbiters.
+
+ const int output = _input_arb[input]->Arbitrate(NULL, NULL);
+
+ if(output > -1) {
+ assert((_inmatch[input] == -1) && (_outmatch[output] == -1));
+
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+ _input_arb[input]->UpdateState() ;
+ _output_arb[output]->UpdateState() ;
+ }
+
+ ++port_iter;
+ }
+}
diff --git a/src/intersim2/allocators/separable_output_first.hpp b/src/intersim2/allocators/separable_output_first.hpp
new file mode 100644
index 0000000..1103f0d
--- /dev/null
+++ b/src/intersim2/allocators/separable_output_first.hpp
@@ -0,0 +1,50 @@
+// $Id: separable_output_first.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// SeparableOutputFirstAllocator: Separable Output-First Allocator
+//
+// ----------------------------------------------------------------------
+
+#ifndef _SEPARABLE_OUTPUT_FIRST_HPP_
+#define _SEPARABLE_OUTPUT_FIRST_HPP_
+
+#include "separable.hpp"
+
+class SeparableOutputFirstAllocator : public SeparableAllocator {
+
+public:
+
+ SeparableOutputFirstAllocator( Module* parent, const string& name, int inputs,
+ int outputs, const string& arb_type ) ;
+
+ virtual void Allocate() ;
+
+} ;
+
+#endif
diff --git a/src/intersim2/allocators/wavefront.cpp b/src/intersim2/allocators/wavefront.cpp
new file mode 100644
index 0000000..39a4427
--- /dev/null
+++ b/src/intersim2/allocators/wavefront.cpp
@@ -0,0 +1,111 @@
+// $Id: wavefront.cpp 5262 2012-09-20 23:39:40Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*wavefront.cpp
+ *
+ *The wave front allocator
+ *
+ */
+#include "booksim.hpp"
+
+#include "wavefront.hpp"
+
+Wavefront::Wavefront( Module *parent, const string& name,
+ int inputs, int outputs, bool skip_diags ) :
+ DenseAllocator( parent, name, inputs, outputs ),
+ _last_in(-1), _last_out(-1), _skip_diags(skip_diags),
+ _square(max(inputs, outputs)), _pri(0), _num_requests(0)
+{
+}
+
+void Wavefront::AddRequest( int in, int out, int label,
+ int in_pri, int out_pri )
+{
+ DenseAllocator::AddRequest(in, out, label, in_pri, out_pri);
+ _num_requests++;
+ _last_in = in;
+ _last_out = out;
+ _priorities.insert(make_pair(out_pri, in_pri));
+}
+
+void Wavefront::Allocate( )
+{
+
+ int first_diag = -1;
+
+ if(_num_requests == 0)
+
+ // bypass allocator completely if there were no requests
+ return;
+
+ if(_num_requests == 1) {
+
+ // if we only had a single request, we can immediately grant it
+ _inmatch[_last_in] = _last_out;
+ _outmatch[_last_out] = _last_in;
+ first_diag = _last_in + _last_out;
+
+ } else {
+
+ // otherwise we have to loop through the diagonals of request matrix
+
+ for(set<pair<int, int> >::const_reverse_iterator iter =
+ _priorities.rbegin();
+ iter != _priorities.rend(); ++iter) {
+
+ for ( int p = 0; p < _square; ++p ) {
+ for ( int output = 0; output < _square; ++output ) {
+ int input = ( ( _pri + p ) + ( _square - output ) ) % _square;
+ if ( ( input < _inputs ) && ( output < _outputs ) &&
+ ( _inmatch[input] == -1 ) && ( _outmatch[output] == -1 ) &&
+ ( _request[input][output].label != -1 ) &&
+ ( _request[input][output].in_pri == iter->second ) &&
+ ( _request[input][output].out_pri == iter->first ) ) {
+ // Grant!
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+ if(first_diag < 0) {
+ first_diag = input + output;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ _num_requests = 0;
+ _last_in = -1;
+ _last_out = -1;
+ _priorities.clear();
+
+ assert(first_diag >= 0);
+
+ // Round-robin the priority diagonal
+ _pri = ( ( _skip_diags ? first_diag : _pri ) + 1 ) % _square;
+}
+
+
diff --git a/src/intersim2/allocators/wavefront.hpp b/src/intersim2/allocators/wavefront.hpp
new file mode 100644
index 0000000..0c36a36
--- /dev/null
+++ b/src/intersim2/allocators/wavefront.hpp
@@ -0,0 +1,57 @@
+// $Id: wavefront.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _WAVEFRONT_HPP_
+#define _WAVEFRONT_HPP_
+
+#include <set>
+
+#include "allocator.hpp"
+
+class Wavefront : public DenseAllocator {
+
+private:
+ int _last_in;
+ int _last_out;
+ set<pair<int, int> > _priorities;
+ bool _skip_diags;
+
+protected:
+ int _square;
+ int _pri;
+ int _num_requests;
+
+public:
+ Wavefront( Module *parent, const string& name,
+ int inputs, int outputs, bool skip_diags = false );
+
+ virtual void AddRequest( int in, int out, int label = 1,
+ int in_pri = 0, int out_pri = 0 );
+ virtual void Allocate( );
+};
+
+#endif
diff --git a/src/intersim2/arbiters/arbiter.cpp b/src/intersim2/arbiters/arbiter.cpp
new file mode 100644
index 0000000..5b4b38f
--- /dev/null
+++ b/src/intersim2/arbiters/arbiter.cpp
@@ -0,0 +1,111 @@
+// $Id: arbiter.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// Arbiter: Base class for Matrix and Round Robin Arbiter
+//
+// ----------------------------------------------------------------------
+
+#include "arbiter.hpp"
+#include "roundrobin_arb.hpp"
+#include "matrix_arb.hpp"
+#include "tree_arb.hpp"
+
+#include <limits>
+#include <cassert>
+
+using namespace std ;
+
+Arbiter::Arbiter( Module *parent, const string &name, int size )
+ : Module( parent, name ),
+ _size(size), _selected(-1), _highest_pri(numeric_limits<int>::min()),
+ _best_input(-1), _num_reqs(0)
+{
+ _request.resize(size);
+ for ( int i = 0 ; i < size ; i++ )
+ _request[i].valid = false ;
+}
+
+void Arbiter::AddRequest( int input, int id, int pri )
+{
+ assert( 0 <= input && input < _size ) ;
+ assert( !_request[input].valid );
+
+ _num_reqs++ ;
+ _request[input].valid = true ;
+ _request[input].id = id ;
+ _request[input].pri = pri ;
+}
+
+int Arbiter::Arbitrate( int* id, int* pri )
+{
+ if ( _selected != -1 ) {
+ if ( id )
+ *id = _request[_selected].id ;
+ if ( pri )
+ *pri = _request[_selected].pri ;
+ }
+
+ assert((_selected >= 0) || (_num_reqs == 0));
+
+ return _selected ;
+}
+
+void Arbiter::Clear()
+{
+ if(_num_reqs > 0) {
+
+ // clear the request vector
+ for ( int i = 0; i < _size ; i++ )
+ _request[i].valid = false ;
+ _num_reqs = 0 ;
+ _selected = -1;
+ }
+}
+
+Arbiter *Arbiter::NewArbiter( Module *parent, const string& name,
+ const string &arb_type, int size)
+{
+ Arbiter *a = NULL;
+ if(arb_type == "round_robin") {
+ a = new RoundRobinArbiter( parent, name, size );
+ } else if(arb_type == "matrix") {
+ a = new MatrixArbiter( parent, name, size );
+ } else if(arb_type.substr(0, 5) == "tree(") {
+ size_t left = 4;
+ size_t middle = arb_type.find_first_of(',');
+ assert(middle != string::npos);
+ size_t right = arb_type.find_last_of(')');
+ assert(right != string::npos);
+ string groups_str = arb_type.substr(left+1, middle-left-1);
+ int groups = atoi(groups_str.c_str());
+ string sub_arb_type = arb_type.substr(middle+1, right-middle-1);
+ a = new TreeArbiter( parent, name, size, groups, sub_arb_type );
+ } else assert(false);
+ return a;
+}
diff --git a/src/intersim2/arbiters/arbiter.hpp b/src/intersim2/arbiters/arbiter.hpp
new file mode 100644
index 0000000..456bd8f
--- /dev/null
+++ b/src/intersim2/arbiters/arbiter.hpp
@@ -0,0 +1,86 @@
+// $Id: arbiter.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// Arbiter: Base class for Matrix and Round Robin Arbiter
+//
+// ----------------------------------------------------------------------
+
+#ifndef _ARBITER_HPP_
+#define _ARBITER_HPP_
+
+#include <vector>
+
+#include "module.hpp"
+
+class Arbiter : public Module {
+
+protected:
+
+ typedef struct {
+ bool valid ;
+ int id ;
+ int pri ;
+ } entry_t ;
+
+ vector<entry_t> _request ;
+ int _size ;
+
+ int _selected ;
+ int _highest_pri;
+ int _best_input;
+
+public:
+ int _num_reqs ;
+ // Constructors
+ Arbiter( Module *parent, const string &name, int size ) ;
+
+ // Print priority matrix to standard output
+ virtual void PrintState() const = 0 ;
+
+ // Register request with arbiter
+ virtual void AddRequest( int input, int id, int pri ) ;
+
+ // Update priority matrix based on last aribtration result
+ virtual void UpdateState() = 0 ;
+
+ // Arbitrate amongst requests. Returns winning input and
+ // updates pointers to metadata when valid pointers are passed
+ virtual int Arbitrate( int* id = 0, int* pri = 0 ) ;
+
+ virtual void Clear();
+
+ inline int LastWinner() const {
+ return _selected;
+ }
+
+ static Arbiter *NewArbiter( Module *parent, const string &name,
+ const string &arb_type, int size );
+} ;
+
+#endif
diff --git a/src/intersim2/arbiters/matrix_arb.cpp b/src/intersim2/arbiters/matrix_arb.cpp
new file mode 100644
index 0000000..d087e19
--- /dev/null
+++ b/src/intersim2/arbiters/matrix_arb.cpp
@@ -0,0 +1,121 @@
+// $Id: matrix_arb.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// Matrix: Matrix Arbiter
+//
+// ----------------------------------------------------------------------
+
+#include "matrix_arb.hpp"
+#include <iostream>
+using namespace std ;
+
+MatrixArbiter::MatrixArbiter( Module *parent, const string &name, int size )
+ : Arbiter( parent, name, size ), _last_req(-1) {
+ _matrix.resize(size);
+ for ( int i = 0 ; i < size ; i++ ) {
+ _matrix[i].resize(size);
+ for ( int j = 0; j < i; j++ ) {
+ _matrix[i][j] = 1;
+ }
+ }
+}
+
+void MatrixArbiter::PrintState() const {
+ cout << "Priority Matrix: " << endl ;
+ for ( int r = 0; r < _size ; r++ ) {
+ for ( int c = 0 ; c < _size ; c++ ) {
+ cout << _matrix[r][c] << " " ;
+ }
+ cout << endl ;
+ }
+ cout << endl ;
+}
+
+void MatrixArbiter::UpdateState() {
+ // update priority matrix using last grant
+ if ( _selected > -1 ) {
+ for ( int i = 0; i < _size ; i++ ) {
+ if( _selected != i ) {
+ _matrix[_selected][i] = 0 ;
+ _matrix[i][_selected] = 1 ;
+ }
+ }
+ }
+}
+
+void MatrixArbiter::AddRequest( int input, int id, int pri )
+{
+ _last_req = input;
+ Arbiter::AddRequest(input, id, pri);
+}
+
+int MatrixArbiter::Arbitrate( int* id, int* pri ) {
+
+ // avoid running arbiter if it has not recevied at least two requests
+ // (in this case, requests and grants are identical)
+ if ( _num_reqs < 2 ) {
+
+ _selected = _last_req ;
+
+ } else {
+
+ _selected = -1 ;
+
+ for ( int input = 0 ; input < _size ; input++ ) {
+ if(_request[input].valid) {
+
+ bool grant = true;
+ for ( int i = 0 ; i < _size ; i++ ) {
+ if ( _request[i].valid &&
+ ( ( ( _request[i].pri == _request[input].pri ) &&
+ _matrix[i][input]) ||
+ ( _request[i].pri > _request[input].pri )
+ ) ) {
+ grant = false ;
+ break ;
+ }
+ }
+
+ if ( grant ) {
+ _selected = input ;
+ break ;
+ }
+ }
+
+ }
+ }
+
+ return Arbiter::Arbitrate(id, pri);
+}
+
+void MatrixArbiter::Clear()
+{
+ _last_req = -1;
+ Arbiter::Clear();
+}
diff --git a/src/intersim2/arbiters/matrix_arb.hpp b/src/intersim2/arbiters/matrix_arb.hpp
new file mode 100644
index 0000000..53d3724
--- /dev/null
+++ b/src/intersim2/arbiters/matrix_arb.hpp
@@ -0,0 +1,71 @@
+// $Id: matrix_arb.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// Matrix: Matrix Arbiter
+//
+// ----------------------------------------------------------------------
+
+#ifndef _MATRIX_ARB_HPP_
+#define _MATRIX_ARB_HPP_
+
+#include <vector>
+
+#include "arbiter.hpp"
+
+using namespace std;
+
+class MatrixArbiter : public Arbiter {
+
+ // Priority matrix
+ vector<vector<int> > _matrix ;
+
+ int _last_req ;
+
+public:
+
+ // Constructors
+ MatrixArbiter( Module *parent, const string &name, int size ) ;
+
+ // Print priority matrix to standard output
+ virtual void PrintState() const ;
+
+ // Update priority matrix based on last aribtration result
+ virtual void UpdateState() ;
+
+ // Arbitrate amongst requests. Returns winning input and
+ // updates pointers to metadata when valid pointers are passed
+ virtual int Arbitrate( int* id = 0, int* pri = 0) ;
+
+ virtual void AddRequest( int input, int id, int pri ) ;
+
+ virtual void Clear();
+
+} ;
+
+#endif
diff --git a/src/intersim2/arbiters/prio_arb.cpp b/src/intersim2/arbiters/prio_arb.cpp
new file mode 100644
index 0000000..9de2bc2
--- /dev/null
+++ b/src/intersim2/arbiters/prio_arb.cpp
@@ -0,0 +1,160 @@
+// $Id: prio_arb.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <cassert>
+
+#include "prio_arb.hpp"
+
+
+PriorityArbiter::PriorityArbiter( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs )
+: Module( parent, name ), _rr_ptr(0), _inputs( inputs )
+{
+
+}
+
+void PriorityArbiter::Clear( )
+{
+ _requests.clear( );
+}
+
+void PriorityArbiter::AddRequest( int in, int label, int pri )
+{
+ sRequest r;
+ list<sRequest>::iterator insert_point;
+
+ r.in = in; r.label = label; r.pri = pri;
+
+ insert_point = _requests.begin( );
+ while( ( insert_point != _requests.end( ) ) &&
+ ( insert_point->in < in ) ) {
+ insert_point++;
+ }
+
+ bool del = false;
+ bool add = true;
+
+ // For consistant behavior, delete the existing request
+ // if it is for the same input and has a higher
+ // priority
+
+ if ( ( insert_point != _requests.end( ) ) &&
+ ( insert_point->in == in ) ) {
+ if ( insert_point->pri < pri ) {
+ del = true;
+ } else {
+ add = false;
+ }
+ }
+
+ if ( add ) {
+ _requests.insert( insert_point, r );
+ }
+
+ if ( del ) {
+ _requests.erase( insert_point );
+ }
+}
+
+void PriorityArbiter::RemoveRequest( int in, int label )
+{
+ list<sRequest>::iterator erase_point;
+
+ erase_point = _requests.begin( );
+ while( ( erase_point != _requests.end( ) ) &&
+ ( erase_point->in < in ) ) {
+ erase_point++;
+ }
+
+ assert( erase_point != _requests.end( ) );
+ _requests.erase( erase_point );
+}
+
+int PriorityArbiter::Match( ) const
+{
+ return _match;
+}
+
+void PriorityArbiter::Arbitrate( )
+{
+ list<sRequest>::iterator p;
+
+ int max_index, max_pri;
+ bool wrapped;
+
+ //MERGENOTE
+ //booksim does not have this if statement
+ //as far as I can tell they are identical in function
+ if ( _requests.begin( ) != _requests.end( ) ) {
+ // A round-robin arbiter between input requests
+ p = _requests.begin( );
+ while( ( p != _requests.end( ) ) &&
+ ( p->in < _rr_ptr ) ) {
+ p++;
+ }
+
+ max_index = -1;
+ max_pri = 0;
+
+ wrapped = false;
+ while( (!wrapped) || ( p->in < _rr_ptr ) ) {
+ if ( p == _requests.end( ) ) {
+ if ( wrapped ) { break; }
+ // p is valid here because empty lists
+ // are skipped (above)
+ p = _requests.begin( );
+ wrapped = true;
+ }
+
+ // check if request is the highest priority so far
+ if ( ( p->pri > max_pri ) || ( max_index == -1 ) ) {
+ max_pri = p->pri;
+ max_index = p->in;
+ }
+
+ p++;
+ }
+
+ _match = max_index; // -1 for no match
+ if ( _match != -1 ) {
+ _rr_ptr = ( _match + 1 ) % _inputs;
+ }
+
+ } else {
+ _match = -1;
+ }
+}
+
+//MERGENOTE
+//added update function to priorityarbiter
+
+void PriorityArbiter::Update( )
+{
+ _rr_ptr = ( _rr_ptr + 1 ) % _inputs;
+}
diff --git a/src/intersim2/arbiters/prio_arb.hpp b/src/intersim2/arbiters/prio_arb.hpp
new file mode 100644
index 0000000..0f7b737
--- /dev/null
+++ b/src/intersim2/arbiters/prio_arb.hpp
@@ -0,0 +1,68 @@
+// $Id: prio_arb.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _PRIO_ARB_HPP_
+#define _PRIO_ARB_HPP_
+
+#include <list>
+
+#include "module.hpp"
+#include "config_utils.hpp"
+
+class PriorityArbiter : public Module {
+ int _rr_ptr;
+
+protected:
+ const int _inputs;
+
+ struct sRequest {
+ int in;
+ int label;
+ int pri;
+ };
+
+ list<sRequest> _requests;
+
+ int _match;
+
+public:
+ PriorityArbiter( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs );
+
+ void Clear( );
+
+ void AddRequest( int in, int label = 0, int pri = 0 );
+ void RemoveRequest( int in, int label = 0 );
+
+ int Match( ) const;
+
+ void Arbitrate( );
+ void Update( );
+};
+
+#endif
diff --git a/src/intersim2/arbiters/roundrobin_arb.cpp b/src/intersim2/arbiters/roundrobin_arb.cpp
new file mode 100644
index 0000000..f338381
--- /dev/null
+++ b/src/intersim2/arbiters/roundrobin_arb.cpp
@@ -0,0 +1,80 @@
+// $Id: roundrobin_arb.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// RoundRobin: RoundRobin Arbiter
+//
+// ----------------------------------------------------------------------
+
+#include "roundrobin_arb.hpp"
+#include <iostream>
+#include <limits>
+
+using namespace std ;
+
+RoundRobinArbiter::RoundRobinArbiter( Module *parent, const string &name,
+ int size )
+ : Arbiter( parent, name, size ), _pointer( 0 ) {
+}
+
+void RoundRobinArbiter::PrintState() const {
+ cout << "Round Robin Priority Pointer: " << endl ;
+ cout << " _pointer = " << _pointer << endl ;
+}
+
+void RoundRobinArbiter::UpdateState() {
+ // update priority matrix using last grant
+ if ( _selected > -1 )
+ _pointer = ( _selected + 1 ) % _size ;
+}
+
+void RoundRobinArbiter::AddRequest( int input, int id, int pri )
+{
+ if(!_request[input].valid || (_request[input].pri < pri)) {
+ if((_num_reqs == 0) ||
+ Supersedes(input, pri, _best_input, _highest_pri, _pointer,_size )) {
+ _highest_pri = pri;
+ _best_input = input;
+ }
+ }
+ Arbiter::AddRequest(input, id, pri);
+}
+
+int RoundRobinArbiter::Arbitrate( int* id, int* pri ) {
+
+ _selected = _best_input;
+
+ return Arbiter::Arbitrate(id, pri);
+}
+
+void RoundRobinArbiter::Clear()
+{
+ _highest_pri = numeric_limits<int>::min();
+ _best_input = -1;
+ Arbiter::Clear();
+}
diff --git a/src/intersim2/arbiters/roundrobin_arb.hpp b/src/intersim2/arbiters/roundrobin_arb.hpp
new file mode 100644
index 0000000..8062270
--- /dev/null
+++ b/src/intersim2/arbiters/roundrobin_arb.hpp
@@ -0,0 +1,75 @@
+// $Id: roundrobin_arb.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// RoundRobin: Round Robin Arbiter
+//
+// ----------------------------------------------------------------------
+
+#ifndef _ROUNDROBIN_HPP_
+#define _ROUNDROBIN_HPP_
+
+#include "arbiter.hpp"
+
+class RoundRobinArbiter : public Arbiter {
+
+ // Priority pointer
+ int _pointer ;
+
+public:
+
+ // Constructors
+ RoundRobinArbiter( Module *parent, const string &name, int size ) ;
+
+ // Print priority matrix to standard output
+ virtual void PrintState() const ;
+
+ // Update priority matrix based on last aribtration result
+ virtual void UpdateState() ;
+
+ // Arbitrate amongst requests. Returns winning input and
+ // updates pointers to metadata when valid pointers are passed
+ virtual int Arbitrate( int* id = 0, int* pri = 0) ;
+
+ virtual void AddRequest( int input, int id, int pri ) ;
+
+ virtual void Clear();
+
+ static inline bool Supersedes(int input1, int pri1, int input2, int pri2, int offset, int size)
+ {
+ // in a round-robin scheme with the given number of positions and current
+ // offset, should a request at input1 with priority pri1 supersede a
+ // request at input2 with priority pri2?
+ return ((pri1 > pri2) ||
+ ((pri1 == pri2) &&
+ (((input1 - offset + size) % size) < ((input2 - offset + size) % size))));
+ }
+
+} ;
+
+#endif
diff --git a/src/intersim2/arbiters/tree_arb.cpp b/src/intersim2/arbiters/tree_arb.cpp
new file mode 100644
index 0000000..11033dc
--- /dev/null
+++ b/src/intersim2/arbiters/tree_arb.cpp
@@ -0,0 +1,119 @@
+// $Id: tree_arb.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// TreeArbiter
+//
+// ----------------------------------------------------------------------
+
+#include "tree_arb.hpp"
+#include <iostream>
+#include <sstream>
+
+using namespace std ;
+
+TreeArbiter::TreeArbiter( Module *parent, const string &name,
+ int size, int groups, const string & arb_type )
+ : Arbiter( parent, name, size ) {
+ assert(size % groups == 0);
+ _group_arbiters.resize(groups);
+ _group_reqs.resize(groups, 0);
+ _group_size = size / groups;
+ for(int i = 0; i < groups; ++i) {
+ ostringstream group_arb_name;
+ group_arb_name << "group_arb" << i;
+ _group_arbiters[i] = Arbiter::NewArbiter(this, group_arb_name.str(), arb_type, _group_size);
+ }
+ _global_arbiter = Arbiter::NewArbiter(this, "global_arb", arb_type, groups);
+}
+
+TreeArbiter::~TreeArbiter() {
+ for(int i = 0; i < (int)_group_arbiters.size(); ++i) {
+ delete _group_arbiters[i];
+ }
+ delete _global_arbiter;
+}
+
+void TreeArbiter::PrintState() const {
+ for(int i = 0; i < (int)_group_arbiters.size(); ++i) {
+ cout << "Group arbiter " << i << ":" << endl;
+ _group_arbiters[i]->PrintState();
+ }
+ cout << "Global arbiter:" << endl;
+ _global_arbiter->PrintState();
+}
+
+void TreeArbiter::UpdateState() {
+ if(_selected > -1) {
+ int last_winner = _global_arbiter->LastWinner();
+ assert(last_winner >= 0 && last_winner < (int)_group_arbiters.size());
+ _group_arbiters[last_winner]->UpdateState();
+ _global_arbiter->UpdateState();
+ }
+}
+
+void TreeArbiter::AddRequest( int input, int id, int pri )
+{
+ Arbiter::AddRequest(input, id, pri);
+ int group_index = input / _group_size;
+ _group_arbiters[group_index]->AddRequest( input % _group_size, id, pri );
+ ++_group_reqs[group_index];
+}
+
+int TreeArbiter::Arbitrate( int* id, int* pri ) {
+ if(!_num_reqs) {
+ return -1;
+ }
+ for(int i = 0; i < (int)_group_arbiters.size(); ++i) {
+ if(_group_reqs[i]) {
+ int group_id, group_pri;
+ _group_arbiters[i]->Arbitrate(&group_id, &group_pri);
+ _global_arbiter->AddRequest(i, group_id, group_pri);
+ }
+ }
+ int group = _global_arbiter->Arbitrate(NULL, NULL);
+ assert(group >= 0 && group < (int)_group_arbiters.size());
+ int group_sel = _group_arbiters[group]->LastWinner();
+ assert(group_sel >= 0 && group_sel < _group_size);
+ _selected = group * _group_size + group_sel;
+ assert(_selected >= 0 && _selected < _size);
+ return Arbiter::Arbitrate(id, pri);
+}
+
+void TreeArbiter::Clear()
+{
+ if(!_num_reqs) {
+ return;
+ }
+ for(int i = 0; i < (int)_group_arbiters.size(); ++i) {
+ _group_arbiters[i]->Clear();
+ _group_reqs[i] = 0;
+ }
+ _global_arbiter->Clear();
+ Arbiter::Clear();
+}
diff --git a/src/intersim2/arbiters/tree_arb.hpp b/src/intersim2/arbiters/tree_arb.hpp
new file mode 100644
index 0000000..4350e56
--- /dev/null
+++ b/src/intersim2/arbiters/tree_arb.hpp
@@ -0,0 +1,71 @@
+// $Id: tree_arb.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// TreeArbiter
+//
+// ----------------------------------------------------------------------
+
+#ifndef _TREE_ARB_HPP_
+#define _TREE_ARB_HPP_
+
+#include "arbiter.hpp"
+
+class TreeArbiter : public Arbiter {
+
+ int _group_size ;
+
+ vector<Arbiter *> _group_arbiters;
+ Arbiter * _global_arbiter;
+
+ vector<int> _group_reqs;
+
+public:
+
+ // Constructors
+ TreeArbiter( Module *parent, const string &name, int size, int groups, const string & arb_type ) ;
+
+ ~TreeArbiter();
+
+ // Print priority matrix to standard output
+ virtual void PrintState() const ;
+
+ // Update priority matrix based on last aribtration result
+ virtual void UpdateState() ;
+
+ // Arbitrate amongst requests. Returns winning input and
+ // updates pointers to metadata when valid pointers are passed
+ virtual int Arbitrate( int* id = 0, int* pri = 0) ;
+
+ virtual void AddRequest( int input, int id, int pri ) ;
+
+ virtual void Clear();
+
+} ;
+
+#endif
diff --git a/src/intersim2/batchtrafficmanager.cpp b/src/intersim2/batchtrafficmanager.cpp
new file mode 100644
index 0000000..c32076c
--- /dev/null
+++ b/src/intersim2/batchtrafficmanager.cpp
@@ -0,0 +1,220 @@
+// $Id: batchtrafficmanager.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <limits>
+#include <sstream>
+#include <fstream>
+
+#include "packet_reply_info.hpp"
+#include "random_utils.hpp"
+#include "batchtrafficmanager.hpp"
+
+BatchTrafficManager::BatchTrafficManager( const Configuration &config,
+ const vector<Network *> & net )
+: TrafficManager(config, net), _last_id(-1), _last_pid(-1),
+ _overall_min_batch_time(0), _overall_avg_batch_time(0),
+ _overall_max_batch_time(0)
+{
+
+ _max_outstanding = config.GetInt ("max_outstanding_requests");
+
+ _batch_size = config.GetInt( "batch_size" );
+ _batch_count = config.GetInt( "batch_count" );
+
+ _batch_time = new Stats( this, "batch_time", 1.0, 1000 );
+ _stats["batch_time"] = _batch_time;
+
+ string sent_packets_out_file = config.GetStr( "sent_packets_out" );
+ if(sent_packets_out_file == "") {
+ _sent_packets_out = NULL;
+ } else {
+ _sent_packets_out = new ofstream(sent_packets_out_file.c_str());
+ }
+}
+
+BatchTrafficManager::~BatchTrafficManager( )
+{
+ delete _batch_time;
+ if(_sent_packets_out) delete _sent_packets_out;
+}
+
+void BatchTrafficManager::_RetireFlit( Flit *f, int dest )
+{
+ _last_id = f->id;
+ _last_pid = f->pid;
+ TrafficManager::_RetireFlit(f, dest);
+}
+
+int BatchTrafficManager::_IssuePacket( int source, int cl )
+{
+ int result = 0;
+ if(_use_read_write[cl]) { //read write packets
+ //check queue for waiting replies.
+ //check to make sure it is on time yet
+ if(!_repliesPending[source].empty()) {
+ if(_repliesPending[source].front()->time <= _time) {
+ result = -1;
+ }
+ } else {
+ if((_packet_seq_no[source] < _batch_size) &&
+ ((_max_outstanding <= 0) ||
+ (_requestsOutstanding[source] < _max_outstanding))) {
+
+ //coin toss to determine request type.
+ result = (RandomFloat() < 0.5) ? 2 : 1;
+
+ _requestsOutstanding[source]++;
+ }
+ }
+ } else { //normal
+ if((_packet_seq_no[source] < _batch_size) &&
+ ((_max_outstanding <= 0) ||
+ (_requestsOutstanding[source] < _max_outstanding))) {
+ result = _GetNextPacketSize(cl);
+ _requestsOutstanding[source]++;
+ }
+ }
+ if(result != 0) {
+ _packet_seq_no[source]++;
+ }
+ return result;
+}
+
+void BatchTrafficManager::_ClearStats( )
+{
+ TrafficManager::_ClearStats();
+ _batch_time->Clear( );
+}
+
+bool BatchTrafficManager::_SingleSim( )
+{
+ int batch_index = 0;
+ while(batch_index < _batch_count) {
+ _packet_seq_no.assign(_nodes, 0);
+ _last_id = -1;
+ _last_pid = -1;
+ _sim_state = running;
+ int start_time = _time;
+ bool batch_complete;
+ cout << "Sending batch " << batch_index + 1 << " (" << _batch_size << " packets)..." << endl;
+ do {
+ _Step();
+ batch_complete = true;
+ for(int i = 0; i < _nodes; ++i) {
+ if(_packet_seq_no[i] < _batch_size) {
+ batch_complete = false;
+ break;
+ }
+ }
+ if(_sent_packets_out) {
+ *_sent_packets_out << _packet_seq_no << endl;
+ }
+ } while(!batch_complete);
+ cout << "Batch injected. Time used is " << _time - start_time << " cycles." << endl;
+
+ int sent_time = _time;
+ cout << "Waiting for batch to complete..." << endl;
+
+ int empty_steps = 0;
+
+ bool packets_left = false;
+ for(int c = 0; c < _classes; ++c) {
+ packets_left |= !_total_in_flight_flits[c].empty();
+ }
+
+ while( packets_left ) {
+ _Step( );
+
+ ++empty_steps;
+
+ if ( empty_steps % 1000 == 0 ) {
+ _DisplayRemaining( );
+ cout << ".";
+ }
+
+ packets_left = false;
+ for(int c = 0; c < _classes; ++c) {
+ packets_left |= !_total_in_flight_flits[c].empty();
+ }
+ }
+ cout << endl;
+ cout << "Batch received. Time used is " << _time - sent_time << " cycles." << endl
+ << "Last packet was " << _last_pid << ", last flit was " << _last_id << "." << endl;
+
+ _batch_time->AddSample(_time - start_time);
+
+ cout << _sim_state << endl;
+
+ UpdateStats();
+ DisplayStats();
+
+ ++batch_index;
+ }
+ _sim_state = draining;
+ _drain_time = _time;
+ return 1;
+}
+
+void BatchTrafficManager::_UpdateOverallStats() {
+ TrafficManager::_UpdateOverallStats();
+ _overall_min_batch_time += _batch_time->Min();
+ _overall_avg_batch_time += _batch_time->Average();
+ _overall_max_batch_time += _batch_time->Max();
+}
+
+string BatchTrafficManager::_OverallStatsCSV(int c) const
+{
+ ostringstream os;
+ os << TrafficManager::_OverallStatsCSV(c) << ','
+ << _overall_min_batch_time / (double)_total_sims << ','
+ << _overall_avg_batch_time / (double)_total_sims << ','
+ << _overall_max_batch_time / (double)_total_sims;
+ return os.str();
+}
+
+void BatchTrafficManager::WriteStats(ostream & os) const
+{
+ TrafficManager::WriteStats(os);
+ os << "batch_time = " << _batch_time->Average() << ";" << endl;
+}
+
+void BatchTrafficManager::DisplayStats(ostream & os) const {
+ TrafficManager::DisplayStats();
+ os << "Minimum batch duration = " << _batch_time->Min() << endl;
+ os << "Average batch duration = " << _batch_time->Average() << endl;
+ os << "Maximum batch duration = " << _batch_time->Max() << endl;
+}
+
+void BatchTrafficManager::DisplayOverallStats(ostream & os) const {
+ TrafficManager::DisplayOverallStats(os);
+ os << "Overall min batch duration = " << _overall_min_batch_time / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Overall min batch duration = " << _overall_avg_batch_time / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Overall min batch duration = " << _overall_max_batch_time / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+}
diff --git a/src/intersim2/batchtrafficmanager.hpp b/src/intersim2/batchtrafficmanager.hpp
new file mode 100644
index 0000000..4a78e2c
--- /dev/null
+++ b/src/intersim2/batchtrafficmanager.hpp
@@ -0,0 +1,75 @@
+// $Id: batchtrafficmanager.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BATCHTRAFFICMANAGER_HPP_
+#define _BATCHTRAFFICMANAGER_HPP_
+
+#include <iostream>
+
+#include "config_utils.hpp"
+#include "stats.hpp"
+#include "trafficmanager.hpp"
+
+class BatchTrafficManager : public TrafficManager {
+
+protected:
+
+ int _max_outstanding;
+ int _batch_size;
+ int _batch_count;
+ int _last_id;
+ int _last_pid;
+
+ Stats * _batch_time;
+ double _overall_min_batch_time;
+ double _overall_avg_batch_time;
+ double _overall_max_batch_time;
+
+ ostream * _sent_packets_out;
+
+ virtual void _RetireFlit( Flit *f, int dest );
+
+ virtual int _IssuePacket( int source, int cl );
+ virtual void _ClearStats( );
+ virtual bool _SingleSim( );
+
+ virtual void _UpdateOverallStats( );
+
+ virtual string _OverallStatsCSV(int c = 0) const;
+
+public:
+
+ BatchTrafficManager( const Configuration &config, const vector<Network *> & net );
+ virtual ~BatchTrafficManager( );
+
+ virtual void WriteStats( ostream & os = cout ) const;
+ virtual void DisplayStats( ostream & os = cout ) const;
+ virtual void DisplayOverallStats( ostream & os = cout ) const;
+
+};
+
+#endif
diff --git a/src/intersim2/booksim.hpp b/src/intersim2/booksim.hpp
new file mode 100644
index 0000000..4c55af3
--- /dev/null
+++ b/src/intersim2/booksim.hpp
@@ -0,0 +1,43 @@
+// $Id: booksim.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BOOKSIM_HPP_
+#define _BOOKSIM_HPP_
+
+#include <string>
+#include <cstdlib>
+#include <cstring>
+#include <climits>
+#include <cassert>
+#ifdef _WIN32_
+#pragma warning (disable: 4786)
+#include <ostream>
+#endif
+
+using namespace std;
+
+#endif
diff --git a/src/intersim2/booksim_config.cpp b/src/intersim2/booksim_config.cpp
new file mode 100644
index 0000000..392121b
--- /dev/null
+++ b/src/intersim2/booksim_config.cpp
@@ -0,0 +1,346 @@
+// $Id: booksim_config.cpp 5506 2013-05-07 21:22:23Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*booksim_config.cpp
+ *
+ *Contains all the configurable parameters in a network
+ *
+ */
+
+
+#include "booksim.hpp"
+#include "booksim_config.hpp"
+
+BookSimConfig::BookSimConfig( )
+{
+ //========================================================
+ // Network options
+ //========================================================
+
+ // Channel length listing file
+ AddStrField( "channel_file", "" ) ;
+
+ // Physical sub-networks
+ _int_map["subnets"] = 1;
+
+ //==== Topology options =======================
+ AddStrField( "topology", "torus" );
+ _int_map["k"] = 8; //network radix
+ _int_map["n"] = 2; //network dimension
+ _int_map["c"] = 1; //concentration
+ AddStrField( "routing_function", "none" );
+
+ //simulator tries to correclty adjust latency for node/router placement
+ _int_map["use_noc_latency"] = 1;
+
+
+ //used for noc latency calcualtion for network with concentration
+ _int_map["x"] = 8; //number of routers in X
+ _int_map["y"] = 8; //number of routers in Y
+ _int_map["xr"] = 1; //number of nodes per router in X only if c>1
+ _int_map["yr"] = 1; //number of nodes per router in Y only if c>1
+
+
+ _int_map["link_failures"] = 0; //legacy
+ _int_map["fail_seed"] = 0; //legacy
+
+ //==== Single-node options ===============================
+
+ _int_map["in_ports"] = 5;
+ _int_map["out_ports"] = 5;
+
+ //========================================================
+ // Router options
+ //========================================================
+
+ //==== General options ===================================
+
+ AddStrField( "router", "iq" );
+
+ _int_map["output_delay"] = 0;
+ _int_map["credit_delay"] = 0;
+ _float_map["internal_speedup"] = 1.0;
+
+ //with switch speedup flits requires otuput buffering
+ //full output buffer will cancel switch allocation requests
+ //default setting is unlimited
+ _int_map["output_buffer_size"] = -1;
+
+ // enable next-hop-output queueing
+ _int_map["noq"] = 0;
+
+ //==== Input-queued ======================================
+
+ // Control of virtual channel speculation
+ _int_map["speculative"] = 0 ;
+ _int_map["spec_check_elig"] = 1 ;
+ _int_map["spec_check_cred"] = 1 ;
+ _int_map["spec_mask_by_reqs"] = 0 ;
+ AddStrField("spec_sw_allocator", "prio");
+
+ _int_map["num_vcs"] = 16;
+ _int_map["vc_buf_size"] = 8; //per vc buffer size
+ _int_map["buf_size"] = -1; //shared buffer size
+ AddStrField("buffer_policy", "private"); //buffer sharing policy
+
+ _int_map["private_bufs"] = -1;
+ _int_map["private_buf_size"] = 1;
+ AddStrField("private_buf_size", "");
+ _int_map["private_buf_start_vc"] = -1;
+ AddStrField("private_buf_start_vc", "");
+ _int_map["private_buf_end_vc"] = -1;
+ AddStrField("private_buf_end_vc", "");
+
+ _int_map["max_held_slots"] = -1;
+
+ _int_map["feedback_aging_scale"] = 1;
+ _int_map["feedback_offset"] = 0;
+
+ _int_map["wait_for_tail_credit"] = 0; // reallocate a VC before a tail credit?
+ _int_map["vc_busy_when_full"] = 0; // mark VCs as in use when they have no credit available
+ _int_map["vc_prioritize_empty"] = 0; // prioritize empty VCs over non-empty ones in VC allocation
+ _int_map["vc_priority_donation"] = 0; // allow high-priority flits to donate their priority to low-priority that they are queued up behind
+ _int_map["vc_shuffle_requests"] = 0; // rearrange VC allocator requests to avoid unfairness
+
+ _int_map["hold_switch_for_packet"] = 0; // hold a switch config for the entire packet
+
+ _int_map["input_speedup"] = 1; // expansion of input ports into crossbar
+ _int_map["output_speedup"] = 1; // expansion of output ports into crossbar
+
+ _int_map["routing_delay"] = 1;
+ _int_map["vc_alloc_delay"] = 1;
+ _int_map["sw_alloc_delay"] = 1;
+ _int_map["st_prepare_delay"] = 0;
+ _int_map["st_final_delay"] = 1;
+
+ //==== Event-driven =====================================
+
+ _int_map["vct"] = 0;
+
+ //==== Allocators ========================================
+
+ AddStrField( "vc_allocator", "islip" );
+ AddStrField( "sw_allocator", "islip" );
+
+ AddStrField( "arb_type", "round_robin" );
+
+ _int_map["alloc_iters"] = 1;
+
+ //==== Traffic ========================================
+
+ _int_map["classes"] = 1;
+
+ AddStrField( "traffic", "uniform" );
+
+ _int_map["class_priority"] = 0;
+ AddStrField("class_priority", ""); // workaraound to allow for vector specification
+
+ _int_map["perm_seed"] = 0; // seed value for random permuation trafficpattern generator
+
+ _float_map["injection_rate"] = 0.1;
+ AddStrField("injection_rate", ""); // workaraound to allow for vector specification
+
+ _int_map["injection_rate_uses_flits"] = 0;
+
+ // number of flits per packet
+ _int_map["packet_size"] = 1;
+ AddStrField("packet_size", ""); // workaraound to allow for vector specification
+
+ // if multiple values are specified per class, set probabilities for each
+ _int_map["packet_size_rate"] = 1;
+ AddStrField("packet_size_rate", ""); // workaraound to allow for vector specification
+
+ AddStrField( "injection_process", "bernoulli" );
+
+ _float_map["burst_alpha"] = 0.5; // burst interval
+ _float_map["burst_beta"] = 0.5; // burst length
+ _float_map["burst_r1"] = -1.0; // burst rate
+
+ AddStrField( "priority", "none" ); // message priorities
+
+ _int_map["batch_size"] = 1000;
+ _int_map["batch_count"] = 1;
+ _int_map["max_outstanding_requests"] = 0; // 0 = unlimited
+
+ // Use read/write request reply scheme
+ _int_map["use_read_write"] = 0;
+ AddStrField("use_read_write", ""); // workaraound to allow for vector specification
+ _float_map["write_fraction"] = 0.5;
+ AddStrField("write_fraction", "");
+
+ // Control assignment of packets to VCs
+ _int_map["read_request_begin_vc"] = 0;
+ _int_map["read_request_end_vc"] = 5;
+ _int_map["write_request_begin_vc"] = 2;
+ _int_map["write_request_end_vc"] = 7;
+ _int_map["read_reply_begin_vc"] = 8;
+ _int_map["read_reply_end_vc"] = 13;
+ _int_map["write_reply_begin_vc"] = 10;
+ _int_map["write_reply_end_vc"] = 15;
+
+ // Control Injection of Packets into Replicated Networks
+ _int_map["read_request_subnet"] = 0;
+ _int_map["read_reply_subnet"] = 0;
+ _int_map["write_request_subnet"] = 0;
+ _int_map["write_reply_subnet"] = 0;
+
+ // Set packet length in flits
+ _int_map["read_request_size"] = 1;
+ AddStrField("read_request_size", ""); // workaraound to allow for vector specification
+ _int_map["write_request_size"] = 1;
+ AddStrField("write_request_size", ""); // workaraound to allow for vector specification
+ _int_map["read_reply_size"] = 1;
+ AddStrField("read_reply_size", ""); // workaraound to allow for vector specification
+ _int_map["write_reply_size"] = 1;
+ AddStrField("write_reply_size", ""); // workaraound to allow for vector specification
+
+ //==== Simulation parameters ==========================
+
+ // types:
+ // latency - average + latency distribution for a particular injection rate
+ // throughput - sustained throughput for a particular injection rate
+
+ AddStrField( "sim_type", "latency" );
+
+ _int_map["warmup_periods"] = 3; // number of samples periods to "warm-up" the simulation
+
+ _int_map["sample_period"] = 1000; // how long between measurements
+ _int_map["max_samples"] = 10; // maximum number of sample periods in a simulation
+
+ // whether or not to measure statistics for a given traffic class
+ _int_map["measure_stats"] = 1;
+ AddStrField("measure_stats", ""); // workaround to allow for vector specification
+ //whether to enable per pair statistics, caution N^2 memory usage
+ _int_map["pair_stats"] = 0;
+
+ // if avg. latency exceeds the threshold, assume unstable
+ _float_map["latency_thres"] = 500.0;
+ AddStrField("latency_thres", ""); // workaround to allow for vector specification
+
+ // consider warmed up once relative change in latency / throughput between successive iterations is smaller than this
+ _float_map["warmup_thres"] = 0.05;
+ AddStrField("warmup_thres", ""); // workaround to allow for vector specification
+ _float_map["acc_warmup_thres"] = 0.05;
+ AddStrField("acc_warmup_thres", ""); // workaround to allow for vector specification
+
+ // consider converged once relative change in latency / throughput between successive iterations is smaller than this
+ _float_map["stopping_thres"] = 0.05;
+ AddStrField("stopping_thres", ""); // workaround to allow for vector specification
+ _float_map["acc_stopping_thres"] = 0.05;
+ AddStrField("acc_stopping_thres", ""); // workaround to allow for vector specification
+
+ _int_map["sim_count"] = 1; // number of simulations to perform
+
+
+ _int_map["include_queuing"] =1; // non-zero includes source queuing latency
+
+ // _int_map["reorder"] = 0; // know what you're doing
+
+ //_int_map["flit_timing"] = 0; // know what you're doing
+ //_int_map["split_packets"] = 0; // know what you're doing
+
+ _int_map["seed"] = 0; //random seed for simulation, e.g. traffic
+
+ _int_map["print_activity"] = 0;
+
+ _int_map["print_csv_results"] = 0;
+
+ _int_map["deadlock_warn_timeout"] = 256;
+
+ _int_map["viewer_trace"] = 0;
+
+ AddStrField("watch_file", "");
+
+ AddStrField("watch_flits", "");
+ AddStrField("watch_packets", "");
+ AddStrField("watch_transactions", "");
+
+ AddStrField("watch_out", "");
+
+ AddStrField("stats_out", "");
+
+#ifdef TRACK_FLOWS
+ AddStrField("injected_flits_out", "");
+ AddStrField("received_flits_out", "");
+ AddStrField("stored_flits_out", "");
+ AddStrField("sent_flits_out", "");
+ AddStrField("outstanding_credits_out", "");
+ AddStrField("ejected_flits_out", "");
+ AddStrField("active_packets_out", "");
+#endif
+
+#ifdef TRACK_CREDITS
+ AddStrField("used_credits_out", "");
+ AddStrField("free_credits_out", "");
+ AddStrField("max_credits_out", "");
+#endif
+
+ // batch only -- packet sequence numbers
+ AddStrField("sent_packets_out", "");
+
+ //==================Power model params=====================
+ _int_map["sim_power"] = 0;
+ AddStrField("power_output_file","pwr_tmp");
+ AddStrField("tech_file", "");
+ _int_map["channel_width"] = 128;
+ _int_map["channel_sweep"] = 0;
+
+ //==================Network file===========================
+ AddStrField("network_file","");
+}
+
+
+
+PowerConfig::PowerConfig( )
+{
+
+ _int_map["H_INVD2"] = 0;
+ _int_map["W_INVD2"] = 0;
+ _int_map["H_DFQD1"] = 0;
+ _int_map["W_DFQD1"] = 0;
+ _int_map["H_ND2D1"] = 0;
+ _int_map["W_ND2D1"] = 0;
+ _int_map["H_SRAM"] = 0;
+ _int_map["W_SRAM"] = 0;
+ _float_map["Vdd"] = 0;
+ _float_map["R"] = 0;
+ _float_map["IoffSRAM"] = 0;
+ _float_map["IoffP"] = 0;
+ _float_map["IoffN"] = 0;
+ _float_map["Cg_pwr"] = 0;
+ _float_map["Cd_pwr"] = 0;
+ _float_map["Cgdl"] = 0;
+ _float_map["Cg"] = 0;
+ _float_map["Cd"] = 0;
+ _float_map["LAMBDA"] = 0;
+ _float_map["MetalPitch"] = 0;
+ _float_map["Rw"] = 0;
+ _float_map["Cw_gnd"] = 0;
+ _float_map["Cw_cpl"] = 0;
+ _float_map["wire_length"] = 0;
+
+}
diff --git a/src/intersim2/booksim_config.hpp b/src/intersim2/booksim_config.hpp
new file mode 100644
index 0000000..9ecdb40
--- /dev/null
+++ b/src/intersim2/booksim_config.hpp
@@ -0,0 +1,53 @@
+// $Id: booksim_config.hpp 5487 2013-02-27 08:16:18Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BOOKSIM_CONFIG_HPP_
+#define _BOOKSIM_CONFIG_HPP_
+
+#include "config_utils.hpp"
+
+class BookSimConfig : public Configuration {
+protected:
+
+public:
+ BookSimConfig( );
+};
+
+#endif
+
+#ifndef _POWER_CONFIG_HPP_
+#define _POWER_CONFIG_HPP_
+
+#include "config_utils.hpp"
+
+class PowerConfig : public Configuration {
+public:
+ PowerConfig( );
+
+};
+
+#endif
diff --git a/src/intersim2/buffer.cpp b/src/intersim2/buffer.cpp
new file mode 100644
index 0000000..25f78e9
--- /dev/null
+++ b/src/intersim2/buffer.cpp
@@ -0,0 +1,83 @@
+// $Id: buffer.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sstream>
+
+#include "globals.hpp"
+#include "booksim.hpp"
+#include "buffer.hpp"
+
+Buffer::Buffer( const Configuration& config, int outputs,
+ Module *parent, const string& name ) :
+Module( parent, name ), _occupancy(0)
+{
+ int num_vcs = config.GetInt( "num_vcs" );
+
+ _size = config.GetInt("buf_size");
+ if(_size < 0) {
+ _size = num_vcs * config.GetInt( "vc_buf_size" );
+ };
+
+ _vc.resize(num_vcs);
+
+ for(int i = 0; i < num_vcs; ++i) {
+ ostringstream vc_name;
+ vc_name << "vc_" << i;
+ _vc[i] = new VC(config, outputs, this, vc_name.str( ) );
+ }
+
+#ifdef TRACK_BUFFERS
+ int classes = config.GetInt("classes");
+ _class_occupancy.resize(classes, 0);
+#endif
+}
+
+Buffer::~Buffer()
+{
+ for(vector<VC*>::iterator i = _vc.begin(); i != _vc.end(); ++i) {
+ delete *i;
+ }
+}
+
+void Buffer::AddFlit( int vc, Flit *f )
+{
+ if(_occupancy >= _size) {
+ Error("Flit buffer overflow.");
+ }
+ ++_occupancy;
+ _vc[vc]->AddFlit(f);
+#ifdef TRACK_BUFFERS
+ ++_class_occupancy[f->cl];
+#endif
+}
+
+void Buffer::Display( ostream & os ) const
+{
+ for(vector<VC*>::const_iterator i = _vc.begin(); i != _vc.end(); ++i) {
+ (*i)->Display(os);
+ }
+}
diff --git a/src/intersim2/buffer.hpp b/src/intersim2/buffer.hpp
new file mode 100644
index 0000000..a6a0b7a
--- /dev/null
+++ b/src/intersim2/buffer.hpp
@@ -0,0 +1,161 @@
+// $Id: buffer.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BUFFER_HPP_
+#define _BUFFER_HPP_
+
+#include <vector>
+
+#include "vc.hpp"
+#include "flit.hpp"
+#include "outputset.hpp"
+#include "routefunc.hpp"
+#include "config_utils.hpp"
+
+class Buffer : public Module {
+
+ int _occupancy;
+ int _size;
+
+ vector<VC*> _vc;
+
+#ifdef TRACK_BUFFERS
+ vector<int> _class_occupancy;
+#endif
+
+public:
+
+ Buffer( const Configuration& config, int outputs,
+ Module *parent, const string& name );
+ ~Buffer();
+
+ void AddFlit( int vc, Flit *f );
+
+ inline Flit *RemoveFlit( int vc )
+ {
+ --_occupancy;
+#ifdef TRACK_BUFFERS
+ int cl = _vc[vc]->FrontFlit()->cl;
+ assert(_class_occupancy[cl] > 0);
+ --_class_occupancy[cl];
+#endif
+ return _vc[vc]->RemoveFlit( );
+ }
+
+ inline Flit *FrontFlit( int vc ) const
+ {
+ return _vc[vc]->FrontFlit( );
+ }
+
+ inline bool Empty( int vc ) const
+ {
+ return _vc[vc]->Empty( );
+ }
+
+ inline bool Full( ) const
+ {
+ return _occupancy >= _size;
+ }
+
+ inline VC::eVCState GetState( int vc ) const
+ {
+ return _vc[vc]->GetState( );
+ }
+
+ inline void SetState( int vc, VC::eVCState s )
+ {
+ _vc[vc]->SetState(s);
+ }
+
+ inline const OutputSet *GetRouteSet( int vc ) const
+ {
+ return _vc[vc]->GetRouteSet( );
+ }
+
+ inline void SetRouteSet( int vc, OutputSet * output_set )
+ {
+ _vc[vc]->SetRouteSet(output_set);
+ }
+
+ inline void SetOutput( int vc, int out_port, int out_vc )
+ {
+ _vc[vc]->SetOutput(out_port, out_vc);
+ }
+
+ inline int GetOutputPort( int vc ) const
+ {
+ return _vc[vc]->GetOutputPort( );
+ }
+
+ inline int GetOutputVC( int vc ) const
+ {
+ return _vc[vc]->GetOutputVC( );
+ }
+
+ inline int GetPriority( int vc ) const
+ {
+ return _vc[vc]->GetPriority( );
+ }
+
+ inline void Route( int vc, tRoutingFunction rf, const Router* router, const Flit* f, int in_channel )
+ {
+ _vc[vc]->Route(rf, router, f, in_channel);
+ }
+
+ // ==== Debug functions ====
+
+ inline void SetWatch( int vc, bool watch = true )
+ {
+ _vc[vc]->SetWatch(watch);
+ }
+
+ inline bool IsWatched( int vc ) const
+ {
+ return _vc[vc]->IsWatched( );
+ }
+
+ inline int GetOccupancy( ) const
+ {
+ return _occupancy;
+ }
+
+ inline int GetOccupancy( int vc ) const
+ {
+ return _vc[vc]->GetOccupancy( );
+ }
+
+#ifdef TRACK_BUFFERS
+ inline int GetOccupancyForClass(int c) const
+ {
+ return _class_occupancy[c];
+ }
+#endif
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/buffer_state.cpp b/src/intersim2/buffer_state.cpp
new file mode 100644
index 0000000..93492f6
--- /dev/null
+++ b/src/intersim2/buffer_state.cpp
@@ -0,0 +1,676 @@
+// $Id: buffer_state.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*buffer_state.cpp
+ *
+ * This class is the buffere state of the next router down the channel
+ * tracks the credit and how much of the buffer is in use
+ */
+
+#include <iostream>
+#include <sstream>
+#include <cstdlib>
+#include <cassert>
+#include <limits>
+
+#include "booksim.hpp"
+#include "buffer_state.hpp"
+#include "random_utils.hpp"
+#include "globals.hpp"
+
+//#define DEBUG_FEEDBACK
+//#define DEBUG_SIMPLEFEEDBACK
+
+BufferState::BufferPolicy::BufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+: Module(parent, name), _buffer_state(parent)
+{
+}
+
+void BufferState::BufferPolicy::TakeBuffer(int vc) {
+}
+
+void BufferState::BufferPolicy::SendingFlit(Flit const * const f) {
+}
+
+void BufferState::BufferPolicy::FreeSlotFor(int vc) {
+}
+
+BufferState::BufferPolicy * BufferState::BufferPolicy::New(Configuration const & config, BufferState * parent, const string & name)
+{
+ BufferPolicy * sp = NULL;
+ string buffer_policy = config.GetStr("buffer_policy");
+ if(buffer_policy == "private") {
+ sp = new PrivateBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "shared") {
+ sp = new SharedBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "limited") {
+ sp = new LimitedSharedBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "dynamic") {
+ sp = new DynamicLimitedSharedBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "shifting") {
+ sp = new ShiftingDynamicLimitedSharedBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "feedback") {
+ sp = new FeedbackSharedBufferPolicy(config, parent, name);
+ } else if(buffer_policy == "simplefeedback") {
+ sp = new SimpleFeedbackSharedBufferPolicy(config, parent, name);
+ } else {
+ cout << "Unknown buffer policy: " << buffer_policy << endl;
+ }
+ return sp;
+}
+
+BufferState::PrivateBufferPolicy::PrivateBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : BufferPolicy(config, parent, name)
+{
+ int const vcs = config.GetInt( "num_vcs" );
+ int const buf_size = config.GetInt("buf_size");
+ if(buf_size <= 0) {
+ _vc_buf_size = config.GetInt("vc_buf_size");
+ } else {
+ _vc_buf_size = buf_size / vcs;
+ }
+ assert(_vc_buf_size > 0);
+}
+
+void BufferState::PrivateBufferPolicy::SendingFlit(Flit const * const f)
+{
+ int const vc = f->vc;
+ if(_buffer_state->OccupancyFor(vc) > _vc_buf_size) {
+ ostringstream err;
+ err << "Buffer overflow for VC " << vc;
+ Error(err.str());
+ }
+}
+
+bool BufferState::PrivateBufferPolicy::IsFullFor(int vc) const
+{
+ return (_buffer_state->OccupancyFor(vc) >= _vc_buf_size);
+}
+
+int BufferState::PrivateBufferPolicy::AvailableFor(int vc) const
+{
+ return _vc_buf_size - _buffer_state->OccupancyFor(vc);
+}
+
+int BufferState::PrivateBufferPolicy::LimitFor(int vc) const
+{
+ return _vc_buf_size;
+}
+
+BufferState::SharedBufferPolicy::SharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : BufferPolicy(config, parent, name), _shared_buf_occupancy(0)
+{
+ int const vcs = config.GetInt( "num_vcs" );
+ int num_private_bufs = config.GetInt("private_bufs");
+ if(num_private_bufs < 0) {
+ num_private_bufs = vcs;
+ } else if(num_private_bufs == 0) {
+ num_private_bufs = 1;
+ }
+
+ _private_buf_occupancy.resize(num_private_bufs, 0);
+
+ _buf_size = config.GetInt("buf_size");
+ if(_buf_size < 0) {
+ _buf_size = vcs * config.GetInt("vc_buf_size");
+ }
+
+ _private_buf_size = config.GetIntArray("private_buf_size");
+ if(_private_buf_size.empty()) {
+ int const bs = config.GetInt("private_buf_size");
+ if(bs < 0) {
+ _private_buf_size.push_back(_buf_size / num_private_bufs);
+ } else {
+ _private_buf_size.push_back(bs);
+ }
+ }
+ _private_buf_size.resize(num_private_bufs, _private_buf_size.back());
+
+ vector<int> start_vc = config.GetIntArray("private_buf_start_vc");
+ if(start_vc.empty()) {
+ int const sv = config.GetInt("private_buf_start_vc");
+ if(sv < 0) {
+ start_vc.resize(num_private_bufs);
+ for(int i = 0; i < num_private_bufs; ++i) {
+ start_vc[i] = i * vcs / num_private_bufs;
+ }
+ } else {
+ start_vc.push_back(sv);
+ }
+ }
+
+ vector<int> end_vc = config.GetIntArray("private_buf_end_vc");
+ if(end_vc.empty()) {
+ int const ev = config.GetInt("private_buf_end_vc");
+ if(ev < 0) {
+ end_vc.resize(num_private_bufs);
+ for(int i = 0; i < num_private_bufs; ++i) {
+ end_vc[i] = (i + 1) * vcs / num_private_bufs - 1;
+ }
+ } else {
+ end_vc.push_back(ev);
+ }
+ }
+
+ _private_buf_vc_map.resize(vcs, -1);
+ _shared_buf_size = _buf_size;
+ for(int i = 0; i < num_private_bufs; ++i) {
+ _shared_buf_size -= _private_buf_size[i];
+ assert(start_vc[i] <= end_vc[i]);
+ for(int v = start_vc[i]; v <= end_vc[i]; ++v) {
+ assert(_private_buf_vc_map[v] < 0);
+ _private_buf_vc_map[v] = i;
+ }
+ }
+ assert(_shared_buf_size >= 0);
+
+ _reserved_slots.resize(vcs, 0);
+}
+
+void BufferState::SharedBufferPolicy::ProcessFreeSlot(int vc)
+{
+ int i = _private_buf_vc_map[vc];
+ --_private_buf_occupancy[i];
+ if(_private_buf_occupancy[i] < 0) {
+ ostringstream err;
+ err << "Private buffer occupancy fell below zero for buffer " << i;
+ Error(err.str());
+ } else if(_private_buf_occupancy[i] >= _private_buf_size[i]) {
+ --_shared_buf_occupancy;
+ if(_shared_buf_occupancy < 0) {
+ Error("Shared buffer occupancy fell below zero.");
+ }
+ }
+}
+
+void BufferState::SharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ int const vc = f->vc;
+ if(_reserved_slots[vc] > 0) {
+ --_reserved_slots[vc];
+ } else {
+ int i = _private_buf_vc_map[vc];
+ ++_private_buf_occupancy[i];
+ if(_private_buf_occupancy[i] > _private_buf_size[i]) {
+ ++_shared_buf_occupancy;
+ if(_shared_buf_occupancy > _shared_buf_size) {
+ Error("Shared buffer overflow.");
+ }
+ }
+ }
+ if(f->tail) {
+ while(_reserved_slots[vc]) {
+ --_reserved_slots[vc];
+ ProcessFreeSlot(vc);
+ }
+ }
+}
+
+void BufferState::SharedBufferPolicy::FreeSlotFor(int vc)
+{
+ if(!_buffer_state->IsAvailableFor(vc) && _buffer_state->IsEmptyFor(vc)) {
+ ++_reserved_slots[vc];
+ } else {
+ ProcessFreeSlot(vc);
+ }
+}
+
+bool BufferState::SharedBufferPolicy::IsFullFor(int vc) const
+{
+ int i = _private_buf_vc_map[vc];
+ return ((_reserved_slots[vc] == 0) &&
+ (_private_buf_occupancy[i] >= _private_buf_size[i]) &&
+ (_shared_buf_occupancy >= _shared_buf_size));
+}
+
+int BufferState::SharedBufferPolicy::AvailableFor(int vc) const
+{
+ int i = _private_buf_vc_map[vc];
+ return (_reserved_slots[vc] +
+ max(_private_buf_size[i] - _private_buf_occupancy[i], 0) +
+ (_shared_buf_size - _shared_buf_occupancy));
+}
+
+int BufferState::SharedBufferPolicy::LimitFor(int vc) const
+{
+ int i = _private_buf_vc_map[vc];
+ return (_private_buf_size[i] + _shared_buf_size);
+}
+
+BufferState::LimitedSharedBufferPolicy::LimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : SharedBufferPolicy(config, parent, name), _active_vcs(0)
+{
+ _vcs = config.GetInt("num_vcs");
+ _max_held_slots = config.GetInt("max_held_slots");
+ if(_max_held_slots < 0) {
+ _max_held_slots = _buf_size;
+ }
+}
+
+void BufferState::LimitedSharedBufferPolicy::TakeBuffer(int vc)
+{
+ ++_active_vcs;
+ if(_active_vcs > _vcs) {
+ Error("Number of active VCs is too large.");
+ }
+}
+
+void BufferState::LimitedSharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ SharedBufferPolicy::SendingFlit(f);
+ if(f->tail) {
+ --_active_vcs;
+ if(_active_vcs < 0) {
+ Error("Number of active VCs fell below zero.");
+ }
+ }
+}
+
+bool BufferState::LimitedSharedBufferPolicy::IsFullFor(int vc) const
+{
+ return (SharedBufferPolicy::IsFullFor(vc) ||
+ (_buffer_state->OccupancyFor(vc) >= _max_held_slots));
+}
+
+int BufferState::LimitedSharedBufferPolicy::AvailableFor(int vc) const
+{
+ return min(SharedBufferPolicy::AvailableFor(vc),
+ _max_held_slots - _buffer_state->OccupancyFor(vc));
+}
+
+int BufferState::LimitedSharedBufferPolicy::LimitFor(int vc) const
+{
+ return min(SharedBufferPolicy::LimitFor(vc), _max_held_slots);
+}
+
+BufferState::DynamicLimitedSharedBufferPolicy::DynamicLimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : LimitedSharedBufferPolicy(config, parent, name)
+{
+ _max_held_slots = _buf_size;
+}
+
+void BufferState::DynamicLimitedSharedBufferPolicy::TakeBuffer(int vc)
+{
+ LimitedSharedBufferPolicy::TakeBuffer(vc);
+ assert(_active_vcs > 0);
+ _max_held_slots = _buf_size / _active_vcs;
+ assert(_max_held_slots > 0);
+}
+
+void BufferState::DynamicLimitedSharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ LimitedSharedBufferPolicy::SendingFlit(f);
+ if(f->tail && _active_vcs) {
+ _max_held_slots = _buf_size / _active_vcs;
+ }
+ assert(_max_held_slots > 0);
+}
+
+BufferState::ShiftingDynamicLimitedSharedBufferPolicy::ShiftingDynamicLimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : DynamicLimitedSharedBufferPolicy(config, parent, name)
+{
+
+}
+
+void BufferState::ShiftingDynamicLimitedSharedBufferPolicy::TakeBuffer(int vc)
+{
+ LimitedSharedBufferPolicy::TakeBuffer(vc);
+ assert(_active_vcs);
+ int i = _active_vcs - 1;
+ _max_held_slots = _buf_size;
+ while(i) {
+ _max_held_slots >>= 1;
+ i >>= 1;
+ }
+ assert(_max_held_slots > 0);
+}
+
+void BufferState::ShiftingDynamicLimitedSharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ LimitedSharedBufferPolicy::SendingFlit(f);
+ if(f->tail && _active_vcs) {
+ int i = _active_vcs - 1;
+ _max_held_slots = _buf_size;
+ while(i) {
+ _max_held_slots >>= 1;
+ i >>= 1;
+ }
+ }
+ assert(_max_held_slots > 0);
+}
+
+BufferState::FeedbackSharedBufferPolicy::FeedbackSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : SharedBufferPolicy(config, parent, name)
+{
+ _aging_scale = config.GetInt("feedback_aging_scale");
+ _offset = config.GetInt("feedback_offset");
+ _vcs = config.GetInt("num_vcs");
+
+ _occupancy_limit.resize(_vcs, _buf_size);
+ _round_trip_time.resize(_vcs, -1);
+ _flit_sent_time.resize(_vcs);
+ _total_mapped_size = _buf_size * _vcs;
+ _min_latency = -1;
+}
+
+void BufferState::FeedbackSharedBufferPolicy::SetMinLatency(int min_latency)
+{
+#ifdef DEBUG_FEEDBACK
+ cerr << FullName() << ": Setting minimum latency to "
+ << min_latency << "." << endl;
+#endif
+ _min_latency = min_latency;
+}
+
+void BufferState::FeedbackSharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ SharedBufferPolicy::SendingFlit(f);
+ _flit_sent_time[f->vc].push(GetSimTime());
+}
+
+int BufferState::FeedbackSharedBufferPolicy::_ComputeRTT(int vc, int last_rtt) const
+{
+ // compute moving average of round-trip time
+ int rtt = _round_trip_time[vc];
+ if(rtt < 0) {
+ return last_rtt;
+ }
+ return ((rtt << _aging_scale) + last_rtt - rtt) >> _aging_scale;
+}
+
+int BufferState::FeedbackSharedBufferPolicy::_ComputeLimit(int rtt) const
+{
+ // for every cycle that the measured average round trip time exceeded the
+ // observed minimum round trip time, reduce buffer occupancy limit by one
+ assert(_min_latency >= 0);
+ return max((_min_latency << 1) - rtt + _offset, 1);
+}
+
+int BufferState::FeedbackSharedBufferPolicy::_ComputeMaxSlots(int vc) const
+{
+ int max_slots = _occupancy_limit[vc];
+ if(!_flit_sent_time[vc].empty()) {
+ int min_rtt = GetSimTime() - _flit_sent_time[vc].front();
+ int rtt = _ComputeRTT(vc, min_rtt);
+ int limit = _ComputeLimit(rtt);
+ max_slots = min(max_slots, limit);
+ }
+ return max_slots;
+}
+
+void BufferState::FeedbackSharedBufferPolicy::FreeSlotFor(int vc)
+{
+ SharedBufferPolicy::FreeSlotFor(vc);
+ assert(!_flit_sent_time[vc].empty());
+ int const last_rtt = GetSimTime() - _flit_sent_time[vc].front();
+#ifdef DEBUG_FEEDBACK
+ cerr << FullName() << ": Probe for VC "
+ << vc << " came back after "
+ << last_rtt << " cycles."
+ << endl;
+#endif
+ _flit_sent_time[vc].pop();
+
+ int rtt = _ComputeRTT(vc, last_rtt);
+#ifdef DEBUG_FEEDBACK
+ int old_rtt = _round_trip_time[vc];
+ if(rtt != old_rtt) {
+ cerr << FullName() << ": Updating RTT estimate for VC "
+ << vc << " from "
+ << old_rtt << " to "
+ << rtt << " cycles."
+ << endl;
+ }
+#endif
+ _round_trip_time[vc] = rtt;
+
+ int limit = _ComputeLimit(rtt);
+#ifdef DEBUG_FEEDBACK
+ int old_limit = _occupancy_limit[vc];
+ int old_mapped_size = _total_mapped_size;
+#endif
+ _total_mapped_size += (limit - _occupancy_limit[vc]);
+ _occupancy_limit[vc] = limit;
+#ifdef DEBUG_FEEDBACK
+ if(limit != old_limit) {
+ cerr << FullName() << ": Occupancy limit for VC "
+ << vc << " changed from "
+ << old_limit << " to "
+ << limit << " slots."
+ << endl;
+ cerr << FullName() << ": Total mapped buffer space changed from "
+ << old_mapped_size << " to "
+ << _total_mapped_size << " slots."
+ << endl;
+ }
+#endif
+}
+
+bool BufferState::FeedbackSharedBufferPolicy::IsFullFor(int vc) const
+{
+ if(SharedBufferPolicy::IsFullFor(vc)) {
+ return true;
+ }
+ return (_buffer_state->OccupancyFor(vc) >= _ComputeMaxSlots(vc));
+}
+
+int BufferState::FeedbackSharedBufferPolicy::AvailableFor(int vc) const
+{
+ return min(SharedBufferPolicy::AvailableFor(vc),
+ _ComputeMaxSlots(vc) - _buffer_state->OccupancyFor(vc));
+}
+
+int BufferState::FeedbackSharedBufferPolicy::LimitFor(int vc) const
+{
+ return min(SharedBufferPolicy::LimitFor(vc), _ComputeMaxSlots(vc));
+}
+
+BufferState::SimpleFeedbackSharedBufferPolicy::SimpleFeedbackSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name)
+ : FeedbackSharedBufferPolicy(config, parent, name)
+{
+ _pending_credits.resize(_vcs, 0);
+}
+
+void BufferState::SimpleFeedbackSharedBufferPolicy::SendingFlit(Flit const * const f)
+{
+ int const & vc = f->vc;
+ if(_flit_sent_time[vc].empty()) {
+ assert(_buffer_state->OccupancyFor(vc) > 0);
+ _pending_credits[vc] = _buffer_state->OccupancyFor(vc) - 1;
+#ifdef DEBUG_SIMPLEFEEDBACK
+ cerr << FullName() << ": Sending probe flit for VC "
+ << vc << "; "
+ << _pending_credits[vc] << " non-probe flits in flight."
+ << endl;
+#endif
+ FeedbackSharedBufferPolicy::SendingFlit(f);
+ return;
+ }
+ SharedBufferPolicy::SendingFlit(f);
+}
+
+void BufferState::SimpleFeedbackSharedBufferPolicy::FreeSlotFor(int vc)
+{
+ if(!_flit_sent_time[vc].empty() && _pending_credits[vc] == 0) {
+#ifdef DEBUG_SIMPLEFEEDBACK
+ cerr << FullName() << ": Probe credit for VC "
+ << vc << " came back." << endl;
+#endif
+ FeedbackSharedBufferPolicy::FreeSlotFor(vc);
+ return;
+ }
+ if(_pending_credits[vc] > 0) {
+ assert(!_flit_sent_time[vc].empty());
+ --_pending_credits[vc];
+#ifdef DEBUG_SIMPLEFEEDBACK
+ cerr << FullName() << ": Ignoring non-probe credit for VC "
+ << vc << "; "
+ << _pending_credits[vc] << " remaining."
+ << endl;
+#endif
+ }
+ SharedBufferPolicy::FreeSlotFor(vc);
+}
+
+BufferState::BufferState( const Configuration& config, Module *parent, const string& name ) :
+ Module( parent, name ), _occupancy(0)
+{
+ _vcs = config.GetInt( "num_vcs" );
+ _size = config.GetInt("buf_size");
+ if(_size < 0) {
+ _size = _vcs * config.GetInt("vc_buf_size");
+ }
+
+ _buffer_policy = BufferPolicy::New(config, this, "policy");
+
+ _wait_for_tail_credit = config.GetInt( "wait_for_tail_credit" );
+
+ _vc_occupancy.resize(_vcs, 0);
+
+ _in_use_by.resize(_vcs, -1);
+ _tail_sent.resize(_vcs, false);
+
+ _last_id.resize(_vcs, -1);
+ _last_pid.resize(_vcs, -1);
+
+#ifdef TRACK_BUFFERS
+ _classes = config.GetInt("classes");
+ _outstanding_classes.resize(_vcs);
+ _class_occupancy.resize(_classes, 0);
+#endif
+}
+
+BufferState::~BufferState()
+{
+ delete _buffer_policy;
+}
+
+void BufferState::ProcessCredit( Credit const * const c )
+{
+ assert( c );
+
+ set<int>::iterator iter = c->vc.begin();
+ while(iter != c->vc.end()) {
+
+ int const vc = *iter;
+
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ if ( ( _wait_for_tail_credit ) &&
+ ( _in_use_by[vc] < 0 ) ) {
+ ostringstream err;
+ err << "Received credit for idle VC " << vc;
+ Error( err.str() );
+ }
+ --_occupancy;
+ if(_occupancy < 0) {
+ Error("Buffer occupancy fell below zero.");
+ }
+ --_vc_occupancy[vc];
+ if(_vc_occupancy[vc] < 0) {
+ ostringstream err;
+ err << "Buffer occupancy fell below zero for VC " << vc;
+ Error(err.str());
+ }
+ if(_wait_for_tail_credit && !_vc_occupancy[vc] && _tail_sent[vc]) {
+ assert(_in_use_by[vc] >= 0);
+ _in_use_by[vc] = -1;
+ }
+
+#ifdef TRACK_BUFFERS
+ assert(!_outstanding_classes[vc].empty());
+ int cl = _outstanding_classes[vc].front();
+ _outstanding_classes[vc].pop();
+ assert((cl >= 0) && (cl < _classes));
+ assert(_class_occupancy[cl] > 0);
+ --_class_occupancy[cl];
+#endif
+
+ _buffer_policy->FreeSlotFor(vc);
+
+ ++iter;
+ }
+}
+
+
+void BufferState::SendingFlit( Flit const * const f )
+{
+ int const vc = f->vc;
+
+ assert( f && ( vc >= 0 ) && ( vc < _vcs ) );
+
+ ++_occupancy;
+ if(_occupancy > _size) {
+ Error("Buffer overflow.");
+ }
+
+ ++_vc_occupancy[vc];
+
+ _buffer_policy->SendingFlit(f);
+
+#ifdef TRACK_BUFFERS
+ _outstanding_classes[vc].push(f->cl);
+ ++_class_occupancy[f->cl];
+#endif
+
+ if ( f->tail ) {
+ _tail_sent[vc] = true;
+
+ if ( !_wait_for_tail_credit ) {
+ assert(_in_use_by[vc] >= 0);
+ _in_use_by[vc] = -1;
+ }
+ }
+ _last_id[vc] = f->id;
+ _last_pid[vc] = f->pid;
+}
+
+void BufferState::TakeBuffer( int vc, int tag )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ if ( _in_use_by[vc] >= 0 ) {
+ ostringstream err;
+ err << "Buffer taken while in use for VC " << vc;
+ Error( err.str() );
+ }
+ _in_use_by[vc] = tag;
+ _tail_sent[vc] = false;
+ _buffer_policy->TakeBuffer(vc);
+}
+
+void BufferState::Display( ostream & os ) const
+{
+ os << FullName() << " :" << endl;
+ os << " occupied = " << _occupancy << endl;
+ for ( int v = 0; v < _vcs; ++v ) {
+ os << " VC " << v << ": ";
+ os << "in_use_by = " << _in_use_by[v]
+ << ", tail_sent = " << _tail_sent[v]
+ << ", occupied = " << _vc_occupancy[v] << endl;
+ }
+}
diff --git a/src/intersim2/buffer_state.hpp b/src/intersim2/buffer_state.hpp
new file mode 100644
index 0000000..32a7da1
--- /dev/null
+++ b/src/intersim2/buffer_state.hpp
@@ -0,0 +1,239 @@
+// $Id: buffer_state.hpp 5378 2013-01-10 03:40:11Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BUFFER_STATE_HPP_
+#define _BUFFER_STATE_HPP_
+
+#include <vector>
+#include <queue>
+
+#include "module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "config_utils.hpp"
+
+class BufferState : public Module {
+
+ class BufferPolicy : public Module {
+ protected:
+ BufferState const * const _buffer_state;
+ public:
+ BufferPolicy(Configuration const & config, BufferState * parent,
+ const string & name);
+ virtual void SetMinLatency(int min_latency) {}
+ virtual void TakeBuffer(int vc = 0);
+ virtual void SendingFlit(Flit const * const f);
+ virtual void FreeSlotFor(int vc = 0);
+ virtual bool IsFullFor(int vc = 0) const = 0;
+ virtual int AvailableFor(int vc = 0) const = 0;
+ virtual int LimitFor(int vc = 0) const = 0;
+
+ static BufferPolicy * New(Configuration const & config,
+ BufferState * parent, const string & name);
+ };
+
+ class PrivateBufferPolicy : public BufferPolicy {
+ protected:
+ int _vc_buf_size;
+ public:
+ PrivateBufferPolicy(Configuration const & config, BufferState * parent,
+ const string & name);
+ virtual void SendingFlit(Flit const * const f);
+ virtual bool IsFullFor(int vc = 0) const;
+ virtual int AvailableFor(int vc = 0) const;
+ virtual int LimitFor(int vc = 0) const;
+ };
+
+ class SharedBufferPolicy : public BufferPolicy {
+ protected:
+ int _buf_size;
+ vector<int> _private_buf_vc_map;
+ vector<int> _private_buf_size;
+ vector<int> _private_buf_occupancy;
+ int _shared_buf_size;
+ int _shared_buf_occupancy;
+ vector<int> _reserved_slots;
+ void ProcessFreeSlot(int vc = 0);
+ public:
+ SharedBufferPolicy(Configuration const & config, BufferState * parent,
+ const string & name);
+ virtual void SendingFlit(Flit const * const f);
+ virtual void FreeSlotFor(int vc = 0);
+ virtual bool IsFullFor(int vc = 0) const;
+ virtual int AvailableFor(int vc = 0) const;
+ virtual int LimitFor(int vc = 0) const;
+ };
+
+ class LimitedSharedBufferPolicy : public SharedBufferPolicy {
+ protected:
+ int _vcs;
+ int _active_vcs;
+ int _max_held_slots;
+ public:
+ LimitedSharedBufferPolicy(Configuration const & config,
+ BufferState * parent,
+ const string & name);
+ virtual void TakeBuffer(int vc = 0);
+ virtual void SendingFlit(Flit const * const f);
+ virtual bool IsFullFor(int vc = 0) const;
+ virtual int AvailableFor(int vc = 0) const;
+ virtual int LimitFor(int vc = 0) const;
+ };
+
+ class DynamicLimitedSharedBufferPolicy : public LimitedSharedBufferPolicy {
+ public:
+ DynamicLimitedSharedBufferPolicy(Configuration const & config,
+ BufferState * parent,
+ const string & name);
+ virtual void TakeBuffer(int vc = 0);
+ virtual void SendingFlit(Flit const * const f);
+ };
+
+ class ShiftingDynamicLimitedSharedBufferPolicy : public DynamicLimitedSharedBufferPolicy {
+ public:
+ ShiftingDynamicLimitedSharedBufferPolicy(Configuration const & config,
+ BufferState * parent,
+ const string & name);
+ virtual void TakeBuffer(int vc = 0);
+ virtual void SendingFlit(Flit const * const f);
+ };
+
+ class FeedbackSharedBufferPolicy : public SharedBufferPolicy {
+ protected:
+ int _ComputeRTT(int vc, int last_rtt) const;
+ int _ComputeLimit(int rtt) const;
+ int _ComputeMaxSlots(int vc) const;
+ int _vcs;
+ vector<int> _occupancy_limit;
+ vector<int> _round_trip_time;
+ vector<queue<int> > _flit_sent_time;
+ int _min_latency;
+ int _total_mapped_size;
+ int _aging_scale;
+ int _offset;
+ public:
+ FeedbackSharedBufferPolicy(Configuration const & config,
+ BufferState * parent, const string & name);
+ virtual void SetMinLatency(int min_latency);
+ virtual void SendingFlit(Flit const * const f);
+ virtual void FreeSlotFor(int vc = 0);
+ virtual bool IsFullFor(int vc = 0) const;
+ virtual int AvailableFor(int vc = 0) const;
+ virtual int LimitFor(int vc = 0) const;
+ };
+
+ class SimpleFeedbackSharedBufferPolicy : public FeedbackSharedBufferPolicy {
+ protected:
+ vector<int> _pending_credits;
+ public:
+ SimpleFeedbackSharedBufferPolicy(Configuration const & config,
+ BufferState * parent, const string & name);
+ virtual void SendingFlit(Flit const * const f);
+ virtual void FreeSlotFor(int vc = 0);
+ };
+
+ bool _wait_for_tail_credit;
+ int _size;
+ int _occupancy;
+ vector<int> _vc_occupancy;
+ int _vcs;
+
+ BufferPolicy * _buffer_policy;
+
+ vector<int> _in_use_by;
+ vector<bool> _tail_sent;
+ vector<int> _last_id;
+ vector<int> _last_pid;
+
+#ifdef TRACK_BUFFERS
+ int _classes;
+ vector<queue<int> > _outstanding_classes;
+ vector<int> _class_occupancy;
+#endif
+
+public:
+
+ BufferState( const Configuration& config,
+ Module *parent, const string& name );
+
+ ~BufferState();
+
+ inline void SetMinLatency(int min_latency) {
+ _buffer_policy->SetMinLatency(min_latency);
+ }
+
+ void ProcessCredit( Credit const * const c );
+ void SendingFlit( Flit const * const f );
+
+ void TakeBuffer( int vc = 0, int tag = 0 );
+
+ inline bool IsFull() const {
+ assert(_occupancy <= _size);
+ return (_occupancy == _size);
+ }
+ inline bool IsFullFor( int vc = 0 ) const {
+ return _buffer_policy->IsFullFor(vc);
+ }
+ inline int AvailableFor( int vc = 0 ) const {
+ return _buffer_policy->AvailableFor(vc);
+ }
+ inline int LimitFor( int vc = 0 ) const {
+ return _buffer_policy->LimitFor(vc);
+ }
+ inline bool IsEmptyFor(int vc = 0) const {
+ assert((vc >= 0) && (vc < _vcs));
+ return (_vc_occupancy[vc] == 0);
+ }
+ inline bool IsAvailableFor( int vc = 0 ) const {
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _in_use_by[vc] < 0;
+ }
+ inline int UsedBy(int vc = 0) const {
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _in_use_by[vc];
+ }
+
+ inline int Occupancy() const {
+ return _occupancy;
+ }
+
+ inline int OccupancyFor( int vc = 0 ) const {
+ assert((vc >= 0) && (vc < _vcs));
+ return _vc_occupancy[vc];
+ }
+
+#ifdef TRACK_BUFFERS
+ inline int OccupancyForClass(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _class_occupancy[c];
+ }
+#endif
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/channel.hpp b/src/intersim2/channel.hpp
new file mode 100644
index 0000000..13ad9f9
--- /dev/null
+++ b/src/intersim2/channel.hpp
@@ -0,0 +1,125 @@
+// $Id: channel.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//////////////////////////////////////////////////////////////////////
+//
+// File Name: channel.hpp
+//
+// The Channel models a generic channel with a multi-cycle
+// transmission delay. The channel latency can be specified as
+// an integer number of simulator cycles.
+//
+/////
+#ifndef _CHANNEL_HPP
+#define _CHANNEL_HPP
+
+#include <queue>
+#include <cassert>
+
+#include "globals.hpp"
+#include "module.hpp"
+#include "timed_module.hpp"
+
+using namespace std;
+
+template<typename T>
+class Channel : public TimedModule {
+public:
+ Channel(Module * parent, string const & name);
+ virtual ~Channel() {}
+
+ // Physical Parameters
+ void SetLatency(int cycles);
+ int GetLatency() const { return _delay ; }
+
+ // Send data
+ virtual void Send(T * data);
+
+ // Receive data
+ virtual T * Receive();
+
+ virtual void ReadInputs();
+ virtual void Evaluate() {}
+ virtual void WriteOutputs();
+
+protected:
+ int _delay;
+ T * _input;
+ T * _output;
+ queue<pair<int, T *> > _wait_queue;
+
+};
+
+template<typename T>
+Channel<T>::Channel(Module * parent, string const & name)
+ : TimedModule(parent, name), _delay(1), _input(0), _output(0) {
+}
+
+template<typename T>
+void Channel<T>::SetLatency(int cycles) {
+ if(cycles <= 0) {
+ Error("Channel must have positive delay.");
+ }
+ _delay = cycles ;
+}
+
+template<typename T>
+void Channel<T>::Send(T * data) {
+ _input = data;
+}
+
+template<typename T>
+T * Channel<T>::Receive() {
+ return _output;
+}
+
+template<typename T>
+void Channel<T>::ReadInputs() {
+ if(_input) {
+ _wait_queue.push(make_pair(GetSimTime() + _delay - 1, _input));
+ _input = 0;
+ }
+}
+
+template<typename T>
+void Channel<T>::WriteOutputs() {
+ _output = 0;
+ if(_wait_queue.empty()) {
+ return;
+ }
+ pair<int, T *> const & item = _wait_queue.front();
+ int const & time = item.first;
+ if(GetSimTime() < time) {
+ return;
+ }
+ assert(GetSimTime() == time);
+ _output = item.second;
+ assert(_output);
+ _wait_queue.pop();
+}
+
+#endif
diff --git a/src/intersim2/config.l b/src/intersim2/config.l
new file mode 100644
index 0000000..4df14c7
--- /dev/null
+++ b/src/intersim2/config.l
@@ -0,0 +1,54 @@
+%{
+
+#include "y.tab.h"
+
+static unsigned int lineno = 1;
+
+void config_error(char * msg, int lineno);
+void yyerror(char * msg);
+
+extern int config_input(char *, int);
+#undef YY_INPUT
+#define YY_INPUT(b, r, ms) (r = config_input(b, ms))
+
+%}
+
+Digit [0-9]
+Exponent [eE][+-]?{Digit}+
+DblConst ({Digit}*\.)?{Digit}+{Exponent}?
+StrConst [A-Za-z_\-/\.][A-Za-z0-9_\-/\.\+(\{\,)\}]*
+
+%%
+
+ /* Ignore comments and all spaces */
+
+\/\/[^\n]* ;
+[ \t\r]* ;
+
+\n { lineno++; }
+
+ /* Commands */
+
+\{[A-Za-z0-9_\-\.(\{\,)\}]+(\,[A-Za-z0-9_\-\.(\{\,)\}]+)*\} { yylval.name = strdup( yytext ); return STR; }
+
+-?[0-9]+ { yylval.num = atoi( yytext ); return NUM; }
+
+-?[0-9]*\.[0-9]+ { yylval.fnum = atof( yytext ); return FNUM; }
+
+-?{DblConst} { yylval.fnum = atof( yytext ); return FNUM;}
+
+{StrConst} { yylval.name = strdup( yytext ); return STR; }
+
+. { return yytext[0]; }
+
+%%
+
+void yyerror( char * msg )
+{
+ config_error( msg, lineno );
+}
+
+int yywrap()
+{
+ return 1;
+}
diff --git a/src/intersim2/config.y b/src/intersim2/config.y
new file mode 100644
index 0000000..377d467
--- /dev/null
+++ b/src/intersim2/config.y
@@ -0,0 +1,37 @@
+%{
+
+int yylex(void);
+void yyerror(char * msg);
+void config_assign_string( char const * field, char const * value );
+void config_assign_int( char const * field, int value );
+void config_assign_float( char const * field, double value );
+
+#ifdef _WIN32
+#pragma warning ( disable : 4102 )
+#pragma warning ( disable : 4244 )
+#endif
+
+%}
+
+%union {
+ char *name;
+ int num;
+ double fnum;
+}
+
+%token <name> STR
+%token <num> NUM
+%token <fnum> FNUM
+
+%%
+
+commands : commands command
+ | command
+;
+
+command : STR '=' STR ';' { config_assign_string( $1, $3 ); free( $1 ); free( $3 ); }
+ | STR '=' NUM ';' { config_assign_int( $1, $3 ); free( $1 ); }
+ | STR '=' FNUM ';' { config_assign_float( $1, $3 ); free( $1 ); }
+;
+
+%%
diff --git a/src/intersim2/config_utils.cpp b/src/intersim2/config_utils.cpp
new file mode 100644
index 0000000..fad5fce
--- /dev/null
+++ b/src/intersim2/config_utils.cpp
@@ -0,0 +1,447 @@
+// $Id: config_utils.cpp 5188 2012-08-30 00:31:31Z dub $
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*config_utils.cpp
+ *
+ *The configuration object which contained the parsed data from the
+ *configuration file
+ */
+
+#include "booksim.hpp"
+#include <iostream>
+#include <cstring>
+#include <sstream>
+#include <fstream>
+#include <cstdlib>
+
+#include "config_utils.hpp"
+
+Configuration *Configuration::theConfig = 0;
+
+Configuration::Configuration()
+{
+ theConfig = this;
+ _config_file = 0;
+}
+
+void Configuration::AddStrField(string const & field, string const & value)
+{
+ _str_map[field] = value;
+}
+
+void Configuration::Assign(string const & field, string const & value)
+{
+ map<string, string>::const_iterator match;
+
+ match = _str_map.find(field);
+ if(match != _str_map.end()) {
+ _str_map[field] = value;
+ } else {
+ ParseError("Unknown string field: " + field);
+ }
+}
+
+void Configuration::Assign(string const & field, int value)
+{
+ map<string, int>::const_iterator match;
+
+ match = _int_map.find(field);
+ if(match != _int_map.end()) {
+ _int_map[field] = value;
+ } else {
+ ParseError("Unknown integer field: " + field);
+ }
+}
+
+void Configuration::Assign(string const & field, double value)
+{
+ map<string, double>::const_iterator match;
+
+ match = _float_map.find(field);
+ if(match != _float_map.end()) {
+ _float_map[field] = value;
+ } else {
+ ParseError("Unknown double field: " + field);
+ }
+}
+
+string Configuration::GetStr(string const & field) const
+{
+ map<string, string>::const_iterator match;
+
+ match = _str_map.find(field);
+ if(match != _str_map.end()) {
+ return match->second;
+ } else {
+ ParseError("Unknown string field: " + field);
+ exit(-1);
+ }
+}
+
+int Configuration::GetInt(string const & field) const
+{
+ map<string, int>::const_iterator match;
+
+ match = _int_map.find(field);
+ if(match != _int_map.end()) {
+ return match->second;
+ } else {
+ ParseError("Unknown integer field: " + field);
+ exit(-1);
+ }
+}
+
+double Configuration::GetFloat(string const & field) const
+{
+ map<string,double>::const_iterator match;
+
+ match = _float_map.find(field);
+ if(match != _float_map.end()) {
+ return match->second;
+ } else {
+ ParseError("Unknown double field: " + field);
+ exit(-1);
+ }
+}
+
+vector<string> Configuration::GetStrArray(string const & field) const
+{
+ string const param_str = GetStr(field);
+ return tokenize_str(param_str);
+}
+
+vector<int> Configuration::GetIntArray(string const & field) const
+{
+ string const param_str = GetStr(field);
+ return tokenize_int(param_str);
+}
+
+vector<double> Configuration::GetFloatArray(string const & field) const
+{
+ string const param_str = GetStr(field);
+ return tokenize_float(param_str);
+}
+
+void Configuration::ParseFile(string const & filename)
+{
+ if((_config_file = fopen(filename.c_str(), "r")) == 0) {
+ cerr << "Could not open configuration file " << filename << endl;
+ exit(-1);
+ }
+
+ yyparse();
+
+ fclose(_config_file);
+ _config_file = 0;
+}
+
+void Configuration::ParseString(string const & str)
+{
+ _config_string = str + ';';
+ yyparse();
+ _config_string = "";
+}
+
+int Configuration::Input(char * line, int max_size)
+{
+ int length = 0;
+
+ if(_config_file) {
+ length = fread(line, 1, max_size, _config_file);
+ } else {
+ length = _config_string.length();
+ _config_string.copy(line, max_size);
+ _config_string.clear();
+ }
+
+ return length;
+}
+
+void Configuration::ParseError(string const & msg, unsigned int lineno) const
+{
+ if(lineno) {
+ cerr << "Parse error on line " << lineno << " : " << msg << endl;
+ } else {
+ cerr << "Parse error : " << msg << endl;
+ }
+
+
+ exit( -1 );
+}
+
+Configuration * Configuration::GetTheConfig()
+{
+ return theConfig;
+}
+
+//============================================================
+
+extern "C" void config_error( char const * msg, int lineno )
+{
+ Configuration::GetTheConfig( )->ParseError( msg, lineno );
+}
+
+extern "C" void config_assign_string( char const * field, char const * value )
+{
+ Configuration::GetTheConfig()->Assign(field, value);
+}
+
+extern "C" void config_assign_int( char const * field, int value )
+{
+ Configuration::GetTheConfig()->Assign(field, value);
+}
+
+extern "C" void config_assign_float( char const * field, double value )
+{
+ Configuration::GetTheConfig()->Assign(field, value);
+}
+
+extern "C" int config_input(char * line, int max_size)
+{
+ return Configuration::GetTheConfig()->Input(line, max_size);
+}
+
+bool ParseArgs(Configuration * cf, int argc, char * * argv)
+{
+ bool rc = false;
+
+ //all dashed variables are ignored by the arg parser
+ for(int i = 1; i < argc; ++i) {
+ string arg(argv[i]);
+ size_t pos = arg.find('=');
+ bool dash = (argv[i][0] =='-');
+ if(pos == string::npos && !dash) {
+ // parse config file
+ cf->ParseFile( argv[i] );
+ ifstream in(argv[i]);
+ cout << "BEGIN Configuration File: " << argv[i] << endl;
+ while (!in.eof()) {
+ char c;
+ in.get(c);
+ cout << c ;
+ }
+ cout << "END Configuration File: " << argv[i] << endl;
+ rc = true;
+ } else if(pos != string::npos) {
+ // override individual parameter
+ cout << "OVERRIDE Parameter: " << arg << endl;
+ cf->ParseString(argv[i]);
+ }
+ }
+
+ return rc;
+}
+
+
+//helpful for the GUI, write out nearly all variables contained in a config file.
+//However, it can't and won't write out empty strings since the booksim yacc
+//parser won't be abled to parse blank strings
+void Configuration::WriteFile(string const & filename) {
+
+ ostream *config_out= new ofstream(filename.c_str());
+
+
+ for(map<string,string>::const_iterator i = _str_map.begin();
+ i!=_str_map.end();
+ i++){
+ //the parser won't read empty strings
+ if(i->second[0]!='\0'){
+ *config_out<<i->first<<" = "<<i->second<<";"<<endl;
+ }
+ }
+
+ for(map<string, int>::const_iterator i = _int_map.begin();
+ i!=_int_map.end();
+ i++){
+ *config_out<<i->first<<" = "<<i->second<<";"<<endl;
+
+ }
+
+ for(map<string, double>::const_iterator i = _float_map.begin();
+ i!=_float_map.end();
+ i++){
+ *config_out<<i->first<<" = "<<i->second<<";"<<endl;
+
+ }
+ config_out->flush();
+ delete config_out;
+
+}
+
+
+
+void Configuration::WriteMatlabFile(ostream * config_out) const {
+
+
+
+ for(map<string,string>::const_iterator i = _str_map.begin();
+ i!=_str_map.end();
+ i++){
+ //the parser won't read blanks lolz
+ if(i->second[0]!='\0'){
+ *config_out<<"%"<<i->first<<" = \'"<<i->second<<"\';"<<endl;
+ }
+ }
+
+ for(map<string, int>::const_iterator i = _int_map.begin();
+ i!=_int_map.end();
+ i++){
+ *config_out<<"%"<<i->first<<" = "<<i->second<<";"<<endl;
+
+ }
+
+ for(map<string, double>::const_iterator i = _float_map.begin();
+ i!=_float_map.end();
+ i++){
+ *config_out<<"%"<<i->first<<" = "<<i->second<<";"<<endl;
+
+ }
+ config_out->flush();
+
+}
+
+vector<string> tokenize_str(string const & data)
+{
+ vector<string> values;
+
+ // no elements, no braces --> empty list
+ if(data.empty()) {
+ return values;
+ }
+
+ // doesn't start with an opening brace --> treat as single element
+ // note that this element can potentially contain nested lists
+ if(data[0] != '{') {
+ values.push_back(data);
+ return values;
+ }
+
+ size_t start = 1;
+ int nested = 0;
+
+ size_t curr = start;
+
+ while(string::npos != (curr = data.find_first_of("{,}", curr))) {
+
+ if(data[curr] == '{') {
+ ++nested;
+ } else if((data[curr] == '}') && nested) {
+ --nested;
+ } else if(!nested) {
+ if(curr > start) {
+ string token = data.substr(start, curr - start);
+ values.push_back(token);
+ }
+ start = curr + 1;
+ }
+ ++curr;
+ }
+ assert(!nested);
+
+ return values;
+}
+
+vector<int> tokenize_int(string const & data)
+{
+ vector<int> values;
+
+ // no elements, no braces --> empty list
+ if(data.empty()) {
+ return values;
+ }
+
+ // doesn't start with an opening brace --> treat as single element
+ // note that this element can potentially contain nested lists
+ if(data[0] != '{') {
+ values.push_back(atoi(data.c_str()));
+ return values;
+ }
+
+ size_t start = 1;
+ int nested = 0;
+
+ size_t curr = start;
+
+ while(string::npos != (curr = data.find_first_of("{,}", curr))) {
+
+ if(data[curr] == '{') {
+ ++nested;
+ } else if((data[curr] == '}') && nested) {
+ --nested;
+ } else if(!nested) {
+ if(curr > start) {
+ string token = data.substr(start, curr - start);
+ values.push_back(atoi(token.c_str()));
+ }
+ start = curr + 1;
+ }
+ ++curr;
+ }
+ assert(!nested);
+
+ return values;
+}
+
+vector<double> tokenize_float(string const & data)
+{
+ vector<double> values;
+
+ // no elements, no braces --> empty list
+ if(data.empty()) {
+ return values;
+ }
+
+ // doesn't start with an opening brace --> treat as single element
+ // note that this element can potentially contain nested lists
+ if(data[0] != '{') {
+ values.push_back(atof(data.c_str()));
+ return values;
+ }
+
+ size_t start = 1;
+ int nested = 0;
+
+ size_t curr = start;
+
+ while(string::npos != (curr = data.find_first_of("{,}", curr))) {
+
+ if(data[curr] == '{') {
+ ++nested;
+ } else if((data[curr] == '}') && nested) {
+ --nested;
+ } else if(!nested) {
+ if(curr > start) {
+ string token = data.substr(start, curr - start);
+ values.push_back(atof(token.c_str()));
+ }
+ start = curr + 1;
+ }
+ ++curr;
+ }
+ assert(!nested);
+
+ return values;
+}
diff --git a/src/intersim2/config_utils.hpp b/src/intersim2/config_utils.hpp
new file mode 100644
index 0000000..de3343b
--- /dev/null
+++ b/src/intersim2/config_utils.hpp
@@ -0,0 +1,95 @@
+// $Id: config_utils.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CONFIG_UTILS_HPP_
+#define _CONFIG_UTILS_HPP_
+
+#include "booksim.hpp"
+
+#include<cstdio>
+#include<string>
+#include<map>
+#include<vector>
+
+extern "C" int yyparse();
+
+class Configuration {
+ static Configuration * theConfig;
+ FILE * _config_file;
+ string _config_string;
+
+protected:
+ map<string,string> _str_map;
+ map<string,int> _int_map;
+ map<string,double> _float_map;
+
+public:
+ Configuration();
+
+ void AddStrField(string const & field, string const & value);
+
+ void Assign(string const & field, string const & value);
+ void Assign(string const & field, int value);
+ void Assign(string const & field, double value);
+
+ string GetStr(string const & field) const;
+ int GetInt(string const & field) const;
+ double GetFloat(string const & field) const;
+
+ vector<string> GetStrArray(const string & field) const;
+ vector<int> GetIntArray(const string & field) const;
+ vector<double> GetFloatArray(const string & field) const;
+
+ void ParseFile(string const & filename);
+ void ParseString(string const & str);
+ int Input(char * line, int max_size);
+ void ParseError(string const & msg, unsigned int lineno = 0) const;
+
+ void WriteFile(string const & filename);
+ void WriteMatlabFile(ostream * o) const;
+
+ inline const map<string, string> & GetStrMap() const {
+ return _str_map;
+ }
+ inline const map<string, int> & GetIntMap() const {
+ return _int_map;
+ }
+ inline const map<string, double> & GetFloatMap() const {
+ return _float_map;
+ }
+
+ static Configuration * GetTheConfig();
+
+};
+
+bool ParseArgs(Configuration * cf, int argc, char **argv);
+
+vector<string> tokenize_str(string const & data);
+vector<int> tokenize_int(string const & data);
+vector<double> tokenize_float(string const & data);
+
+#endif
diff --git a/src/intersim2/credit.cpp b/src/intersim2/credit.cpp
new file mode 100644
index 0000000..c6db498
--- /dev/null
+++ b/src/intersim2/credit.cpp
@@ -0,0 +1,79 @@
+// $Id: credit.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*credit.cpp
+ *
+ *A class for credits
+ */
+
+#include "booksim.hpp"
+#include "credit.hpp"
+
+stack<Credit *> Credit::_all;
+stack<Credit *> Credit::_free;
+
+Credit::Credit()
+{
+ Reset();
+}
+
+void Credit::Reset()
+{
+ vc.clear();
+ head = false;
+ tail = false;
+ id = -1;
+}
+
+Credit * Credit::New() {
+ Credit * c;
+ if(_free.empty()) {
+ c = new Credit();
+ _all.push(c);
+ } else {
+ c = _free.top();
+ c->Reset();
+ _free.pop();
+ }
+ return c;
+}
+
+void Credit::Free() {
+ _free.push(this);
+}
+
+void Credit::FreeAll() {
+ while(!_all.empty()) {
+ delete _all.top();
+ _all.pop();
+ }
+}
+
+
+int Credit::OutStanding(){
+ return _all.size()-_free.size();
+}
diff --git a/src/intersim2/credit.hpp b/src/intersim2/credit.hpp
new file mode 100644
index 0000000..8081394
--- /dev/null
+++ b/src/intersim2/credit.hpp
@@ -0,0 +1,60 @@
+// $Id: credit.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CREDIT_HPP_
+#define _CREDIT_HPP_
+
+#include <set>
+#include <stack>
+
+class Credit {
+
+public:
+
+ set<int> vc;
+
+ // these are only used by the event router
+ bool head, tail;
+ int id;
+
+ void Reset();
+
+ static Credit * New();
+ void Free();
+ static void FreeAll();
+ static int OutStanding();
+private:
+
+ static stack<Credit *> _all;
+ static stack<Credit *> _free;
+
+ Credit();
+ ~Credit() {}
+
+};
+
+#endif
diff --git a/src/intersim2/examples/cmeshconfig b/src/intersim2/examples/cmeshconfig
new file mode 100644
index 0000000..c71ff8d
--- /dev/null
+++ b/src/intersim2/examples/cmeshconfig
@@ -0,0 +1,47 @@
+// $Id: cmeshconfig 5188 2012-08-30 00:31:31Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//concentrated mesh configuration file running batch mode
+//xr, yr, x, y, are use to indicate how the concnetration is formed.
+
+topology = cmesh;
+
+k = 4;
+n = 2;
+c = 4;
+xr = 2;
+yr = 2;
+
+x = 4;
+y = 4;
+
+routing_function = dor_no_express;
+
+traffic = bitcomp;
+
+use_read_write = 0;
+
+batch_size = 2000;
diff --git a/src/intersim2/examples/dragonflyconfig b/src/intersim2/examples/dragonflyconfig
new file mode 100644
index 0000000..763b549
--- /dev/null
+++ b/src/intersim2/examples/dragonflyconfig
@@ -0,0 +1,79 @@
+// $Id: dragonflyconfig 5188 2012-08-30 00:31:31Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+// Dragonfly
+//
+
+
+
+
+vc_buf_size = 256;
+
+
+wait_for_tail_credit = 0;
+
+//
+// Router architecture
+//
+vc_allocator = separable_input_first;
+sw_allocator = separable_input_first;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+st_final_delay = 1;
+
+input_speedup = 1;
+output_speedup = 1;
+internal_speedup = 2.0;
+
+
+warmup_periods = 3;
+sim_count = 1;
+
+sample_period = 10000;
+
+
+
+routing_function = min;
+num_vcs = 2;
+
+priority = none;
+traffic = uniform;
+
+injection_rate = 0.8;
+packet_size = 10;
+injection_rate_uses_flits=1;
+
+topology = dragonflynew;
+
+k = 4;
+n = 1;
+
+watch_out=-;
+
diff --git a/src/intersim2/examples/fattree_config b/src/intersim2/examples/fattree_config
new file mode 100644
index 0000000..b4202ff
--- /dev/null
+++ b/src/intersim2/examples/fattree_config
@@ -0,0 +1,76 @@
+// $Id: dragonflyconfig 3555 2011-05-16 23:37:55Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+
+hold_switch_for_packet=1;
+
+vc_buf_size = 16;
+
+
+wait_for_tail_credit = 0;
+
+//
+// Router architecture
+//
+vc_allocator = separable_input_first;
+sw_allocator = separable_input_first;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+st_final_delay = 1;
+
+input_speedup = 1;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+
+warmup_periods = 3;
+sim_count = 1;
+
+sample_period = 10000;
+
+
+
+routing_function = nca;
+num_vcs = 4;
+
+priority = none;
+traffic = uniform;
+
+injection_rate = 0.6;
+packet_size = 1;
+injection_rate_uses_flits=1;
+
+topology = fattree;
+
+
+k = 4;
+n = 3;
+
+watch_out=-; \ No newline at end of file
diff --git a/src/intersim2/examples/flatflyconfig b/src/intersim2/examples/flatflyconfig
new file mode 100644
index 0000000..6674d28
--- /dev/null
+++ b/src/intersim2/examples/flatflyconfig
@@ -0,0 +1,116 @@
+// $Id: flatflyconfig 5188 2012-08-30 00:31:31Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//A flattened butterfly configurate file with many tweaks from the
+//default settings.
+
+
+// Flow control
+// Total number of VCs must match the above assignments
+num_vcs = 8;
+vc_buf_size = 4;
+
+wait_for_tail_credit = 0;
+
+//
+// Router architectureq
+//
+vc_allocator = islip;
+sw_allocator = islip;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+st_final_delay = 1;
+
+input_speedup = 1;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+//
+// Traffic
+//
+
+warmup_periods = 3;
+
+sample_period = 1000;
+
+sim_count = 1;
+
+traffic = uniform;
+
+
+// Flatfly
+//
+// #node = k^(n+1)
+//
+// x, y, specifies the arrangement of routers in x and y dim
+// xr, yr specifiies the arayment of clients in a router
+//
+topology = flatfly;
+subnets = 1;
+
+c = 4;
+k = 4;
+n = 2;
+
+x = 4;
+y = 4;
+xr = 2;
+yr = 2;
+
+//
+// Routing
+//
+
+routing_function = ran_min;
+
+//1: batch mode, 0: injection mode
+use_read_write = 0;
+
+//for injection mode
+packet_size = 1;
+injection_rate = 0.1;
+
+//for batch mode
+read_request_size=1;
+write_request_size=1;
+read_reply_size=1;
+write_reply_size=1;
+
+read_request_begin_vc = 0;
+read_request_end_vc = 3;
+write_reply_begin_vc = 4;
+write_reply_end_vc = 7;
+read_reply_begin_vc = 4;
+read_reply_end_vc = 7;
+write_request_begin_vc = 0;
+write_request_end_vc = 3;
+
+//latency: drains all packet, throughput:no drain?
+sim_type = latency;
diff --git a/src/intersim2/examples/mesh88_lat b/src/intersim2/examples/mesh88_lat
new file mode 100644
index 0000000..189104e
--- /dev/null
+++ b/src/intersim2/examples/mesh88_lat
@@ -0,0 +1,69 @@
+// $Id: mesh88_lat 5506 2013-05-07 21:22:23Z qtedq $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//8X8 mesh with 20 flits per packet under injection mode
+//injection rate here is packet per cycle, NOT flit per cycle
+
+// Topology
+
+topology = mesh;
+k = 8;
+n = 2;
+
+// Routing
+routing_function = dor;
+
+// Flow control
+num_vcs = 8;
+vc_buf_size = 8;
+wait_for_tail_credit = 1;
+
+// Router architecture
+vc_allocator = islip;
+sw_allocator = islip;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+
+// Traffic
+traffic = transpose;
+packet_size = 20;
+
+
+// Simulation
+sim_type = latency;
+
+injection_rate = 0.005;
+watch_packets = {1,1,1};
+
diff --git a/src/intersim2/examples/mesh88_lat_hotspot b/src/intersim2/examples/mesh88_lat_hotspot
new file mode 100644
index 0000000..45c2b3f
--- /dev/null
+++ b/src/intersim2/examples/mesh88_lat_hotspot
@@ -0,0 +1,82 @@
+// $Id: mesh88_lat 5487 2013-02-27 08:16:18Z qtedq $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//8X8 mesh with 20 flits per packet under injection mode
+//injection rate here is packet per cycle, NOT flit per cycle
+
+// Topology
+
+topology = mesh;
+k = 8;
+n = 2;
+
+// Routing
+
+routing_function = dor;
+
+// Flow control
+
+num_vcs = 8;
+vc_buf_size = 8;
+
+wait_for_tail_credit = 0;
+
+// Router architecture
+
+vc_allocator = separable_input_first;
+sw_allocator = separable_input_first;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+speculative=1;
+
+input_speedup = 1;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = hotspot;
+packet_size ={{1,2,3,4},{10,20}};
+packet_size_rate={{1,1,1,1},{2,1}};
+// Simulation
+
+sim_type = latency;
+latency_thres = 100000.0;
+
+injection_rate = 0.1;
+
+
+classes=2;
+
+
+classes=2;
+injection_rate={0.01,0.01};
+packet_size={{1,5},{10,20}};
+packet_size_rate={{1,1},{2,1}};
diff --git a/src/intersim2/examples/singleconfig b/src/intersim2/examples/singleconfig
new file mode 100644
index 0000000..aca3d28
--- /dev/null
+++ b/src/intersim2/examples/singleconfig
@@ -0,0 +1,57 @@
+// $Id: singleconfig 5188 2012-08-30 00:31:31Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//A single cross 10X10 cross bar under injection mode
+
+topology = fly;
+
+k = 10;
+n = 1;
+
+num_vcs = 8;
+
+vc_buf_size = 8;
+
+vc_allocator = separable_input_first;
+sw_allocator = separable_input_first;
+
+routing_function = dest_tag;
+
+traffic = uniform;
+
+use_read_write = 0;
+
+injection_rate = 1.0;
+
+
+
+
+sample_period = 100000;
+
+routing_delay = 0;
+vc_alloc_delay = 1;
+sw_alloc_delay = 1;
+st_final_delay = 1;
diff --git a/src/intersim2/examples/torus88 b/src/intersim2/examples/torus88
new file mode 100644
index 0000000..17ae91f
--- /dev/null
+++ b/src/intersim2/examples/torus88
@@ -0,0 +1,40 @@
+// $Id: torus88 5188 2012-08-30 00:31:31Z dub $
+
+// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+//simple 8X8 torus under injection mode
+
+
+// Topology
+topology = torus;
+k = 8;
+n = 2;
+// Routing
+routing_function = dim_order;
+// Flow control
+num_vcs = 2;
+// Traffic
+traffic = uniform;
+injection_rate = 0.15;
diff --git a/src/intersim2/flit.cpp b/src/intersim2/flit.cpp
new file mode 100644
index 0000000..8e0c66f
--- /dev/null
+++ b/src/intersim2/flit.cpp
@@ -0,0 +1,107 @@
+// $Id: flit.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*flit.cpp
+ *
+ *flit struct is a flit, carries all the control signals that a flit needs
+ *Add additional signals as necessary. Flits has no concept of length
+ *it is a singluar object.
+ *
+ *When adding objects make sure to set a default value in this constructor
+ */
+
+#include "booksim.hpp"
+#include "flit.hpp"
+
+stack<Flit *> Flit::_all;
+stack<Flit *> Flit::_free;
+
+ostream& operator<<( ostream& os, const Flit& f )
+{
+ os << " Flit ID: " << f.id << " (" << &f << ")"
+ << " Packet ID: " << f.pid
+ << " Type: " << f.type
+ << " Head: " << f.head
+ << " Tail: " << f.tail << endl;
+ os << " Source: " << f.src << " Dest: " << f.dest << " Intm: "<<f.intm<<endl;
+ os << " Creation time: " << f.ctime << " Injection time: " << f.itime << " Arrival time: " << f.atime << " Phase: "<<f.ph<< endl;
+ os << " VC: " << f.vc << endl;
+ return os;
+}
+
+Flit::Flit()
+{
+ Reset();
+}
+
+void Flit::Reset()
+{
+ type = ANY_TYPE ;
+ vc = -1 ;
+ cl = -1 ;
+ head = false ;
+ tail = false ;
+ ctime = -1 ;
+ itime = -1 ;
+ atime = -1 ;
+ id = -1 ;
+ pid = -1 ;
+ hops = 0 ;
+ watch = false ;
+ record = false ;
+ intm = 0;
+ src = -1;
+ dest = -1;
+ pri = 0;
+ intm =-1;
+ ph = -1;
+ data = 0;
+}
+
+Flit * Flit::New() {
+ Flit * f;
+ if(_free.empty()) {
+ f = new Flit;
+ _all.push(f);
+ } else {
+ f = _free.top();
+ f->Reset();
+ _free.pop();
+ }
+ return f;
+}
+
+void Flit::Free() {
+ _free.push(this);
+}
+
+void Flit::FreeAll() {
+ while(!_all.empty()) {
+ delete _all.top();
+ _all.pop();
+ }
+}
diff --git a/src/intersim2/flit.hpp b/src/intersim2/flit.hpp
new file mode 100644
index 0000000..fd48306
--- /dev/null
+++ b/src/intersim2/flit.hpp
@@ -0,0 +1,104 @@
+// $Id: flit.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _FLIT_HPP_
+#define _FLIT_HPP_
+
+#include <iostream>
+#include <stack>
+
+#include "booksim.hpp"
+#include "outputset.hpp"
+
+class Flit {
+
+public:
+
+ const static int NUM_FLIT_TYPES = 5;
+ enum FlitType { READ_REQUEST = 0,
+ READ_REPLY = 1,
+ WRITE_REQUEST = 2,
+ WRITE_REPLY = 3,
+ ANY_TYPE = 4 };
+ FlitType type;
+
+ int vc;
+
+ int cl;
+
+ bool head;
+ bool tail;
+
+ int ctime;
+ int itime;
+ int atime;
+
+ int id;
+ int pid;
+
+ bool record;
+
+ int src;
+ int dest;
+
+ int pri;
+
+ int hops;
+ bool watch;
+ int subnetwork;
+
+ // intermediate destination (if any)
+ mutable int intm;
+
+ // phase in multi-phase algorithms
+ mutable int ph;
+
+ // Fields for arbitrary data
+ void* data ;
+
+ // Lookahead route info
+ OutputSet la_route_set;
+
+ void Reset();
+
+ static Flit * New();
+ void Free();
+ static void FreeAll();
+
+private:
+
+ Flit();
+ ~Flit() {}
+
+ static stack<Flit *> _all;
+ static stack<Flit *> _free;
+
+};
+
+ostream& operator<<( ostream& os, const Flit& f );
+
+#endif
diff --git a/src/intersim2/flitchannel.cpp b/src/intersim2/flitchannel.cpp
new file mode 100644
index 0000000..0515f5f
--- /dev/null
+++ b/src/intersim2/flitchannel.cpp
@@ -0,0 +1,91 @@
+// $Id: flitchannel.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// File Name: flitchannel.cpp
+// Author: James Balfour, Rebecca Schultz
+//
+// ----------------------------------------------------------------------
+
+#include "flitchannel.hpp"
+
+#include <iostream>
+#include <iomanip>
+
+#include "router.hpp"
+#include "globals.hpp"
+
+// ----------------------------------------------------------------------
+// $Author: jbalfour $
+// $Date: 2007/06/27 23:10:17 $
+// $Id: flitchannel.cpp 5188 2012-08-30 00:31:31Z dub $
+// ----------------------------------------------------------------------
+FlitChannel::FlitChannel(Module * parent, string const & name, int classes)
+: Channel<Flit>(parent, name), _routerSource(NULL), _routerSourcePort(-1),
+ _routerSink(NULL), _routerSinkPort(-1), _idle(0), _classes(classes) {
+ _active.resize(classes, 0);
+}
+
+void FlitChannel::SetSource(Router const * const router, int port) {
+ _routerSource = router;
+ _routerSourcePort = port;
+}
+
+void FlitChannel::SetSink(Router const * const router, int port) {
+ _routerSink = router;
+ _routerSinkPort = port;
+}
+
+void FlitChannel::Send(Flit * f) {
+ if(f) {
+ ++_active[f->cl];
+ } else {
+ ++_idle;
+ }
+ Channel<Flit>::Send(f);
+}
+
+void FlitChannel::ReadInputs() {
+ Flit const * const & f = _input;
+ if(f && f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning channel traversal for flit " << f->id
+ << " with delay " << _delay
+ << "." << endl;
+ }
+ Channel<Flit>::ReadInputs();
+}
+
+void FlitChannel::WriteOutputs() {
+ Channel<Flit>::WriteOutputs();
+ if(_output && _output->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed channel traversal for flit " << _output->id
+ << "." << endl;
+ }
+}
diff --git a/src/intersim2/flitchannel.hpp b/src/intersim2/flitchannel.hpp
new file mode 100644
index 0000000..632ab10
--- /dev/null
+++ b/src/intersim2/flitchannel.hpp
@@ -0,0 +1,100 @@
+// $Id: flitchannel.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// File Name: flitchannel.hpp
+//
+// The FlitChannel models a flit channel with a multi-cycle
+// transmission delay. The channel latency can be specified as
+// an integer number of simulator cycles.
+// ----------------------------------------------------------------------
+
+#ifndef FLITCHANNEL_HPP
+#define FLITCHANNEL_HPP
+
+// ----------------------------------------------------------------------
+// $Author: jbalfour $
+// $Date: 2007/06/27 23:10:17 $
+// $Id: flitchannel.hpp 5188 2012-08-30 00:31:31Z dub $
+// ----------------------------------------------------------------------
+
+#include "channel.hpp"
+#include "flit.hpp"
+
+using namespace std;
+
+class Router ;
+
+class FlitChannel : public Channel<Flit> {
+public:
+ FlitChannel(Module * parent, string const & name, int classes);
+
+ void SetSource(Router const * const router, int port) ;
+ inline Router const * const GetSource() const {
+ return _routerSource;
+ }
+ inline int const & GetSourcePort() const {
+ return _routerSourcePort;
+ }
+ void SetSink(Router const * const router, int port) ;
+ inline Router const * const GetSink() const {
+ return _routerSink;
+ }
+ inline int const & GetSinkPort() const {
+ return _routerSinkPort;
+ }
+ inline vector<int> const & GetActivity() const {
+ return _active;
+ }
+
+ // Send flit
+ virtual void Send(Flit * flit);
+
+ virtual void ReadInputs();
+ virtual void WriteOutputs();
+
+private:
+
+ ////////////////////////////////////////
+ //
+ // Power Models OBSOLETE
+ //
+ ////////////////////////////////////////
+
+ Router const * _routerSource;
+ int _routerSourcePort;
+ Router const * _routerSink;
+ int _routerSinkPort;
+
+ // Statistics for Activity Factors
+ vector<int> _active;
+ int _idle;
+ int _classes;
+};
+
+#endif
diff --git a/src/intersim2/globals.hpp b/src/intersim2/globals.hpp
new file mode 100644
index 0000000..c443512
--- /dev/null
+++ b/src/intersim2/globals.hpp
@@ -0,0 +1,56 @@
+// $Id: globals.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _GLOBALS_HPP_
+#define _GLOBALS_HPP_
+#include <string>
+#include <vector>
+#include <iostream>
+
+/*all declared in main.cpp*/
+
+int GetSimTime();
+
+class Stats;
+Stats * GetStats(const std::string & name);
+
+class InterconnectInterface;
+extern InterconnectInterface *g_icnt_interface;
+
+extern bool gPrintActivity;
+
+extern int gK;
+extern int gN;
+extern int gC;
+
+extern int gNodes;
+
+extern bool gTrace;
+
+extern std::ostream * gWatchOut;
+
+#endif
diff --git a/src/intersim2/gputrafficmanager.cpp b/src/intersim2/gputrafficmanager.cpp
new file mode 100644
index 0000000..bf422d6
--- /dev/null
+++ b/src/intersim2/gputrafficmanager.cpp
@@ -0,0 +1,676 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <sstream>
+#include <fstream>
+#include <limits>
+
+#include "gputrafficmanager.hpp"
+#include "interconnect_interface.hpp"
+#include "globals.hpp"
+
+
+GPUTrafficManager::GPUTrafficManager( const Configuration &config, const vector<Network *> &net)
+:TrafficManager(config, net)
+{
+ // The total simulations equal to number of kernels
+ _total_sims = 0;
+
+ _input_queue.resize(_subnets);
+ for ( int subnet = 0; subnet < _subnets; ++subnet) {
+ _input_queue[subnet].resize(_nodes);
+ for ( int node = 0; node < _nodes; ++node ) {
+ _input_queue[subnet][node].resize(_classes);
+ }
+ }
+}
+
+GPUTrafficManager::~GPUTrafficManager()
+{
+}
+
+void GPUTrafficManager::Init()
+{
+ _time = 0;
+ _sim_state = running;
+ _ClearStats( );
+
+}
+
+void GPUTrafficManager::_RetireFlit( Flit *f, int dest )
+{
+ _deadlock_timer = 0;
+
+ assert(_total_in_flight_flits[f->cl].count(f->id) > 0);
+ _total_in_flight_flits[f->cl].erase(f->id);
+
+ if(f->record) {
+ assert(_measured_in_flight_flits[f->cl].count(f->id) > 0);
+ _measured_in_flight_flits[f->cl].erase(f->id);
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << dest << " | "
+ << "Retiring flit " << f->id
+ << " (packet " << f->pid
+ << ", src = " << f->src
+ << ", dest = " << f->dest
+ << ", hops = " << f->hops
+ << ", flat = " << f->atime - f->itime
+ << ")." << endl;
+ }
+
+ if ( f->head && ( f->dest != dest ) ) {
+ ostringstream err;
+ err << "Flit " << f->id << " arrived at incorrect output " << dest;
+ Error( err.str( ) );
+ }
+
+ if((_slowest_flit[f->cl] < 0) ||
+ (_flat_stats[f->cl]->Max() < (f->atime - f->itime)))
+ _slowest_flit[f->cl] = f->id;
+
+ _flat_stats[f->cl]->AddSample( f->atime - f->itime);
+ if(_pair_stats){
+ _pair_flat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - f->itime );
+ }
+
+ if ( f->tail ) {
+ Flit * head;
+ if(f->head) {
+ head = f;
+ } else {
+ map<int, Flit *>::iterator iter = _retired_packets[f->cl].find(f->pid);
+ assert(iter != _retired_packets[f->cl].end());
+ head = iter->second;
+ _retired_packets[f->cl].erase(iter);
+ assert(head->head);
+ assert(f->pid == head->pid);
+ }
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << dest << " | "
+ << "Retiring packet " << f->pid
+ << " (plat = " << f->atime - head->ctime
+ << ", nlat = " << f->atime - head->itime
+ << ", frag = " << (f->atime - head->atime) - (f->id - head->id) // NB: In the spirit of solving problems using ugly hacks, we compute the packet length by taking advantage of the fact that the IDs of flits within a packet are contiguous.
+ << ", src = " << head->src
+ << ", dest = " << head->dest
+ << ")." << endl;
+ }
+
+// GPGPUSim: Memory will handle reply, do not need this
+#if 0
+ //code the source of request, look carefully, its tricky ;)
+ if (f->type == Flit::READ_REQUEST || f->type == Flit::WRITE_REQUEST) {
+ PacketReplyInfo* rinfo = PacketReplyInfo::New();
+ rinfo->source = f->src;
+ rinfo->time = f->atime;
+ rinfo->record = f->record;
+ rinfo->type = f->type;
+ _repliesPending[dest].push_back(rinfo);
+ } else {
+ if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){
+ _requestsOutstanding[dest]--;
+ } else if(f->type == Flit::ANY_TYPE) {
+ _requestsOutstanding[f->src]--;
+ }
+
+ }
+#endif
+
+ if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){
+ _requestsOutstanding[dest]--;
+ } else if(f->type == Flit::ANY_TYPE) {
+ ostringstream err;
+ err << "Flit " << f->id << " cannot be ANY_TYPE" ;
+ Error( err.str( ) );
+ }
+
+ // Only record statistics once per packet (at tail)
+ // and based on the simulation state
+ if ( ( _sim_state == warming_up ) || f->record ) {
+
+ _hop_stats[f->cl]->AddSample( f->hops );
+
+ if((_slowest_packet[f->cl] < 0) ||
+ (_plat_stats[f->cl]->Max() < (f->atime - head->itime)))
+ _slowest_packet[f->cl] = f->pid;
+ _plat_stats[f->cl]->AddSample( f->atime - head->ctime);
+ _nlat_stats[f->cl]->AddSample( f->atime - head->itime);
+ _frag_stats[f->cl]->AddSample( (f->atime - head->atime) - (f->id - head->id) );
+
+ if(_pair_stats){
+ _pair_plat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->ctime );
+ _pair_nlat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->itime );
+ }
+ }
+
+ if(f != head) {
+ head->Free();
+ }
+
+ }
+
+ if(f->head && !f->tail) {
+ _retired_packets[f->cl].insert(make_pair(f->pid, f));
+ } else {
+ f->Free();
+ }
+}
+int GPUTrafficManager::_IssuePacket( int source, int cl )
+{
+ return 0;
+}
+
+//TODO: Remove stype?
+void GPUTrafficManager::_GeneratePacket(int source, int stype, int cl, int time, int subnet, int packet_size, const Flit::FlitType& packet_type, void* const data, int dest)
+{
+ assert(stype!=0);
+
+ // Flit::FlitType packet_type = Flit::ANY_TYPE;
+ int size = packet_size; //input size
+ int pid = _cur_pid++;
+ assert(_cur_pid);
+ int packet_destination = dest;
+ bool record = false;
+ bool watch = gWatchOut && (_packets_to_watch.count(pid) > 0);
+
+ // In GPGPUSim, the core specified the packet_type and size
+
+#if 0
+ if(_use_read_write[cl]){
+ if(stype > 0) {
+ if (stype == 1) {
+ packet_type = Flit::READ_REQUEST;
+ size = _read_request_size[cl];
+ } else if (stype == 2) {
+ packet_type = Flit::WRITE_REQUEST;
+ size = _write_request_size[cl];
+ } else {
+ ostringstream err;
+ err << "Invalid packet type: " << packet_type;
+ Error( err.str( ) );
+ }
+ } else {
+ PacketReplyInfo* rinfo = _repliesPending[source].front();
+ if (rinfo->type == Flit::READ_REQUEST) {//read reply
+ size = _read_reply_size[cl];
+ packet_type = Flit::READ_REPLY;
+ } else if(rinfo->type == Flit::WRITE_REQUEST) { //write reply
+ size = _write_reply_size[cl];
+ packet_type = Flit::WRITE_REPLY;
+ } else {
+ ostringstream err;
+ err << "Invalid packet type: " << rinfo->type;
+ Error( err.str( ) );
+ }
+ packet_destination = rinfo->source;
+ time = rinfo->time;
+ record = rinfo->record;
+ _repliesPending[source].pop_front();
+ rinfo->Free();
+ }
+ }
+#endif
+
+ if ((packet_destination <0) || (packet_destination >= _nodes)) {
+ ostringstream err;
+ err << "Incorrect packet destination " << packet_destination
+ << " for stype " << packet_type;
+ Error( err.str( ) );
+ }
+
+ if ( ( _sim_state == running ) ||
+ ( ( _sim_state == draining ) && ( time < _drain_time ) ) ) {
+ record = _measure_stats[cl];
+ }
+
+ int subnetwork = subnet;
+ // ((packet_type == Flit::ANY_TYPE) ?
+ // RandomInt(_subnets-1) :
+ // _subnet[packet_type]);
+
+ if ( watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << source << " | "
+ << "Enqueuing packet " << pid
+ << " at time " << time
+ << "." << endl;
+ }
+
+ for ( int i = 0; i < size; ++i ) {
+ Flit * f = Flit::New();
+ f->id = _cur_id++;
+ assert(_cur_id);
+ f->pid = pid;
+ f->watch = watch | (gWatchOut && (_flits_to_watch.count(f->id) > 0));
+ f->subnetwork = subnetwork;
+ f->src = source;
+ f->ctime = time;
+ f->record = record;
+ f->cl = cl;
+ f->data = data;
+
+ _total_in_flight_flits[f->cl].insert(make_pair(f->id, f));
+ if(record) {
+ _measured_in_flight_flits[f->cl].insert(make_pair(f->id, f));
+ }
+
+ if(gTrace){
+ cout<<"New Flit "<<f->src<<endl;
+ }
+ f->type = packet_type;
+
+ if ( i == 0 ) { // Head flit
+ f->head = true;
+ //packets are only generated to nodes smaller or equal to limit
+ f->dest = packet_destination;
+ } else {
+ f->head = false;
+ f->dest = -1;
+ }
+ switch( _pri_type ) {
+ case class_based:
+ f->pri = _class_priority[cl];
+ assert(f->pri >= 0);
+ break;
+ case age_based:
+ f->pri = numeric_limits<int>::max() - time;
+ assert(f->pri >= 0);
+ break;
+ case sequence_based:
+ f->pri = numeric_limits<int>::max() - _packet_seq_no[source];
+ assert(f->pri >= 0);
+ break;
+ default:
+ f->pri = 0;
+ }
+ if ( i == ( size - 1 ) ) { // Tail flit
+ f->tail = true;
+ } else {
+ f->tail = false;
+ }
+
+ f->vc = -1;
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << source << " | "
+ << "Enqueuing flit " << f->id
+ << " (packet " << f->pid
+ << ") at time " << time
+ << "." << endl;
+ }
+
+ _input_queue[subnet][source][cl].push_back( f );
+ }
+}
+
+void GPUTrafficManager::_Step()
+{
+ bool flits_in_flight = false;
+ for(int c = 0; c < _classes; ++c) {
+ flits_in_flight |= !_total_in_flight_flits[c].empty();
+ }
+ if(flits_in_flight && (_deadlock_timer++ >= _deadlock_warn_timeout)){
+ _deadlock_timer = 0;
+ cout << "WARNING: Possible network deadlock.\n";
+ }
+
+ vector<map<int, Flit *> > flits(_subnets);
+
+ for ( int subnet = 0; subnet < _subnets; ++subnet ) {
+ for ( int n = 0; n < _nodes; ++n ) {
+ Flit * const f = _net[subnet]->ReadFlit( n );
+ if ( f ) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Ejecting flit " << f->id
+ << " (packet " << f->pid << ")"
+ << " from VC " << f->vc
+ << "." << endl;
+ }
+ g_icnt_interface->WriteOutBuffer(subnet, n, f);
+ }
+
+ g_icnt_interface->Transfer2BoundaryBuffer(subnet, n);
+ Flit* const ejected_flit = g_icnt_interface->GetEjectedFlit(subnet, n);
+ if (ejected_flit) {
+ if(ejected_flit->head)
+ assert(ejected_flit->dest == n);
+ if(ejected_flit->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Ejected flit " << ejected_flit->id
+ << " (packet " << ejected_flit->pid
+ << " VC " << ejected_flit->vc << ")"
+ << "from ejection buffer." << endl;
+ }
+ flits[subnet].insert(make_pair(n, ejected_flit));
+ if((_sim_state == warming_up) || (_sim_state == running)) {
+ ++_accepted_flits[ejected_flit->cl][n];
+ if(ejected_flit->tail) {
+ ++_accepted_packets[ejected_flit->cl][n];
+ }
+ }
+ }
+
+ // Processing the credit From the network
+ Credit * const c = _net[subnet]->ReadCredit( n );
+ if ( c ) {
+#ifdef TRACK_FLOWS
+ for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) {
+ int const vc = *iter;
+ assert(!_outstanding_classes[n][subnet][vc].empty());
+ int cl = _outstanding_classes[n][subnet][vc].front();
+ _outstanding_classes[n][subnet][vc].pop();
+ assert(_outstanding_credits[cl][subnet][n] > 0);
+ --_outstanding_credits[cl][subnet][n];
+ }
+#endif
+ _buf_states[n][subnet]->ProcessCredit(c);
+ c->Free();
+ }
+ }
+ _net[subnet]->ReadInputs( );
+ }
+
+// GPGPUSim will generate/inject packets from interconnection interface
+#if 0
+ if ( !_empty_network ) {
+ _Inject();
+ }
+#endif
+
+ for(int subnet = 0; subnet < _subnets; ++subnet) {
+
+ for(int n = 0; n < _nodes; ++n) {
+
+ Flit * f = NULL;
+
+ BufferState * const dest_buf = _buf_states[n][subnet];
+
+ int const last_class = _last_class[n][subnet];
+
+ int class_limit = _classes;
+
+ if(_hold_switch_for_packet) {
+ list<Flit *> const & pp = _input_queue[subnet][n][last_class];
+ if(!pp.empty() && !pp.front()->head &&
+ !dest_buf->IsFullFor(pp.front()->vc)) {
+ f = pp.front();
+ assert(f->vc == _last_vc[n][subnet][last_class]);
+
+ // if we're holding the connection, we don't need to check that class
+ // again in the for loop
+ --class_limit;
+ }
+ }
+
+ for(int i = 1; i <= class_limit; ++i) {
+
+ int const c = (last_class + i) % _classes;
+
+ list<Flit *> const & pp = _input_queue[subnet][n][c];
+
+ if(pp.empty()) {
+ continue;
+ }
+
+ Flit * const cf = pp.front();
+ assert(cf);
+ assert(cf->cl == c);
+
+ assert(cf->subnetwork == subnet);
+
+ if(f && (f->pri >= cf->pri)) {
+ continue;
+ }
+
+ if(cf->head && cf->vc == -1) { // Find first available VC
+
+ OutputSet route_set;
+ _rf(NULL, cf, -1, &route_set, true);
+ set<OutputSet::sSetElement> const & os = route_set.GetSet();
+ assert(os.size() == 1);
+ OutputSet::sSetElement const & se = *os.begin();
+ assert(se.output_port == -1);
+ int vc_start = se.vc_start;
+ int vc_end = se.vc_end;
+ int vc_count = vc_end - vc_start + 1;
+ if(_noq) {
+ assert(_lookahead_routing);
+ const FlitChannel * inject = _net[subnet]->GetInject(n);
+ const Router * router = inject->GetSink();
+ assert(router);
+ int in_channel = inject->GetSinkPort();
+
+ // NOTE: Because the lookahead is not for injection, but for the
+ // first hop, we have to temporarily set cf's VC to be non-negative
+ // in order to avoid seting of an assertion in the routing function.
+ cf->vc = vc_start;
+ _rf(router, cf, in_channel, &cf->la_route_set, false);
+ cf->vc = -1;
+
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Generating lookahead routing info for flit " << cf->id
+ << " (NOQ)." << endl;
+ }
+ set<OutputSet::sSetElement> const sl = cf->la_route_set.GetSet();
+ assert(sl.size() == 1);
+ int next_output = sl.begin()->output_port;
+ vc_count /= router->NumOutputs();
+ vc_start += next_output * vc_count;
+ vc_end = vc_start + vc_count - 1;
+ assert(vc_start >= se.vc_start && vc_start <= se.vc_end);
+ assert(vc_end >= se.vc_start && vc_end <= se.vc_end);
+ assert(vc_start <= vc_end);
+ }
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Finding output VC for flit " << cf->id
+ << ":" << endl;
+ }
+ for(int i = 1; i <= vc_count; ++i) {
+ int const lvc = _last_vc[n][subnet][c];
+ int const vc =
+ (lvc < vc_start || lvc > vc_end) ?
+ vc_start :
+ (vc_start + (lvc - vc_start + i) % vc_count);
+ assert((vc >= vc_start) && (vc <= vc_end));
+ if(!dest_buf->IsAvailableFor(vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output VC " << vc << " is busy." << endl;
+ }
+ } else {
+ if(dest_buf->IsFullFor(vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output VC " << vc << " is full." << endl;
+ }
+ } else {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Selected output VC " << vc << "." << endl;
+ }
+ cf->vc = vc;
+ break;
+ }
+ }
+ }
+ }
+
+ if(cf->vc == -1) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "No output VC found for flit " << cf->id
+ << "." << endl;
+ }
+ } else {
+ if(dest_buf->IsFullFor(cf->vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Selected output VC " << cf->vc
+ << " is full for flit " << cf->id
+ << "." << endl;
+ }
+ } else {
+ f = cf;
+ }
+ }
+ }
+
+ if(f) {
+
+ assert(f->subnetwork == subnet);
+
+ int const c = f->cl;
+
+ if(f->head) {
+
+ if (_lookahead_routing) {
+ if(!_noq) {
+ const FlitChannel * inject = _net[subnet]->GetInject(n);
+ const Router * router = inject->GetSink();
+ assert(router);
+ int in_channel = inject->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Generating lookahead routing info for flit " << f->id
+ << "." << endl;
+ }
+ } else if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Already generated lookahead routing info for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+
+ dest_buf->TakeBuffer(f->vc);
+ _last_vc[n][subnet][c] = f->vc;
+ }
+
+ _last_class[n][subnet] = c;
+
+ _input_queue[subnet][n][c].pop_front();
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[c][subnet][n];
+ _outstanding_classes[n][subnet][f->vc].push(c);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ if(_pri_type == network_age_based) {
+ f->pri = numeric_limits<int>::max() - _time;
+ assert(f->pri >= 0);
+ }
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Injecting flit " << f->id
+ << " into subnet " << subnet
+ << " at time " << _time
+ << " with priority " << f->pri
+ << "." << endl;
+ }
+ f->itime = _time;
+
+ // Pass VC "back"
+ if(!_input_queue[subnet][n][c].empty() && !f->tail) {
+ Flit * const nf = _input_queue[subnet][n][c].front();
+ nf->vc = f->vc;
+ }
+
+ if((_sim_state == warming_up) || (_sim_state == running)) {
+ ++_sent_flits[c][n];
+ if(f->head) {
+ ++_sent_packets[c][n];
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_injected_flits[c][n];
+#endif
+
+ _net[subnet]->WriteFlit(f, n);
+
+ }
+ }
+ }
+ //Send the credit To the network
+ for(int subnet = 0; subnet < _subnets; ++subnet) {
+ for(int n = 0; n < _nodes; ++n) {
+ map<int, Flit *>::const_iterator iter = flits[subnet].find(n);
+ if(iter != flits[subnet].end()) {
+ Flit * const f = iter->second;
+
+ f->atime = _time;
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Injecting credit for VC " << f->vc
+ << " into subnet " << subnet
+ << "." << endl;
+ }
+ Credit * const c = Credit::New();
+ c->vc.insert(f->vc);
+ _net[subnet]->WriteCredit(c, n);
+
+#ifdef TRACK_FLOWS
+ ++_ejected_flits[f->cl][n];
+#endif
+
+ _RetireFlit(f, n);
+ }
+ }
+ flits[subnet].clear();
+ // _InteralStep here
+ _net[subnet]->Evaluate( );
+ _net[subnet]->WriteOutputs( );
+ }
+
+ ++_time;
+ assert(_time);
+ if(gTrace){
+ cout<<"TIME "<<_time<<endl;
+ }
+
+}
+
diff --git a/src/intersim2/gputrafficmanager.hpp b/src/intersim2/gputrafficmanager.hpp
new file mode 100644
index 0000000..65d2717
--- /dev/null
+++ b/src/intersim2/gputrafficmanager.hpp
@@ -0,0 +1,74 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _GPUTRAFFICMANAGER_HPP_
+#define _GPUTRAFFICMANAGER_HPP_
+
+#include <iostream>
+#include <vector>
+#include <list>
+
+#include "config_utils.hpp"
+#include "stats.hpp"
+#include "trafficmanager.hpp"
+#include "booksim.hpp"
+#include "booksim_config.hpp"
+#include "flit.hpp"
+
+class GPUTrafficManager : public TrafficManager {
+
+protected:
+ virtual void _RetireFlit( Flit *f, int dest );
+ virtual void _GeneratePacket(int source, int stype, int cl, int time, int subnet, int package_size, const Flit::FlitType& packet_type, void* const data, int dest);
+ virtual int _IssuePacket( int source, int cl );
+ virtual void _Step();
+
+ // record size of _partial_packets for each subnet
+ vector<vector<vector<list<Flit *> > > > _input_queue;
+
+public:
+
+ GPUTrafficManager( const Configuration &config, const vector<Network *> & net );
+ virtual ~GPUTrafficManager( );
+
+ // correspond to TrafficManger::Run/SingleSim
+ void Init();
+
+ // TODO: if it is not good...
+ friend class InterconnectInterface;
+
+
+
+ // virtual void WriteStats( ostream & os = cout ) const;
+ // virtual void DisplayStats( ostream & os = cout ) const;
+ // virtual void DisplayOverallStats( ostream & os = cout ) const;
+
+};
+
+
+
+#endif
diff --git a/src/intersim2/injection.cpp b/src/intersim2/injection.cpp
new file mode 100644
index 0000000..b192ce3
--- /dev/null
+++ b/src/intersim2/injection.cpp
@@ -0,0 +1,190 @@
+// $Id: injection.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <iostream>
+#include <vector>
+#include <cassert>
+#include <limits>
+#include "random_utils.hpp"
+#include "injection.hpp"
+
+using namespace std;
+
+InjectionProcess::InjectionProcess(int nodes, double rate)
+ : _nodes(nodes), _rate(rate)
+{
+ if(nodes <= 0) {
+ cout << "Error: Number of nodes must be greater than zero." << endl;
+ exit(-1);
+ }
+ if((rate < 0.0) || (rate > 1.0)) {
+ cout << "Error: Injection process must have load between 0.0 and 1.0."
+ << endl;
+ exit(-1);
+ }
+}
+
+void InjectionProcess::reset()
+{
+
+}
+
+InjectionProcess * InjectionProcess::New(string const & inject, int nodes,
+ double load,
+ Configuration const * const config)
+{
+ string process_name;
+ string param_str;
+ size_t left = inject.find_first_of('(');
+ if(left == string::npos) {
+ process_name = inject;
+ } else {
+ process_name = inject.substr(0, left);
+ size_t right = inject.find_last_of(')');
+ if(right == string::npos) {
+ param_str = inject.substr(left+1);
+ } else {
+ param_str = inject.substr(left+1, right-left-1);
+ }
+ }
+ vector<string> params = tokenize_str(param_str);
+
+ InjectionProcess * result = NULL;
+ if(process_name == "bernoulli") {
+ result = new BernoulliInjectionProcess(nodes, load);
+ } else if(process_name == "on_off") {
+ bool missing_params = false;
+ double alpha = numeric_limits<double>::quiet_NaN();
+ if(params.size() < 1) {
+ if(config) {
+ alpha = config->GetFloat("burst_alpha");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ alpha = atof(params[0].c_str());
+ }
+ double beta = numeric_limits<double>::quiet_NaN();
+ if(params.size() < 2) {
+ if(config) {
+ beta = config->GetFloat("burst_beta");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ beta = atof(params[1].c_str());
+ }
+ double r1 = numeric_limits<double>::quiet_NaN();
+ if(params.size() < 3) {
+ r1 = config ? config->GetFloat("burst_r1") : -1.0;
+ } else {
+ r1 = atof(params[2].c_str());
+ }
+ if(missing_params) {
+ cout << "Missing parameters for injection process: " << inject << endl;
+ exit(-1);
+ }
+ if((alpha < 0.0 && beta < 0.0) ||
+ (alpha < 0.0 && r1 < 0.0) ||
+ (beta < 0.0 && r1 < 0.0) ||
+ (alpha >= 0.0 && beta >= 0.0 && r1 >= 0.0)) {
+ cout << "Invalid parameters for injection process: " << inject << endl;
+ exit(-1);
+ }
+ vector<int> initial(nodes);
+ if(params.size() > 3) {
+ initial = tokenize_int(params[2]);
+ initial.resize(nodes, initial.back());
+ } else {
+ for(int n = 0; n < nodes; ++n) {
+ initial[n] = RandomInt(1);
+ }
+ }
+ result = new OnOffInjectionProcess(nodes, load, alpha, beta, r1, initial);
+ } else {
+ cout << "Invalid injection process: " << inject << endl;
+ exit(-1);
+ }
+ return result;
+}
+
+//=============================================================
+
+BernoulliInjectionProcess::BernoulliInjectionProcess(int nodes, double rate)
+ : InjectionProcess(nodes, rate)
+{
+
+}
+
+bool BernoulliInjectionProcess::test(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ return (RandomFloat() < _rate);
+}
+
+//=============================================================
+
+OnOffInjectionProcess::OnOffInjectionProcess(int nodes, double rate,
+ double alpha, double beta,
+ double r1, vector<int> initial)
+ : InjectionProcess(nodes, rate),
+ _alpha(alpha), _beta(beta), _r1(r1), _initial(initial)
+{
+ assert(alpha <= 1.0);
+ assert(beta <= 1.0);
+ assert(r1 <= 1.0);
+ if(alpha < 0.0) {
+ assert(beta >= 0.0);
+ assert(r1 >= 0.0);
+ _alpha = beta * rate / (r1 - rate);
+ } else if(beta < 0.0) {
+ assert(alpha >= 0.0);
+ assert(r1 >= 0.0);
+ _beta = alpha * (r1 - rate) / rate;
+ } else {
+ assert(r1 < 0.0);
+ _r1 = rate * (alpha + beta) / alpha;
+ }
+ reset();
+}
+
+void OnOffInjectionProcess::reset()
+{
+ _state = _initial;
+}
+
+bool OnOffInjectionProcess::test(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ // advance state
+ _state[source] =
+ _state[source] ? (RandomFloat() >= _beta) : (RandomFloat() < _alpha);
+
+ // generate packet
+ return _state[source] && (RandomFloat() < _r1);
+}
diff --git a/src/intersim2/injection.hpp b/src/intersim2/injection.hpp
new file mode 100644
index 0000000..53dab67
--- /dev/null
+++ b/src/intersim2/injection.hpp
@@ -0,0 +1,68 @@
+// $Id: injection.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _INJECTION_HPP_
+#define _INJECTION_HPP_
+
+#include "config_utils.hpp"
+
+using namespace std;
+
+class InjectionProcess {
+protected:
+ int _nodes;
+ double _rate;
+ InjectionProcess(int nodes, double rate);
+public:
+ virtual ~InjectionProcess() {}
+ virtual bool test(int source) = 0;
+ virtual void reset();
+ static InjectionProcess * New(string const & inject, int nodes, double load,
+ Configuration const * const config = NULL);
+};
+
+class BernoulliInjectionProcess : public InjectionProcess {
+public:
+ BernoulliInjectionProcess(int nodes, double rate);
+ virtual bool test(int source);
+};
+
+class OnOffInjectionProcess : public InjectionProcess {
+private:
+ double _alpha;
+ double _beta;
+ double _r1;
+ vector<int> _initial;
+ vector<int> _state;
+public:
+ OnOffInjectionProcess(int nodes, double rate, double alpha, double beta,
+ double r1, vector<int> initial);
+ virtual void reset();
+ virtual bool test(int source);
+};
+
+#endif
diff --git a/src/intersim2/interconnect_interface.cpp b/src/intersim2/interconnect_interface.cpp
new file mode 100644
index 0000000..338e82e
--- /dev/null
+++ b/src/intersim2/interconnect_interface.cpp
@@ -0,0 +1,501 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+
+#include "interconnect_interface.hpp"
+#include "routefunc.hpp"
+#include "globals.hpp"
+#include "trafficmanager.hpp"
+#include "power_module.hpp"
+#include "mem_fetch.h"
+#include "flit.hpp"
+#include "gputrafficmanager.hpp"
+#include "booksim.hpp"
+#include "intersim_config.hpp"
+#include "network.hpp"
+
+InterconnectInterface::InterconnectInterface(const char* const config_file, unsigned int n_shader, unsigned int n_mem)
+:_n_shader(n_shader), _n_mem(n_mem)
+{
+ if (! config_file ) {
+ cout << "Interconnect Requires a configfile" << endl;
+ exit (-1);
+ }
+ _icnt_config = new IntersimConfig();
+ _icnt_config->ParseFile(config_file);
+
+ InitializeRoutingMap(*_icnt_config);
+
+ gPrintActivity = (_icnt_config->GetInt("print_activity") > 0);
+ gTrace = (_icnt_config->GetInt("viewer_trace") > 0);
+
+ string watch_out_file = _icnt_config->GetStr( "watch_out" );
+ if(watch_out_file == "") {
+ gWatchOut = NULL;
+ } else if(watch_out_file == "-") {
+ gWatchOut = &cout;
+ } else {
+ gWatchOut = new ofstream(watch_out_file.c_str());
+ }
+
+ _subnets = _icnt_config->GetInt("subnets");
+ assert(_subnets);
+
+ /*To include a new network, must register the network here
+ *add an else if statement with the name of the network
+ */
+ _net.resize(_subnets);
+ for (int i = 0; i < _subnets; ++i) {
+ ostringstream name;
+ name << "network_" << i;
+ _net[i] = Network::New( *_icnt_config, name.str() );
+ }
+
+ assert(_icnt_config->GetStr("sim_type") == "gpgpusim");
+ _traffic_manager = static_cast<GPUTrafficManager*>(TrafficManager::New( *_icnt_config, _net )) ;
+
+ _flit_size = _icnt_config->GetInt( "flit_size" );
+
+ // Config for interface buffers
+ if (_icnt_config->GetInt("ejection_buffer_size")) {
+ _ejection_buffer_capacity = _icnt_config->GetInt( "ejection_buffer_size" ) ;
+ } else {
+ _ejection_buffer_capacity = _icnt_config->GetInt( "vc_buf_size" );
+ }
+
+ _boundary_buffer_capacity = _icnt_config->GetInt( "boundary_buffer_size" ) ;
+ assert(_boundary_buffer_capacity);
+ if (_icnt_config->GetInt("input_buffer_size")) {
+ _input_buffer_capacity = _icnt_config->GetInt("input_buffer_size");
+ } else {
+ _input_buffer_capacity = 9;
+ }
+ _vcs = _icnt_config->GetInt("num_vcs");
+
+ _CreateBuffer();
+ _CreateNodeMap(_n_shader, _n_mem, _traffic_manager->_nodes, _icnt_config->GetInt("use_map"));
+
+}
+
+InterconnectInterface::~InterconnectInterface()
+{
+ for (int i=0; i<_subnets; ++i) {
+ ///Power analysis
+ if(_icnt_config->GetInt("sim_power") > 0){
+ Power_Module pnet(_net[i], *_icnt_config);
+ pnet.run();
+ }
+ delete _net[i];
+ }
+
+ delete _traffic_manager;
+ _traffic_manager = NULL;
+ delete _icnt_config;
+}
+
+void InterconnectInterface::Init()
+{
+ _traffic_manager->Init();
+ // TODO: Should we init _round_robin_turn?
+ // _boundary_buffer, _ejection_buffer and _ejected_flit_queue should be cleared
+}
+
+void InterconnectInterface::Push(unsigned input_deviceID, unsigned output_deviceID, void *data, unsigned int size)
+{
+ int output_icntID = _node_map[output_deviceID];
+ int input_icntID = _node_map[input_deviceID];
+
+#if 0
+ cout<<"Call interconnect push input: "<<input<<" output: "<<output<<endl;
+#endif
+
+ //TODO: move to _IssuePacket
+ //TODO: create a Inject and wrap _IssuePacket and _GeneratePacket
+ unsigned int n_flits = size / _flit_size + ((size % _flit_size)? 1:0);
+ int subnet;
+ if (_subnets == 1) {
+ subnet = 0;
+ } else {
+ if (int(input_deviceID) < _n_shader ) {
+ subnet = 0;
+ } else {
+ subnet = 1;
+ }
+ }
+
+ Flit::FlitType packet_type;
+ mem_fetch* mf = static_cast<mem_fetch*>(data);
+
+ switch (mf->get_type()) {
+ case READ_REQUEST: packet_type = Flit::READ_REQUEST ;break;
+ case WRITE_REQUEST: packet_type = Flit::WRITE_REQUEST ;break;
+ case READ_REPLY: packet_type = Flit::READ_REPLY ;break;
+ case WRITE_ACK: packet_type = Flit::WRITE_REPLY ;break;
+ default: assert (0);
+ }
+
+ //TODO: _include_queuing ?
+ _traffic_manager->_GeneratePacket( input_icntID, -1, 0 /*class*/, _traffic_manager->_time, subnet, n_flits, packet_type, data, output_icntID);
+
+#if DOUB
+ cout <<"Traffic[" << subnet << "] (mapped) sending form "<< input_icntID << " to " << output_icntID << endl;
+#endif
+// }
+}
+
+void* InterconnectInterface::Pop(unsigned deviceID)
+{
+ int icntID = _node_map[deviceID];
+#if DEBUG
+ cout<<"Call interconnect POP " << output<<endl;
+#endif
+
+ void* data = NULL;
+
+ // 0-_n_shader-1 indicates reply(network 1), otherwise request(network 0)
+ int subnet = 0;
+ if (deviceID < _n_shader)
+ subnet = 1;
+
+ int turn = _round_robin_turn[subnet][icntID];
+ for (int vc=0;(vc<_vcs) && (data==NULL);vc++) {
+ if (_boundary_buffer[subnet][icntID][turn].HasPacket()) {
+ data = _boundary_buffer[subnet][icntID][turn].PopPacket();
+ }
+ turn++;
+ if (turn == _vcs) turn = 0;
+ }
+ if (data) {
+ _round_robin_turn[subnet][icntID] = turn;
+ }
+
+ return data;
+
+}
+
+void InterconnectInterface::Advance()
+{
+ _traffic_manager->_Step();
+}
+
+bool InterconnectInterface::Busy() const
+{
+ bool busy = !_traffic_manager->_measured_in_flight_flits[0].empty();
+ if (!busy) {
+ for (int s = 0; s < _subnets; ++s) {
+ for (int n = 0; n < _n_shader+_n_mem; ++n) {
+ //FIXME: if this cannot make sure _partial_packets is empty
+ assert(_traffic_manager->_input_queue[s][n][0].empty());
+ }
+ }
+ }
+ else
+ return true;
+ for (int s = 0; s < _subnets; ++s) {
+ for (int n=0; n < (_n_shader+_n_mem); ++n) {
+ for (int vc=0; vc<_vcs; ++vc) {
+ if (_boundary_buffer[s][n][vc].HasPacket() ) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool InterconnectInterface::HasBuffer(unsigned deviceID, unsigned int size) const
+{
+ bool has_buffer = false;
+ unsigned int n_flits = size / _flit_size + ((size % _flit_size)? 1:0);
+ int icntID = _node_map.find(deviceID)->second;
+
+ has_buffer = _traffic_manager->_input_queue[0][icntID][0].size() +n_flits <= _input_buffer_capacity;
+
+ if ((_subnets>1) && int(deviceID) >= _n_shader) // deviceID is memory node
+ has_buffer = _traffic_manager->_input_queue[1][icntID][0].size() +n_flits <= _input_buffer_capacity;
+
+ return has_buffer;
+}
+
+void InterconnectInterface::DisplayStats() const
+{
+ _traffic_manager->UpdateStats();
+ _traffic_manager->DisplayStats();
+}
+
+unsigned InterconnectInterface::GetFlitSize() const
+{
+ return _flit_size;
+}
+
+void InterconnectInterface::DisplayOverallStats() const
+{
+ // hack: booksim2 use _drain_time and calculate delta time based on it, but we don't, change this if you have a better idea
+ _traffic_manager->_drain_time = _traffic_manager->_time;
+ // hack: also _total_sims equals to number of kernel calls
+ _traffic_manager->_total_sims += 1;
+
+ _traffic_manager->_UpdateOverallStats();
+ _traffic_manager->DisplayOverallStats();
+ if(_traffic_manager->_print_csv_results) {
+ _traffic_manager->DisplayOverallStatsCSV();
+ }
+}
+
+void InterconnectInterface::DisplayState(FILE *fp) const
+{
+ fprintf(fp, "GPGPU-Sim uArch: ICNT:Display State: Under implementation\n");
+// fprintf(fp,"GPGPU-Sim uArch: interconnect busy state\n");
+
+// for (unsigned i=0; i<net_c;i++) {
+// if (traffic[i]->_measured_in_flight)
+// fprintf(fp," Network %u has %u _measured_in_flight\n", i, traffic[i]->_measured_in_flight );
+// }
+//
+// for (unsigned i=0 ;i<(_n_shader+_n_mem);i++ ) {
+// if( !traffic[0]->_partial_packets[i] [0].empty() )
+// fprintf(fp," Network 0 has nonempty _partial_packets[%u][0]\n", i);
+// if ( doub_net && !traffic[1]->_partial_packets[i] [0].empty() )
+// fprintf(fp," Network 1 has nonempty _partial_packets[%u][0]\n", i);
+// for (unsigned j=0;j<g_num_vcs;j++ ) {
+// if( !ejection_buf[i][j].empty() )
+// fprintf(fp," ejection_buf[%u][%u] is non-empty\n", i, j);
+// if( clock_boundary_buf[i][j].has_packet() )
+// fprintf(fp," clock_boundary_buf[%u][%u] has packet\n", i, j );
+// }
+// }
+}
+
+void InterconnectInterface::Transfer2BoundaryBuffer(int subnet, int output)
+{
+ Flit* flit;
+ int vc;
+ for (vc=0; vc<_vcs;vc++) {
+
+ if ( !_ejection_buffer[subnet][output][vc].empty() && _boundary_buffer[subnet][output][vc].Size() < _boundary_buffer_capacity ) {
+ flit = _ejection_buffer[subnet][output][vc].front();
+ assert(flit);
+
+ _ejection_buffer[subnet][output][vc].pop();
+ _boundary_buffer[subnet][output][vc].PushFlitData( flit->data, flit->tail);
+
+ _ejected_flit_queue[subnet][output].push(flit); //indicate this flit is already popped from ejection buffer and ready for credit return
+
+ if ( flit->head ) {
+ assert (flit->dest == output);
+ }
+ }
+ }
+}
+
+void InterconnectInterface::WriteOutBuffer(int subnet, int output_icntID, Flit* flit )
+{
+ int vc = flit->vc;
+ assert (_ejection_buffer[subnet][output_icntID][vc].size() < _ejection_buffer_capacity);
+ _ejection_buffer[subnet][output_icntID][vc].push(flit);
+}
+
+int InterconnectInterface::GetIcntTime() const
+{
+ return _traffic_manager->getTime();
+}
+
+Stats* InterconnectInterface::GetIcntStats(const string &name) const
+{
+ return _traffic_manager->getStats(name);
+}
+
+Flit* InterconnectInterface::GetEjectedFlit(int subnet, int node)
+{
+ Flit* flit = NULL;
+ if (!_ejected_flit_queue[subnet][node].empty()) {
+ flit = _ejected_flit_queue[subnet][node].front();
+ _ejected_flit_queue[subnet][node].pop();
+ }
+ return flit;
+}
+
+void InterconnectInterface::_CreateBuffer()
+{
+ int nodes = _n_shader + _n_mem;
+
+ _boundary_buffer.resize(_subnets);
+ _ejection_buffer.resize(_subnets);
+ _round_robin_turn.resize(_subnets);
+ _ejected_flit_queue.resize(_subnets);
+
+ for (int subnet = 0; subnet < _subnets; ++subnet) {
+ _ejection_buffer[subnet].resize(nodes);
+ _boundary_buffer[subnet].resize(nodes);
+ _round_robin_turn[subnet].resize(nodes);
+ _ejected_flit_queue[subnet].resize(nodes);
+
+ for (int node=0;node<nodes;++node){
+ _ejection_buffer[subnet][node].resize(_vcs);
+ _boundary_buffer[subnet][node].resize(_vcs);
+ }
+ }
+}
+
+void InterconnectInterface::_CreateNodeMap(int n_shader, int n_mem, int n_node, int use_map)
+{
+ if (use_map) {
+ map<int, vector<int> > preset_memory_map;
+
+ // good for 8 shaders and 8 memory cores
+ {
+ int memory_node[] = {1, 3, 4, 6, 9, 11, 12, 14};
+ preset_memory_map[16] = vector<int>(memory_node, memory_node+8);
+ }
+
+ // good for 28 shaders and 8 memory cores
+ {
+ int memory_node[] = {3, 7, 10, 12, 23, 25, 28, 32};
+ preset_memory_map[36] = vector<int>(memory_node, memory_node+8);
+ }
+
+ // good for 56 shaders and 8 memory cores
+ {
+ int memory_node[] = {3, 15, 17, 29, 36, 47, 49, 61};
+ preset_memory_map[64] = vector<int>(memory_node, memory_node+sizeof(memory_node)/sizeof(int));
+ }
+
+ // good for 110 shaders and 11 memory cores
+ {
+ int memory_node[] = {12, 20, 25, 28, 57, 60, 63, 92, 95,100,108};
+ preset_memory_map[121] = vector<int>(memory_node, memory_node+sizeof(memory_node)/sizeof(int));
+ }
+
+ const vector<int> &memory_node = preset_memory_map[n_node];
+ if (memory_node.empty()) {
+ cerr<<"ERROR!!! NO MAPPING IMPLEMENTED YET FOR THIS CONFIG"<<endl;
+ assert(0);
+ }
+
+ // create node map
+ int next_node = 0;
+ int memory_node_index = 0;
+ for (int i = 0; i < n_shader; ++i) {
+ while (next_node == memory_node[memory_node_index]) {
+ next_node += 1;
+ memory_node_index += 1;
+ }
+ _node_map[i] = next_node;
+ next_node += 1;
+ }
+ for (int i = n_shader; i < n_shader+n_mem; ++i) {
+ _node_map[i] = memory_node[i-n_shader];
+ }
+ } else { //not use preset map
+ for (int i=0;i<n_node;i++) {
+ _node_map[i]=i;
+ }
+ }
+
+ for (int i = 0; i < n_node ; i++) {
+ for (int j = 0; j< n_node ; j++) {
+ if ( _node_map[j] == i ) {
+ _reverse_node_map[i]=j;
+ break;
+ }
+ }
+ }
+
+ //FIXME: should compatible with non-squre number
+ _DisplayMap((int) sqrt(n_node), n_node);
+
+}
+
+void InterconnectInterface::_DisplayMap(int dim,int count)
+{
+ cout << "GPGPU-Sim uArch: interconnect node map (shaderID+MemID to icntID)" << endl;
+ cout << "GPGPU-Sim uArch: Memory nodes ID start from index: " << _n_shader << endl;
+ cout << "GPGPU-Sim uArch: ";
+ for (int i = 0;i < count; i++) {
+ cout << setw(4) << _node_map[i];
+ if ((i+1)%dim == 0 && i != count-1)
+ cout << endl << "GPGPU-Sim uArch: ";
+ }
+ cout << endl;
+
+ cout << "GPGPU-Sim uArch: interconnect node reverse map (icntID to shaderID+MemID)" << endl;
+ cout << "GPGPU-Sim uArch: Memory nodes start from ID: " << _n_shader << endl;
+ cout << "GPGPU-Sim uArch: ";
+ for (int i = 0;i < count; i++) {
+ cout << setw(4) << _reverse_node_map[i];
+ if ((i+1)%dim == 0 && i != count-1)
+ cout << endl << "GPGPU-Sim uArch: ";
+ }
+ cout << endl;
+}
+
+void* InterconnectInterface::_BoundaryBufferItem::PopPacket()
+{
+ assert (_packet_n);
+ void * data = NULL;
+ void * flit_data = _buffer.front();
+ while (data == NULL) {
+ assert(flit_data == _buffer.front()); //all flits must belong to the same packet
+ if (_tail_flag.front()) {
+ data = _buffer.front();
+ _packet_n--;
+ }
+ _buffer.pop();
+ _tail_flag.pop();
+ }
+ return data;
+}
+
+void* InterconnectInterface::_BoundaryBufferItem::TopPacket() const
+{
+ assert (_packet_n);
+ void* data = NULL;
+ void* temp_d = _buffer.front();
+ while (data==NULL) {
+ if (_tail_flag.front()) {
+ data = _buffer.front();
+ }
+ assert(temp_d == _buffer.front()); //all flits must belong to the same packet
+ }
+ return data;
+
+}
+
+void InterconnectInterface::_BoundaryBufferItem::PushFlitData(void* data,bool is_tail)
+{
+ _buffer.push(data);
+ _tail_flag.push(is_tail);
+ if (is_tail) {
+ _packet_n++;
+ }
+}
+
diff --git a/src/intersim2/interconnect_interface.hpp b/src/intersim2/interconnect_interface.hpp
new file mode 100644
index 0000000..6ce4418
--- /dev/null
+++ b/src/intersim2/interconnect_interface.hpp
@@ -0,0 +1,131 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _INTERCONNECT_INTERFACE_HPP_
+#define _INTERCONNECT_INTERFACE_HPP_
+
+#include <vector>
+#include <queue>
+#include <iostream>
+#include <map>
+using namespace std;
+
+
+// Do not use #include since it will not compile in icnt_wrapper or change the makefile to make it
+class Flit;
+class GPUTrafficManager;
+class IntersimConfig;
+class Network;
+class Stats;
+
+//TODO: fixed_lat_icnt, add class support? support for signle network
+
+class InterconnectInterface {
+public:
+ InterconnectInterface(const char* const config_file, unsigned int n_shader, unsigned int n_mem);
+ virtual ~InterconnectInterface();
+
+ //node side functions
+ void Init();
+ void Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size);
+ void* Pop(unsigned ouput_deviceID);
+ void Advance();
+ bool Busy() const;
+ bool HasBuffer(unsigned deviceID, unsigned int size) const;
+ void DisplayStats() const;
+ void DisplayOverallStats() const;
+ unsigned GetFlitSize() const;
+
+ void DisplayState(FILE* fp) const;
+
+ //booksim side functions
+ void WriteOutBuffer( int subnet, int output, Flit* flit );
+ void Transfer2BoundaryBuffer(int subnet, int output);
+
+ int GetIcntTime() const;
+
+ Stats* GetIcntStats(const string & name) const;
+
+ Flit* GetEjectedFlit(int subnet, int node);
+
+
+private:
+
+ class _BoundaryBufferItem {
+ public:
+ _BoundaryBufferItem():_packet_n(0) {}
+ inline unsigned Size(void) const { return _buffer.size(); }
+ inline bool HasPacket() const { return _packet_n; }
+ void* PopPacket();
+ void* TopPacket() const;
+ void PushFlitData(void* data,bool is_tail);
+
+ private:
+ queue<void *> _buffer;
+ queue<bool> _tail_flag;
+ int _packet_n;
+ };
+ typedef queue<Flit*> _EjectionBufferItem;
+
+ void _CreateBuffer( );
+ void _CreateNodeMap(int n_shader, int n_mem, int n_node, int use_map);
+ void _DisplayMap(int dim,int count);
+
+ // size: [subnets][nodes][vcs]
+ vector<vector<vector<_BoundaryBufferItem> > > _boundary_buffer;
+ unsigned int _boundary_buffer_capacity;
+ // size: [subnets][nodes][vcs]
+ vector<vector<vector<_EjectionBufferItem> > > _ejection_buffer;
+ // size:[subnets][nodes]
+ vector<vector<queue<Flit* > > > _ejected_flit_queue;
+
+ unsigned int _ejection_buffer_capacity;
+ unsigned int _input_buffer_capacity;
+
+ vector<vector<int> > _round_robin_turn; //keep track of _boundary_buffer last used in icnt_pop
+
+ GPUTrafficManager* _traffic_manager;
+ unsigned int _flit_size;
+ IntersimConfig* _icnt_config;
+ const int _n_shader, _n_mem;
+ vector<Network *> _net;
+ int _vcs;
+ int _subnets;
+
+ //deviceID to icntID map
+ //deviceID : Starts from 0 for shaders and then continues until mem nodes
+ //which starts at location n_shader and then continues to n_shader+n_mem (last device)
+ map<int, int> _node_map;
+
+ //icntID to deviceID map
+ map<int, int> _reverse_node_map;
+
+};
+
+#endif
+
+
diff --git a/src/intersim2/intersim_config.cpp b/src/intersim2/intersim_config.cpp
new file mode 100644
index 0000000..742fe9a
--- /dev/null
+++ b/src/intersim2/intersim_config.cpp
@@ -0,0 +1,54 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "intersim_config.hpp"
+
+IntersimConfig::IntersimConfig()
+{
+ // Add options for intersim
+
+ _int_map["perfect_icnt"] = 0; // if set overrides fixed_lat_per_hop setting
+ _int_map["fixed_lat_per_hop"] = 0; // if set icnt is NOT simulated instead packets are sent into destination based on a fixed_lat_per_hop
+ _int_map["network_count"] = 2; // number of independent interconnection networks (if it is set to 2 then 2 identical networks are created: sh2mem and mem2shd )
+
+ _int_map["output_extra_latency"] = 0;
+
+ _int_map["use_map"] = 1;
+
+ _int_map["flit_size"] = 32;
+ //stats
+ _int_map["enable_link_stats"] = 0; // show output link and VC utilization stats
+
+ _int_map["MATLAB_OUTPUT"] = 0; // output data in MATLAB friendly format
+ _int_map["DISPLAY_LAT_DIST"] = 0; // distribution of packet latencies
+ _int_map["DISPLAY_HOP_DIST"] = 0; // distribution of hop counts
+ _int_map["DISPLAY_PAIR_LATENCY"] = 0; // avg. latency for each s-d pair
+
+ _int_map["input_buffer_size"] = 0;
+ _int_map["ejection_buffer_size"] = 0; // if left zero the simulator will use the vc_buf_size instead
+ _int_map["boundary_buffer_size"] = 16;
+} \ No newline at end of file
diff --git a/src/intersim2/intersim_config.hpp b/src/intersim2/intersim_config.hpp
new file mode 100644
index 0000000..641dd22
--- /dev/null
+++ b/src/intersim2/intersim_config.hpp
@@ -0,0 +1,39 @@
+// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda
+// The University of British Columbia
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// Redistributions in binary form must reproduce the above copyright notice, this
+// list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+// Neither the name of The University of British Columbia nor the names of its
+// contributors may be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _INTERSIM_CONFIG_HPP_
+#define _INTERSIM_CONFIG_HPP_
+
+#include "config_utils.hpp"
+#include "booksim_config.hpp"
+
+class IntersimConfig : public BookSimConfig {
+public:
+ IntersimConfig();
+};
+
+#endif \ No newline at end of file
diff --git a/src/intersim2/main.cpp b/src/intersim2/main.cpp
new file mode 100644
index 0000000..9b43fff
--- /dev/null
+++ b/src/intersim2/main.cpp
@@ -0,0 +1,209 @@
+// $Id: main.cpp 5487 2013-02-27 08:16:18Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*main.cpp
+ *
+ *The starting point of the network simulator
+ *-Include all network header files
+ *-initilize the network
+ *-initialize the traffic manager and set it to run
+ *
+ *
+ */
+#include <sys/time.h>
+
+#include <string>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+
+
+#include <sstream>
+#include "booksim.hpp"
+#include "routefunc.hpp"
+#include "traffic.hpp"
+#include "booksim_config.hpp"
+#include "trafficmanager.hpp"
+#include "random_utils.hpp"
+#include "network.hpp"
+#include "injection.hpp"
+#include "power_module.hpp"
+#include "interconnect_interface.hpp"
+
+///////////////////////////////////////////////////////////////////////////////
+//Global declarations
+//////////////////////
+
+// Interconnect Interface instance
+InterconnectInterface *g_icnt_interface;
+
+/* the current traffic manager instance */
+TrafficManager * trafficManager = NULL;
+#if 0
+
+int GetSimTime() {
+ return trafficManager->getTime();
+}
+
+class Stats;
+Stats * GetStats(const std::string & name) {
+ Stats* test = trafficManager->getStats(name);
+ if(test == 0){
+ cout<<"warning statistics "<<name<<" not found"<<endl;
+ }
+ return test;
+}
+#else
+int GetSimTime() {
+ return g_icnt_interface->GetIcntTime();
+}
+
+class Stats;
+Stats * GetStats(const std::string & name) {
+ Stats* test = g_icnt_interface->GetIcntStats(name);
+ if(test == 0){
+ cout<<"warning statistics "<<name<<" not found"<<endl;
+ }
+ return test;
+}
+
+#endif
+
+/* printing activity factor*/
+bool gPrintActivity;
+
+int gK;//radix
+int gN;//dimension
+int gC;//concentration
+
+int gNodes;
+
+//generate nocviewer trace
+bool gTrace;
+
+ostream * gWatchOut;
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool Simulate( BookSimConfig const & config )
+{
+ vector<Network *> net;
+
+ int subnets = config.GetInt("subnets");
+ /*To include a new network, must register the network here
+ *add an else if statement with the name of the network
+ */
+ net.resize(subnets);
+ for (int i = 0; i < subnets; ++i) {
+ ostringstream name;
+ name << "network_" << i;
+ net[i] = Network::New( config, name.str() );
+ }
+
+ /*tcc and characterize are legacy
+ *not sure how to use them
+ */
+
+ assert(trafficManager == NULL);
+ trafficManager = TrafficManager::New( config, net ) ;
+
+ /*Start the simulation run
+ */
+
+ double total_time; /* Amount of time we've run */
+ struct timeval start_time, end_time; /* Time before/after user code */
+ total_time = 0.0;
+ gettimeofday(&start_time, NULL);
+
+ bool result = trafficManager->Run() ;
+
+
+ gettimeofday(&end_time, NULL);
+ total_time = ((double)(end_time.tv_sec) + (double)(end_time.tv_usec)/1000000.0)
+ - ((double)(start_time.tv_sec) + (double)(start_time.tv_usec)/1000000.0);
+
+ cout<<"Total run time "<<total_time<<endl;
+
+ for (int i=0; i<subnets; ++i) {
+
+ ///Power analysis
+ if(config.GetInt("sim_power") > 0){
+ Power_Module pnet(net[i], config);
+ pnet.run();
+ }
+
+ delete net[i];
+ }
+
+ delete trafficManager;
+ trafficManager = NULL;
+
+ return result;
+}
+
+#ifdef CREATE_LIBRARY
+
+#else
+int main( int argc, char **argv )
+{
+
+ BookSimConfig config;
+
+
+ if ( !ParseArgs( &config, argc, argv ) ) {
+ cerr << "Usage: " << argv[0] << " configfile... [param=value...]" << endl;
+ return 0;
+ }
+
+
+ /*initialize routing, traffic, injection functions
+ */
+ InitializeRoutingMap( config );
+
+ gPrintActivity = (config.GetInt("print_activity") > 0);
+ gTrace = (config.GetInt("viewer_trace") > 0);
+
+ string watch_out_file = config.GetStr( "watch_out" );
+ if(watch_out_file == "") {
+ gWatchOut = NULL;
+ } else if(watch_out_file == "-") {
+ gWatchOut = &cout;
+ } else {
+ gWatchOut = new ofstream(watch_out_file.c_str());
+ }
+
+
+ /*configure and run the simulator
+ */
+ bool result = Simulate( config );
+ return result ? -1 : 0;
+}
+#endif
+
diff --git a/src/intersim2/misc_utils.cpp b/src/intersim2/misc_utils.cpp
new file mode 100644
index 0000000..70ba93e
--- /dev/null
+++ b/src/intersim2/misc_utils.cpp
@@ -0,0 +1,52 @@
+// $Id: misc_utils.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include "misc_utils.hpp"
+
+int powi( int x, int y ) // compute x to the y
+{
+ int r = 1;
+
+ for ( int i = 0; i < y; ++i ) {
+ r *= x;
+ }
+
+ return r;
+}
+
+int log_two( int x )
+{
+ int r = 0;
+
+ x >>= 1;
+ while( x ) {
+ r++; x >>= 1;
+ }
+
+ return r;
+}
diff --git a/src/intersim2/misc_utils.hpp b/src/intersim2/misc_utils.hpp
new file mode 100644
index 0000000..5c478a3
--- /dev/null
+++ b/src/intersim2/misc_utils.hpp
@@ -0,0 +1,34 @@
+// $Id: misc_utils.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MISC_UTILS_HPP_
+#define _MISC_UTILS_HPP_
+
+int log_two( int x );
+int powi( int x, int y );
+
+#endif
diff --git a/src/intersim2/module.cpp b/src/intersim2/module.cpp
new file mode 100644
index 0000000..c6eb605
--- /dev/null
+++ b/src/intersim2/module.cpp
@@ -0,0 +1,88 @@
+// $Id: module.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*module.cpp
+ *
+ *The basic class that is extended by all other components of the network
+ *Provides the basic hierarchy structure and basic fuctions
+ *
+ */
+
+#include <iostream>
+#include <cstdlib>
+
+#include "booksim.hpp"
+#include "module.hpp"
+
+Module::Module( Module *parent, const string& name )
+{
+ _name = name;
+
+ if ( parent ) {
+ parent->_AddChild( this );
+ _fullname = parent->_fullname + "/" + name;
+ } else {
+ _fullname = name;
+ }
+}
+
+void Module::_AddChild( Module *child )
+{
+ _children.push_back( child );
+}
+
+void Module::DisplayHierarchy( int level, ostream & os ) const
+{
+ vector<Module *>::const_iterator mod_iter;
+
+ for ( int l = 0; l < level; l++ ) {
+ os << " ";
+ }
+
+ os << _name << endl;
+
+ for ( mod_iter = _children.begin( );
+ mod_iter != _children.end( ); mod_iter++ ) {
+ (*mod_iter)->DisplayHierarchy( level + 1 );
+ }
+}
+
+void Module::Error( const string& msg ) const
+{
+ cout << "Error in " << _fullname << " : " << msg << endl;
+ exit( -1 );
+}
+
+void Module::Debug( const string& msg ) const
+{
+ cout << "Debug (" << _fullname << ") : " << msg << endl;
+}
+
+void Module::Display( ostream & os ) const
+{
+ os << "Display method not implemented for " << _fullname << endl;
+}
diff --git a/src/intersim2/module.hpp b/src/intersim2/module.hpp
new file mode 100644
index 0000000..e24f723
--- /dev/null
+++ b/src/intersim2/module.hpp
@@ -0,0 +1,62 @@
+// $Id: module.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MODULE_HPP_
+#define _MODULE_HPP_
+
+#include "booksim.hpp"
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+class Module {
+private:
+ string _name;
+ string _fullname;
+
+ vector<Module *> _children;
+
+protected:
+ void _AddChild( Module *child );
+
+public:
+ Module( Module *parent, const string& name );
+ virtual ~Module( ) { }
+
+ inline const string & Name() const { return _name; }
+ inline const string & FullName() const { return _fullname; }
+
+ void DisplayHierarchy( int level = 0, ostream & os = cout ) const;
+
+ void Error( const string& msg ) const;
+ void Debug( const string& msg ) const;
+
+ virtual void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/networks/anynet.cpp b/src/intersim2/networks/anynet.cpp
new file mode 100644
index 0000000..4db1dfb
--- /dev/null
+++ b/src/intersim2/networks/anynet.cpp
@@ -0,0 +1,501 @@
+// $Id: anynet.cpp 5354 2012-11-07 23:51:49Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*anynet
+ *
+ *Network setup file format
+ *example 1:
+ *router 0 router 1 15 router 2
+ *
+ *Router 0 is connect to router 1 with a 15-cycle channel, and router 0 is connected to
+ * router 2 with a 1-cycle channel, the channels latency are unidirectional, so channel
+ * from router 1 back to router 0 is only single-cycle because it was not specified
+ *
+ *example 2:
+ *router 0 node 0 node 1 5 node 2 5
+ *
+ *Router 0 is directly connected to node 0-2. Channel latency is 5cycles for 1 and 2. In
+ * this case the latency specification is bidirectional, the injeciton and ejection lat
+ * for node 1 and 2 are 5-cycle
+ *
+ *other notes:
+ *
+ *Router and node numbers must be sequential starting with 0
+ *Credit channel latency follows the channel latency, even though it travels in revse
+ * direction this might not be desired
+ *
+ */
+
+#include "anynet.hpp"
+#include <fstream>
+#include <sstream>
+#include <limits>
+#include <algorithm>
+//this is a hack, I can't easily get the routing talbe out of the network
+map<int, int>* global_routing_table;
+
+AnyNet::AnyNet( const Configuration &config, const string & name )
+ : Network( config, name ){
+
+ router_list.resize(2);
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+AnyNet::~AnyNet(){
+ for(int i = 0; i < 2; ++i) {
+ for(map<int, map<int, pair<int,int> > >::iterator iter = router_list[i].begin();
+ iter != router_list[i].end();
+ ++iter) {
+ iter->second.clear();
+ }
+ }
+}
+
+void AnyNet::_ComputeSize( const Configuration &config ){
+ file_name = config.GetStr("network_file");
+ if(file_name==""){
+ cout<<"No network file name provided"<<endl;
+ exit(-1);
+ }
+ //parse the network description file
+ readFile();
+
+ _channels =0;
+ cout<<"========================Network File Parsed=================\n";
+ cout<<"******************node listing**********************\n";
+ map<int, int >::iterator iter;
+ for(iter = node_list.begin(); iter!=node_list.end(); iter++){
+ cout<<"Node "<<iter->first;
+ cout<<"\tRouter "<<iter->second<<endl;
+ }
+
+ map<int, map<int, pair<int,int> > >::iterator iter3;
+ cout<<"\n****************router to node listing*************\n";
+ for(iter3 = router_list[0].begin(); iter3!=router_list[0].end(); iter3++){
+ cout<<"Router "<<iter3->first<<endl;
+ map<int, pair<int,int> >::iterator iter2;
+ for(iter2 = iter3->second.begin();
+ iter2!=iter3->second.end();
+ iter2++){
+ cout<<"\t Node "<<iter2->first<<" lat "<<iter2->second.second<<endl;
+ }
+ }
+
+ cout<<"\n*****************router to router listing************\n";
+ for(iter3 = router_list[1].begin(); iter3!=router_list[1].end(); iter3++){
+ cout<<"Router "<<iter3->first<<endl;
+ map<int, pair<int,int> >::iterator iter2;
+ if(iter3->second.size() == 0){
+ cout<<"Caution Router "<<iter3->first
+ <<" is not connected to any other Router\n"<<endl;
+ }
+ for(iter2 = iter3->second.begin();
+ iter2!=iter3->second.end();
+ iter2++){
+ cout<<"\t Router "<<iter2->first<<" lat "<<iter2->second.second<<endl;
+ _channels++;
+ }
+ }
+
+ _size = router_list[1].size();
+ _nodes = node_list.size();
+
+}
+
+
+
+void AnyNet::_BuildNet( const Configuration &config ){
+
+
+ //I need to keep track the output ports for each router during build
+ int * outport = (int*)malloc(sizeof(int)*_size);
+ for(int i = 0; i<_size; i++){outport[i] = 0;}
+
+ cout<<"==========================Node to Router =====================\n";
+ //adding the injection/ejection chanenls first
+ map<int, map<int, pair<int,int> > >::iterator niter;
+ for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){
+ map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first);
+ //calculate radix
+ int radix = niter->second.size()+riter->second.size();
+ int node = niter->first;
+ cout<<"router "<<node<<" radix "<<radix<<endl;
+ //decalre the routers
+ ostringstream router_name;
+ router_name << "router";
+ router_name << "_" << node ;
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, radix, radix );
+ _timed_modules.push_back(_routers[node]);
+ //add injeciton ejection channels
+ map<int, pair<int,int> >::iterator nniter;
+ for(nniter = niter->second.begin();nniter!=niter->second.end(); nniter++){
+ int link = nniter->first;
+ //add the outport port assined to the map
+ (niter->second)[link].first = outport[node];
+ outport[node]++;
+ cout<<"\t connected to node "<<link<<" at outport "<<nniter->second.first
+ <<" lat "<<nniter->second.second<<endl;
+ _inject[link]->SetLatency(nniter->second.second);
+ _inject_cred[link]->SetLatency(nniter->second.second);
+ _eject[link]->SetLatency(nniter->second.second);
+ _eject_cred[link]->SetLatency(nniter->second.second);
+
+ _routers[node]->AddInputChannel( _inject[link], _inject_cred[link] );
+ _routers[node]->AddOutputChannel( _eject[link], _eject_cred[link] );
+ }
+
+ }
+
+ cout<<"==========================Router to Router =====================\n";
+ //add inter router channels
+ //since there is no way to systematically number the channels we just start from 0
+ //the map, is a mapping of output->input
+ int channel_count = 0;
+ for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){
+ map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first);
+ int node = niter->first;
+ map<int, pair<int,int> >::iterator rriter;
+ cout<<"router "<<node<<endl;
+ for(rriter = riter->second.begin();rriter!=riter->second.end(); rriter++){
+ int other_node = rriter->first;
+ int link = channel_count;
+ //add the outport port assined to the map
+ (riter->second)[other_node].first = outport[node];
+ outport[node]++;
+ cout<<"\t connected to router "<<other_node<<" using link "<<link
+ <<" at outport "<<rriter->second.first
+ <<" lat "<<rriter->second.second<<endl;
+
+ _chan[link]->SetLatency(rriter->second.second);
+ _chan_cred[link]->SetLatency(rriter->second.second);
+
+ _routers[node]->AddOutputChannel( _chan[link], _chan_cred[link] );
+ _routers[other_node]->AddInputChannel( _chan[link], _chan_cred[link]);
+ channel_count++;
+ }
+ }
+
+ buildRoutingTable();
+
+}
+
+
+void AnyNet::RegisterRoutingFunctions() {
+ gRoutingFunctionMap["min_anynet"] = &min_anynet;
+}
+
+void min_anynet( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ){
+ int out_port=-1;
+ if(!inject){
+ assert(global_routing_table[r->GetID()].count(f->dest)!=0);
+ out_port=global_routing_table[r->GetID()][f->dest];
+ }
+
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+void AnyNet::buildRoutingTable(){
+ cout<<"========================== Routing table =====================\n";
+ routing_table.resize(_size);
+ for(int i = 0; i<_size; i++){
+ route(i);
+ }
+ global_routing_table = &routing_table[0];
+}
+
+
+//11/7/2012
+//basically djistra's, tested on a large dragonfly anynet configuration
+void AnyNet::route(int r_start){
+ int* dist = new int[_size];
+ int* prev = new int[_size];
+ set<int> rlist;
+ for(int i = 0; i<_size; i++){
+ dist[i] = numeric_limits<int>::max();
+ prev[i] = -1;
+ rlist.insert(i);
+ }
+ dist[r_start] = 0;
+ while(!rlist.empty()){
+ //find min
+ int min_dist = numeric_limits<int>::max();
+ int min_cand = -1;
+ for(set<int>::iterator i = rlist.begin();
+ i!=rlist.end();
+ i++){
+ if(dist[*i]<min_dist){
+ min_dist = dist[*i];
+ min_cand = *i;
+ }
+ }
+ rlist.erase(min_cand);
+
+ //neighbor
+ for(map<int,pair<int,int> >::iterator i = router_list[1][min_cand].begin();
+ i!=router_list[1][min_cand].end();
+ i++){
+ int new_dist = dist[min_cand] + i->second.second;//distance is hops not cycles
+ if(new_dist < dist[i->first]){
+ dist[i->first] = new_dist;
+ prev[i->first] = min_cand;
+ }
+ }
+ }
+
+ //post process from the prev list
+ for(int i = 0; i<_size; i++){
+ if(prev[i] ==-1){ //self
+ assert(i == r_start);
+ for(map<int, pair<int, int> >::iterator iter = router_list[0][i].begin();
+ iter!=router_list[0][i].end();
+ iter++){
+ routing_table[r_start][iter->first]=iter->second.first;
+ //cout<<"node "<<iter->first<<" port "<< iter->second.first<<endl;
+ }
+ } else {
+ int distance=0;
+ int neighbor=i;
+ while(prev[neighbor]!=r_start){
+ assert(router_list[1][neighbor].count(prev[neighbor])>0);
+ distance+=router_list[1][prev[neighbor]][neighbor].second;//REVERSE lat
+ neighbor= prev[neighbor];
+ }
+ distance+=router_list[1][prev[neighbor]][neighbor].second;//lat
+
+ assert( router_list[1][r_start].count(neighbor)!=0);
+ int port = router_list[1][r_start][neighbor].first;
+ for(map<int, pair<int,int> >::iterator iter = router_list[0][i].begin();
+ iter!=router_list[0][i].end();
+ iter++){
+ routing_table[r_start][iter->first]=port;
+ //cout<<"node "<<iter->first<<" port "<< port<<" dist "<<distance<<endl;
+ }
+ }
+ }
+}
+
+
+void AnyNet::readFile(){
+
+ ifstream network_list;
+ string line;
+ enum ParseState{HEAD_TYPE=0,
+ HEAD_ID,
+ BODY_TYPE,
+ BODY_ID,
+ LINK_WEIGHT};
+ enum ParseType{NODE=0,
+ ROUTER,
+ UNKNOWN};
+
+ network_list.open(file_name.c_str());
+ if(!network_list.is_open()){
+ cout<<"Anynet:can't open network file "<<file_name<<endl;
+ exit(-1);
+ }
+
+ //loop through the entire file
+ while(!network_list.eof()){
+ getline(network_list,line);
+ if(line==""){
+ continue;
+ }
+
+ ParseState state=HEAD_TYPE;
+ //position to parse out white sspace
+ int pos = 0;
+ int next_pos=-1;
+ string temp;
+ //the first node and its type
+ int head_id = -1;
+ ParseType head_type = UNKNOWN;
+ //stuff that head are linked to
+ ParseType body_type = UNKNOWN;
+ int body_id = -1;
+ int link_weight = 1;
+
+ do{
+
+ //skip empty spaces
+ next_pos = line.find(" ",pos);
+ temp = line.substr(pos,next_pos-pos);
+ pos = next_pos+1;
+ if(temp=="" || temp==" "){
+ continue;
+ }
+
+ switch(state){
+ case HEAD_TYPE:
+ if(temp=="router"){
+ head_type = ROUTER;
+ } else if (temp == "node"){
+ head_type = NODE;
+ } else {
+ cout<<"Anynet:Unknow head of line type "<<temp<<"\n";
+ assert(false);
+ }
+ state=HEAD_ID;
+ break;
+ case HEAD_ID:
+ //need better error check
+ head_id = atoi(temp.c_str());
+
+ //intialize router structures
+ if(router_list[NODE].count(head_id) == 0){
+ router_list[NODE][head_id] = map<int, pair<int,int> >();
+ }
+ if(router_list[ROUTER].count(head_id) == 0){
+ router_list[ROUTER][head_id] = map<int, pair<int,int> >();
+ }
+
+ state=BODY_TYPE;
+ break;
+ case LINK_WEIGHT:
+ if(temp=="router"||
+ temp == "node"){
+ //ignore
+ } else {
+ link_weight= atoi(temp.c_str());
+ router_list[head_type][head_id][body_id].second=link_weight;
+ break;
+ }
+ //intentionally letting it flow through
+ case BODY_TYPE:
+ if(temp=="router"){
+ body_type = ROUTER;
+ } else if (temp == "node"){
+ body_type = NODE;
+ } else {
+ cout<<"Anynet:Unknow body type "<<temp<<"\n";
+ assert(false);
+ }
+ state=BODY_ID;
+ break;
+ case BODY_ID:
+ body_id = atoi(temp.c_str());
+ //intialize router structures if necessary
+ if(body_type==ROUTER){
+ if(router_list[NODE].count(body_id) ==0){
+ router_list[NODE][body_id] = map<int, pair<int,int> >();
+ }
+ if(router_list[ROUTER].count(body_id) == 0){
+ router_list[ROUTER][body_id] = map<int, pair<int,int> >();
+ }
+ }
+
+ if(head_type==NODE && body_type==NODE){
+
+ cout<<"Anynet:Cannot connect node to node "<<temp<<"\n";
+ assert(false);
+
+ } else if(head_type==NODE && body_type==ROUTER){
+
+ if(node_list.count(head_id)!=0 &&
+ node_list[head_id]!=body_id){
+ cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router "
+ <<body_id<<" and "<<node_list[head_id]<<endl;
+ assert(false);
+ }
+ node_list[head_id]=body_id;
+ router_list[NODE][body_id][head_id]=pair<int, int>(-1,1);
+
+ } else if(head_type==ROUTER && body_type==NODE){
+ //insert and check node
+ if(node_list.count(body_id) != 0 &&
+ node_list[body_id]!=head_id){
+ cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router "
+ <<body_id<<" and "<<node_list[head_id]<<endl;
+ assert(false);
+ }
+ node_list[body_id] = head_id;
+ router_list[NODE][head_id][body_id]=pair<int, int>(-1,1);
+
+ } else if(head_type==ROUTER && body_type==ROUTER){
+ router_list[ROUTER][head_id][body_id]=pair<int, int>(-1,1);
+ if(router_list[ROUTER][body_id].count(head_id)==0){
+ router_list[ROUTER][body_id][head_id]=pair<int, int>(-1,1);
+ }
+ }
+ state=LINK_WEIGHT;
+ break ;
+ default:
+ cout<<"Anynet:Unknow parse state\n";
+ assert(false);
+ break;
+ }
+
+ } while(pos!=0);
+ if(state!=LINK_WEIGHT &&
+ state!=BODY_TYPE){
+ cout<<"Anynet:Incomplete parse of the line: "<<line<<endl;
+ }
+
+ }
+
+ //map verification, make sure the information contained in bother maps
+ //are the same
+ assert(router_list[0].size() == router_list[1].size());
+
+ //traffic generator assumes node list is sequenctial and starts at 0
+ vector<int> node_check;
+ for(map<int,int>::iterator i = node_list.begin();
+ i!=node_list.end();
+ i++){
+ node_check.push_back(i->first);
+ }
+ sort(node_check.begin(), node_check.end());
+ for(size_t i = 0; i<node_check.size(); i++){
+ if(node_check[i] != i){
+ cout<<"Anynet:booksim trafficmanager assumes sequential node numbering starting at 0\n";
+ assert(false);
+ }
+ }
+
+}
+
diff --git a/src/intersim2/networks/anynet.hpp b/src/intersim2/networks/anynet.hpp
new file mode 100644
index 0000000..1cfe904
--- /dev/null
+++ b/src/intersim2/networks/anynet.hpp
@@ -0,0 +1,69 @@
+// $Id: anynet.hpp 5354 2012-11-07 23:51:49Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ANYNET_HPP_
+#define _ANYNET_HPP_
+
+#include "network.hpp"
+#include "routefunc.hpp"
+#include <cassert>
+#include <string>
+#include <map>
+#include <list>
+
+class AnyNet : public Network {
+
+ string file_name;
+ //associtation between nodes and routers
+ map<int, int > node_list;
+ //[link type][src router][dest router]=(port, latency)
+ vector<map<int, map<int, pair<int,int> > > > router_list;
+ //stores minimal routing information from every router to every node
+ //[router][dest_node]=port
+ vector<map<int, int> > routing_table;
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+ void readFile();
+ void buildRoutingTable();
+ void route(int r_start);
+
+public:
+ AnyNet( const Configuration &config, const string & name );
+ ~AnyNet();
+
+ int GetN( ) const{ return -1;}
+ int GetK( ) const{ return -1;}
+
+ static void RegisterRoutingFunctions();
+ double Capacity( ) const {return -1;}
+ void InsertRandomFaults( const Configuration &config ){}
+};
+
+void min_anynet( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+#endif
diff --git a/src/intersim2/networks/cmesh.cpp b/src/intersim2/networks/cmesh.cpp
new file mode 100644
index 0000000..06580d3
--- /dev/null
+++ b/src/intersim2/networks/cmesh.cpp
@@ -0,0 +1,856 @@
+// $Id: cmesh.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// ----------------------------------------------------------------------
+//
+// CMesh: Network with <Int> Terminal Nodes arranged in a concentrated
+// mesh topology
+//
+// ----------------------------------------------------------------------
+
+// ----------------------------------------------------------------------
+// $Author: jbalfour $
+// $Date: 2007/06/28 17:24:35 $
+// $Id: cmesh.cpp 5188 2012-08-30 00:31:31Z dub $
+// Modified 11/6/2007 by Ted Jiang
+// Now handeling n = most power of 2: 16, 64, 256, 1024
+// ----------------------------------------------------------------------
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include <cassert>
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+#include "cmesh.hpp"
+
+int CMesh::_cX = 0 ;
+int CMesh::_cY = 0 ;
+int CMesh::_memo_NodeShiftX = 0 ;
+int CMesh::_memo_NodeShiftY = 0 ;
+int CMesh::_memo_PortShiftY = 0 ;
+
+CMesh::CMesh( const Configuration& config, const string & name )
+ : Network(config, name)
+{
+ _ComputeSize( config );
+ _Alloc();
+ _BuildNet(config);
+}
+
+void CMesh::RegisterRoutingFunctions() {
+ gRoutingFunctionMap["dor_cmesh"] = &dor_cmesh;
+ gRoutingFunctionMap["dor_no_express_cmesh"] = &dor_no_express_cmesh;
+ gRoutingFunctionMap["xy_yx_cmesh"] = &xy_yx_cmesh;
+ gRoutingFunctionMap["xy_yx_no_express_cmesh"] = &xy_yx_no_express_cmesh;
+}
+
+void CMesh::_ComputeSize( const Configuration &config ) {
+
+ int k = config.GetInt( "k" );
+ int n = config.GetInt( "n" );
+ assert(n <= 2); // broken for n > 2
+ int c = config.GetInt( "c" );
+ assert(c == 4); // broken for c != 4
+
+ ostringstream router_name;
+ //how many routers in the x or y direction
+ _xcount = config.GetInt("x");
+ _ycount = config.GetInt("y");
+ assert(_xcount == _ycount); // broken for asymmetric topologies
+ //configuration of hohw many clients in X and Y per router
+ _xrouter = config.GetInt("xr");
+ _yrouter = config.GetInt("yr");
+ assert(_xrouter == _yrouter); // broken for asymmetric concentration
+
+ gK = _k = k ;
+ gN = _n = n ;
+ gC = _c = c ;
+
+ assert(c == _xrouter*_yrouter);
+
+ _nodes = _c * powi( _k, _n); // Number of nodes in network
+ _size = powi( _k, _n); // Number of routers in network
+ _channels = 2 * _n * _size; // Number of channels in network
+
+ _cX = _c / _n ; // Concentration in X Dimension
+ _cY = _c / _cX ; // Concentration in Y Dimension
+
+ //
+ _memo_NodeShiftX = _cX >> 1 ;
+ _memo_NodeShiftY = log_two(gK * _cX) + ( _cY >> 1 ) ;
+ _memo_PortShiftY = log_two(gK * _cX) ;
+
+}
+
+void CMesh::_BuildNet( const Configuration& config ) {
+
+ int x_index ;
+ int y_index ;
+
+ //standard trace configuration
+ if(gTrace){
+ cout<<"Setup Finished Router"<<endl;
+ }
+
+ //latency type, noc or conventional network
+ bool use_noc_latency;
+ use_noc_latency = (config.GetInt("use_noc_latency")==1);
+
+ ostringstream name;
+ // The following vector is used to check that every
+ // processor in the system is connected to the network
+ vector<bool> channel_vector(_nodes, false) ;
+
+ //
+ // Routers and Channel
+ //
+ for (int node = 0; node < _size; ++node) {
+
+ // Router index derived from mesh index
+ y_index = node / _k ;
+ x_index = node % _k ;
+
+ const int degree_in = 2 *_n + _c ;
+ const int degree_out = 2 *_n + _c ;
+
+ name << "router_" << y_index << '_' << x_index;
+ _routers[node] = Router::NewRouter( config,
+ this,
+ name.str(),
+ node,
+ degree_in,
+ degree_out);
+ _timed_modules.push_back(_routers[node]);
+ name.str("");
+
+ //
+ // Port Numbering: as best as I can determine, the order in
+ // which the input and output channels are added to the
+ // router determines the associated port number that must be
+ // used by the router. Output port number increases with
+ // each new channel
+ //
+
+ //
+ // Processing node channels
+ //
+ for (int y = 0; y < _cY ; y++) {
+ for (int x = 0; x < _cX ; x++) {
+ int link = (_k * _cX) * (_cY * y_index + y) + (_cX * x_index + x) ;
+ assert( link >= 0 ) ;
+ assert( link < _nodes ) ;
+ assert( channel_vector[ link ] == false ) ;
+ channel_vector[link] = true ;
+ // Ingress Ports
+ _routers[node]->AddInputChannel(_inject[link], _inject_cred[link]);
+ // Egress Ports
+ _routers[node]->AddOutputChannel(_eject[link], _eject_cred[link]);
+ //injeciton ejection latency is 1
+ _inject[link]->SetLatency( 1 );
+ _eject[link]->SetLatency( 1 );
+ }
+ }
+
+ //
+ // router to router channels
+ //
+ const int x = node % _k ;
+ const int y = node / _k ;
+ const int offset = powi( _k, _n ) ;
+
+ //the channel number of the input output channels.
+ int px_out = _k * y + x + 0 * offset ;
+ int nx_out = _k * y + x + 1 * offset ;
+ int py_out = _k * y + x + 2 * offset ;
+ int ny_out = _k * y + x + 3 * offset ;
+ int px_in = _k * y + ((x+1)) + 1 * offset ;
+ int nx_in = _k * y + ((x-1)) + 0 * offset ;
+ int py_in = _k * ((y+1)) + x + 3 * offset ;
+ int ny_in = _k * ((y-1)) + x + 2 * offset ;
+
+ // Express Channels
+ if (x == 0){
+ // Router on left edge of mesh. Connect to -x output of
+ // another router on the left edge of the mesh.
+ if (y < _k / 2 )
+ nx_in = _k * (y + _k/2) + x + offset ;
+ else
+ nx_in = _k * (y - _k/2) + x + offset ;
+ }
+
+ if (x == (_k-1)){
+ // Router on right edge of mesh. Connect to +x output of
+ // another router on the right edge of the mesh.
+ if (y < _k / 2)
+ px_in = _k * (y + _k/2) + x ;
+ else
+ px_in = _k * (y - _k/2) + x ;
+ }
+
+ if (y == 0) {
+ // Router on bottom edge of mesh. Connect to -y output of
+ // another router on the bottom edge of the mesh.
+ if (x < _k / 2)
+ ny_in = _k * y + (x + _k/2) + 3 * offset ;
+ else
+ ny_in = _k * y + (x - _k/2) + 3 * offset ;
+ }
+
+ if (y == (_k-1)) {
+ // Router on top edge of mesh. Connect to +y output of
+ // another router on the top edge of the mesh
+ if (x < _k / 2)
+ py_in = _k * y + (x + _k/2) + 2 * offset ;
+ else
+ py_in = _k * y + (x - _k/2) + 2 * offset ;
+ }
+
+ /*set latency and add the channels*/
+
+ // Port 0: +x channel
+ if(use_noc_latency) {
+ int const px_latency = (x == _k-1) ? (_cY*_k/2) : _cX;
+ _chan[px_out]->SetLatency( px_latency );
+ _chan_cred[px_out]->SetLatency( px_latency );
+ } else {
+ _chan[px_out]->SetLatency( 1 );
+ _chan_cred[px_out]->SetLatency( 1 );
+ }
+ _routers[node]->AddOutputChannel( _chan[px_out], _chan_cred[px_out] );
+ _routers[node]->AddInputChannel( _chan[px_in], _chan_cred[px_in] );
+
+ if(gTrace) {
+ cout<<"Link "<<" "<<px_out<<" "<<px_in<<" "<<node<<" "<<_chan[px_out]->GetLatency()<<endl;
+ }
+
+ // Port 1: -x channel
+ if(use_noc_latency) {
+ int const nx_latency = (x == 0) ? (_cY*_k/2) : _cX;
+ _chan[nx_out]->SetLatency( nx_latency );
+ _chan_cred[nx_out]->SetLatency( nx_latency );
+ } else {
+ _chan[nx_out]->SetLatency( 1 );
+ _chan_cred[nx_out]->SetLatency( 1 );
+ }
+ _routers[node]->AddOutputChannel( _chan[nx_out], _chan_cred[nx_out] );
+ _routers[node]->AddInputChannel( _chan[nx_in], _chan_cred[nx_in] );
+
+ if(gTrace){
+ cout<<"Link "<<" "<<nx_out<<" "<<nx_in<<" "<<node<<" "<<_chan[nx_out]->GetLatency()<<endl;
+ }
+
+ // Port 2: +y channel
+ if(use_noc_latency) {
+ int const py_latency = (y == _k-1) ? (_cX*_k/2) : _cY;
+ _chan[py_out]->SetLatency( py_latency );
+ _chan_cred[py_out]->SetLatency( py_latency );
+ } else {
+ _chan[py_out]->SetLatency( 1 );
+ _chan_cred[py_out]->SetLatency( 1 );
+ }
+ _routers[node]->AddOutputChannel( _chan[py_out], _chan_cred[py_out] );
+ _routers[node]->AddInputChannel( _chan[py_in], _chan_cred[py_in] );
+
+ if(gTrace){
+ cout<<"Link "<<" "<<py_out<<" "<<py_in<<" "<<node<<" "<<_chan[py_out]->GetLatency()<<endl;
+ }
+
+ // Port 3: -y channel
+ if(use_noc_latency){
+ int const ny_latency = (y == 0) ? (_cX*_k/2) : _cY;
+ _chan[ny_out]->SetLatency( ny_latency );
+ _chan_cred[ny_out]->SetLatency( ny_latency );
+ } else {
+ _chan[ny_out]->SetLatency( 1 );
+ _chan_cred[ny_out]->SetLatency( 1 );
+ }
+ _routers[node]->AddOutputChannel( _chan[ny_out], _chan_cred[ny_out] );
+ _routers[node]->AddInputChannel( _chan[ny_in], _chan_cred[ny_in] );
+
+ if(gTrace){
+ cout<<"Link "<<" "<<ny_out<<" "<<ny_in<<" "<<node<<" "<<_chan[ny_out]->GetLatency()<<endl;
+ }
+
+ }
+
+ // Check that all processors were connected to the network
+ for ( int i = 0 ; i < _nodes ; i++ )
+ assert( channel_vector[i] == true ) ;
+
+ if(gTrace){
+ cout<<"Setup Finished Link"<<endl;
+ }
+}
+
+
+// ----------------------------------------------------------------------
+//
+// Routing Helper Functions
+//
+// ----------------------------------------------------------------------
+
+int CMesh::NodeToRouter( int address ) {
+
+ int y = (address / (_cX*gK))/_cY ;
+ int x = (address % (_cX*gK))/_cY ;
+ int router = y*gK + x ;
+
+ return router ;
+}
+
+int CMesh::NodeToPort( int address ) {
+
+ const int maskX = _cX - 1 ;
+ const int maskY = _cY - 1 ;
+
+ int x = address & maskX ;
+ int y = (int)(address/(2*gK)) & maskY ;
+
+ return (gC / 2) * y + x;
+}
+
+// ----------------------------------------------------------------------
+//
+// Routing Functions
+//
+// ----------------------------------------------------------------------
+
+// Concentrated Mesh: X-Y
+int cmesh_xy( int cur, int dest ) {
+
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ int cur_y = cur / gK;
+ int cur_x = cur % gK;
+ int dest_y = dest / gK;
+ int dest_x = dest % gK;
+
+ // Dimension-order Routing: x , y
+ if (cur_x < dest_x) {
+ // Express?
+ if ((dest_x - cur_x) > 1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ // Express ?
+ if ((cur_x - dest_x) > 1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + NEGATIVE_X ;
+ }
+ if (cur_y < dest_y) {
+ // Express?
+ if ((dest_y - cur_y) > 1) {
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ // Express ?
+ if ((cur_y - dest_y) > 1 ){
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + NEGATIVE_Y ;
+ }
+ return 0;
+}
+
+// Concentrated Mesh: Y-X
+int cmesh_yx( int cur, int dest ) {
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ int cur_y = cur / gK ;
+ int cur_x = cur % gK ;
+ int dest_y = dest / gK ;
+ int dest_x = dest % gK ;
+
+ // Dimension-order Routing: y, x
+ if (cur_y < dest_y) {
+ // Express?
+ if ((dest_y - cur_y) > 1) {
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ // Express ?
+ if ((cur_y - dest_y) > 1 ){
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + NEGATIVE_Y ;
+ }
+ if (cur_x < dest_x) {
+ // Express?
+ if ((dest_x - cur_x) > 1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ // Express ?
+ if ((cur_x - dest_x) > 1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + NEGATIVE_X ;
+ }
+ return 0;
+}
+
+void xy_yx_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ // Current Router
+ int cur_router = r->GetID();
+
+ // Destination Router
+ int dest_router = CMesh::NodeToRouter( f->dest ) ;
+
+ if (dest_router == cur_router) {
+
+ // Forward to processing element
+ out_port = CMesh::NodeToPort( f->dest );
+
+ } else {
+
+ // Forward to neighbouring router
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ // randomly select dimension order at first hop
+ bool x_then_y = ((in_channel < gC) ?
+ (RandomInt(1) > 0) :
+ (f->vc < (vcBegin + available_vcs)));
+
+ if(x_then_y) {
+ out_port = cmesh_xy( cur_router, dest_router );
+ vcEnd -= available_vcs;
+ } else {
+ out_port = cmesh_yx( cur_router, dest_router );
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+// ----------------------------------------------------------------------
+//
+// Concentrated Mesh: Random XY-YX w/o Express Links
+//
+// <int> cur: current router address
+/// <int> dest: destination router address
+//
+// ----------------------------------------------------------------------
+
+int cmesh_xy_no_express( int cur, int dest ) {
+
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ const int cur_y = cur / gK ;
+ const int cur_x = cur % gK ;
+ const int dest_y = dest / gK ;
+ const int dest_x = dest % gK ;
+
+
+ // Note: channel numbers bellow gC (degree of concentration) are
+ // injection and ejection links
+
+ // Dimension-order Routing: X , Y
+ if (cur_x < dest_x) {
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ return gC + NEGATIVE_X ;
+ }
+ if (cur_y < dest_y) {
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ return gC + NEGATIVE_Y ;
+ }
+ return 0;
+}
+
+int cmesh_yx_no_express( int cur, int dest ) {
+
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ const int cur_y = cur / gK ;
+ const int cur_x = cur % gK ;
+ const int dest_y = dest / gK ;
+ const int dest_x = dest % gK ;
+
+ // Note: channel numbers bellow gC (degree of concentration) are
+ // injection and ejection links
+
+ // Dimension-order Routing: X , Y
+ if (cur_y < dest_y) {
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ return gC + NEGATIVE_Y ;
+ }
+ if (cur_x < dest_x) {
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ return gC + NEGATIVE_X ;
+ }
+ return 0;
+}
+
+void xy_yx_no_express_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ // Current Router
+ int cur_router = r->GetID();
+
+ // Destination Router
+ int dest_router = CMesh::NodeToRouter( f->dest );
+
+ if (dest_router == cur_router) {
+
+ // Forward to processing element
+ out_port = CMesh::NodeToPort( f->dest );
+
+ } else {
+
+ // Forward to neighbouring router
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ // randomly select dimension order at first hop
+ bool x_then_y = ((in_channel < gC) ?
+ (RandomInt(1) > 0) :
+ (f->vc < (vcBegin + available_vcs)));
+
+ if(x_then_y) {
+ out_port = cmesh_xy_no_express( cur_router, dest_router );
+ vcEnd -= available_vcs;
+ } else {
+ out_port = cmesh_yx_no_express( cur_router, dest_router );
+ vcBegin += available_vcs;
+ }
+ }
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+//============================================================
+//
+//=====
+int cmesh_next( int cur, int dest ) {
+
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ int cur_y = cur / gK ;
+ int cur_x = cur % gK ;
+ int dest_y = dest / gK ;
+ int dest_x = dest % gK ;
+
+ // Dimension-order Routing: x , y
+ if (cur_x < dest_x) {
+ // Express?
+ if ((dest_x - cur_x) > gK/2-1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ // Express ?
+ if ((cur_x - dest_x) > gK/2-1){
+ if (cur_y == 0)
+ return gC + NEGATIVE_Y ;
+ if (cur_y == (gK-1))
+ return gC + POSITIVE_Y ;
+ }
+ return gC + NEGATIVE_X ;
+ }
+ if (cur_y < dest_y) {
+ // Express?
+ if ((dest_y - cur_y) > gK/2-1) {
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ // Express ?
+ if ((cur_y - dest_y) > gK/2-1){
+ if (cur_x == 0)
+ return gC + NEGATIVE_X ;
+ if (cur_x == (gK-1))
+ return gC + POSITIVE_X ;
+ }
+ return gC + NEGATIVE_Y ;
+ }
+
+ assert(false);
+ return -1;
+}
+
+void dor_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ // Current Router
+ int cur_router = r->GetID();
+
+ // Destination Router
+ int dest_router = CMesh::NodeToRouter( f->dest ) ;
+
+ if (dest_router == cur_router) {
+
+ // Forward to processing element
+ out_port = CMesh::NodeToPort( f->dest ) ;
+
+ } else {
+
+ // Forward to neighbouring router
+ out_port = cmesh_next( cur_router, dest_router );
+ }
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port, vcBegin, vcEnd);
+}
+
+//============================================================
+//
+//=====
+int cmesh_next_no_express( int cur, int dest ) {
+
+ const int POSITIVE_X = 0 ;
+ const int NEGATIVE_X = 1 ;
+ const int POSITIVE_Y = 2 ;
+ const int NEGATIVE_Y = 3 ;
+
+ //magic constant 2, which is supose to be _cX and _cY
+ int cur_y = cur/gK ;
+ int cur_x = cur%gK ;
+ int dest_y = dest/gK;
+ int dest_x = dest%gK ;
+
+ // Dimension-order Routing: x , y
+ if (cur_x < dest_x) {
+ return gC + POSITIVE_X ;
+ }
+ if (cur_x > dest_x) {
+ return gC + NEGATIVE_X ;
+ }
+ if (cur_y < dest_y) {
+ return gC + POSITIVE_Y ;
+ }
+ if (cur_y > dest_y) {
+ return gC + NEGATIVE_Y ;
+ }
+ assert(false);
+ return -1;
+}
+
+void dor_no_express_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ // Current Router
+ int cur_router = r->GetID();
+
+ // Destination Router
+ int dest_router = CMesh::NodeToRouter( f->dest ) ;
+
+ if (dest_router == cur_router) {
+
+ // Forward to processing element
+ out_port = CMesh::NodeToPort( f->dest );
+
+ } else {
+
+ // Forward to neighbouring router
+ out_port = cmesh_next_no_express( cur_router, dest_router );
+ }
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
diff --git a/src/intersim2/networks/cmesh.hpp b/src/intersim2/networks/cmesh.hpp
new file mode 100644
index 0000000..1ee55a6
--- /dev/null
+++ b/src/intersim2/networks/cmesh.hpp
@@ -0,0 +1,95 @@
+// $Id: cmesh.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// CMesh: Mesh topology with concentration and express links along the
+// edge of the network
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/06/26 22:49:23 $
+// $Id: cmesh.hpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+#ifndef _CMESH_HPP_
+#define _CMESH_HPP_
+
+#include "network.hpp"
+#include "routefunc.hpp"
+
+class CMesh : public Network {
+public:
+ CMesh( const Configuration &config, const string & name );
+ int GetN() const;
+ int GetK() const;
+
+ static int NodeToRouter( int address ) ;
+ static int NodeToPort( int address ) ;
+
+ static void RegisterRoutingFunctions() ;
+
+private:
+
+ static int _cX ;
+ static int _cY ;
+
+ static int _memo_NodeShiftX ;
+ static int _memo_NodeShiftY ;
+ static int _memo_PortShiftY ;
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration& config );
+
+ int _k ;
+ int _n ;
+ int _c ;
+ int _xcount;
+ int _ycount;
+ int _xrouter;
+ int _yrouter;
+ bool _express_channels;
+};
+
+//
+// Routing Functions
+//
+void xy_yx_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ) ;
+
+void xy_yx_no_express_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ) ;
+
+void dor_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ) ;
+
+void dor_no_express_cmesh( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ) ;
+
+#endif
diff --git a/src/intersim2/networks/dragonfly.cpp b/src/intersim2/networks/dragonfly.cpp
new file mode 100644
index 0000000..b539cc6
--- /dev/null
+++ b/src/intersim2/networks/dragonfly.cpp
@@ -0,0 +1,575 @@
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this list
+ of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+ Neither the name of the Stanford University nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+
+#include "dragonfly.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+#include "globals.hpp"
+
+#define DRAGON_LATENCY
+
+int gP, gA, gG;
+
+//calculate the hop count between src and estination
+int dragonflynew_hopcnt(int src, int dest)
+{
+ int hopcnt;
+ int dest_grp_ID, src_grp_ID;
+ int src_hopcnt, dest_hopcnt;
+ int src_intm, dest_intm;
+ int grp_output, dest_grp_output;
+ int grp_output_RID;
+
+ int _grp_num_routers= gA;
+ int _grp_num_nodes =_grp_num_routers*gP;
+
+ dest_grp_ID = int(dest/_grp_num_nodes);
+ src_grp_ID = int(src / _grp_num_nodes);
+
+ //source and dest are in the same group, either 0-1 hop
+ if (dest_grp_ID == src_grp_ID) {
+ if ((int)(dest / gP) == (int)(src /gP))
+ hopcnt = 0;
+ else
+ hopcnt = 1;
+
+ } else {
+ //source and dest are in the same group
+ //find the number of hops in the source group
+ //find the number of hops in the dest group
+ if (src_grp_ID > dest_grp_ID) {
+ grp_output = dest_grp_ID;
+ dest_grp_output = src_grp_ID - 1;
+ }
+ else {
+ grp_output = dest_grp_ID - 1;
+ dest_grp_output = src_grp_ID;
+ }
+ grp_output_RID = ((int) (grp_output / (gP))) + src_grp_ID * _grp_num_routers;
+ src_intm = grp_output_RID * gP;
+
+ grp_output_RID = ((int) (dest_grp_output / (gP))) + dest_grp_ID * _grp_num_routers;
+ dest_intm = grp_output_RID * gP;
+
+ //hop count in source group
+ if ((int)( src_intm / gP) == (int)( src / gP ) )
+ src_hopcnt = 0;
+ else
+ src_hopcnt = 1;
+
+ //hop count in destination group
+ if ((int)( dest_intm / gP) == (int)( dest / gP ) ){
+ dest_hopcnt = 0;
+ }else{
+ dest_hopcnt = 1;
+ }
+
+ //tally
+ hopcnt = src_hopcnt + 1 + dest_hopcnt;
+ }
+
+ return hopcnt;
+}
+
+
+//packet output port based on the source, destination and current location
+int dragonfly_port(int rID, int source, int dest){
+ int _grp_num_routers= gA;
+ int _grp_num_nodes =_grp_num_routers*gP;
+
+ int out_port = -1;
+ int grp_ID = int(rID / _grp_num_routers);
+ int dest_grp_ID = int(dest/_grp_num_nodes);
+ int grp_output=-1;
+ int grp_RID=-1;
+ int group_dest=-1;
+
+ //which router within this group the packet needs to go to
+ if (dest_grp_ID == grp_ID) {
+ grp_RID = int(dest / gP);
+ } else {
+ if (grp_ID > dest_grp_ID) {
+ grp_output = dest_grp_ID;
+ } else {
+ grp_output = dest_grp_ID - 1;
+ }
+ grp_RID = int(grp_output /gP) + grp_ID * _grp_num_routers;
+ group_dest = grp_RID * gP;
+ }
+
+ //At the last hop
+ if (dest >= rID*gP && dest < (rID+1)*gP) {
+ out_port = dest%gP;
+ } else if (grp_RID == rID) {
+ //At the optical link
+ out_port = gP + (gA-1) + grp_output %(gP);
+ } else {
+ //need to route within a group
+ assert(grp_RID!=-1);
+
+ if (rID < grp_RID){
+ out_port = (grp_RID % _grp_num_routers) - 1 + gP;
+ }else{
+ out_port = (grp_RID % _grp_num_routers) + gP;
+ }
+ }
+
+ assert(out_port!=-1);
+ return out_port;
+}
+
+
+DragonFlyNew::DragonFlyNew( const Configuration &config, const string & name ) :
+ Network( config, name )
+{
+
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void DragonFlyNew::_ComputeSize( const Configuration &config )
+{
+
+ // LIMITATION
+ // -- only one dimension between the group
+ // _n == # of dimensions within a group
+ // _p == # of processors within a router
+ // inter-group ports : _p
+ // terminal ports : _p
+ // intra-group ports : 2*_p - 1
+ _p = config.GetInt( "k" ); // # of ports in each switch
+ _n = config.GetInt( "n" );
+
+
+ assert(_n==1);
+ // dimension
+
+ if (_n == 1)
+ _k = _p + _p + 2*_p - 1;
+ else
+ _k = _p + _p + 2*_p;
+
+
+ // FIX...
+ gK = _p; gN = _n;
+
+ // with 1 dimension, total of 2p routers per group
+ // N = 2p * p * (2p^2 + 1)
+ // a = # of routers per group
+ // = 2p (if n = 1)
+ // = p^(n) (if n > 2)
+ // g = # of groups
+ // = a * p + 1
+ // N = a * p * g;
+
+ if (_n == 1)
+ _a = 2 * _p;
+ else
+ _a = powi(_p, _n);
+
+ _g = _a * _p + 1;
+ _nodes = _a * _p * _g;
+
+ _num_of_switch = _nodes / _p;
+ _channels = _num_of_switch * (_k - _p);
+ _size = _num_of_switch;
+
+
+
+ gG = _g;
+ gP = _p;
+ gA = _a;
+ _grp_num_routers = gA;
+ _grp_num_nodes =_grp_num_routers*gP;
+
+}
+
+void DragonFlyNew::_BuildNet( const Configuration &config )
+{
+
+ int _output;
+ int _input;
+ int c;
+ int _dim_ID;
+ int _num_ports_per_switch;
+ int _dim_size;
+
+ ostringstream router_name;
+
+
+
+ cout << " Dragonfly " << endl;
+ cout << " p = " << _p << " n = " << _n << endl;
+ cout << " each switch - total radix = "<< _k << endl;
+ cout << " # of switches = "<< _num_of_switch << endl;
+ cout << " # of channels = "<< _channels << endl;
+ cout << " # of nodes ( size of network ) = " << _nodes << endl;
+ cout << " # of groups (_g) = " << _g << endl;
+ cout << " # of routers per group (_a) = " << _a << endl;
+
+ for ( int node = 0; node < _num_of_switch; ++node ) {
+ // ID of the group
+ int grp_ID;
+ grp_ID = (int) (node/_a);
+ router_name << "router";
+
+ router_name << "_" << node ;
+
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, _k, _k );
+ _timed_modules.push_back(_routers[node]);
+
+ router_name.str("");
+
+ for ( int cnt = 0; cnt < _p; ++cnt ) {
+ c = _p * node + cnt;
+ _routers[node]->AddInputChannel( _inject[c], _inject_cred[c] );
+
+ }
+
+ for ( int cnt = 0; cnt < _p; ++cnt ) {
+ c = _p * node + cnt;
+ _routers[node]->AddOutputChannel( _eject[c], _eject_cred[c] );
+
+ }
+
+ // add OUPUT channels
+ // _k == # of processor per router
+ // need 2*_k routers --thus,
+ // 2_k-1 outputs channels within group
+ // _k-1 outputs for intra-group
+
+ //
+
+ if (_n > 1 ) { cout << " ERROR: n>1 dimension NOT supported yet... " << endl; exit(-1); }
+
+ //********************************************
+ // connect OUTPUT channels
+ //********************************************
+ // add intra-group output channel
+ for ( int dim = 0; dim < _n; ++dim ) {
+ for ( int cnt = 0; cnt < (2*_p -1); ++cnt ) {
+ _output = (2*_p-1 + _p) * _n * node + (2*_p-1) * dim + cnt;
+
+ _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] );
+
+#ifdef DRAGON_LATENCY
+ _chan[_output]->SetLatency(10);
+ _chan_cred[_output]->SetLatency(10);
+#endif
+ }
+ }
+
+ // add inter-group output channel
+
+ for ( int cnt = 0; cnt < _p; ++cnt ) {
+ _output = (2*_p-1 + _p) * node + (2*_p - 1) + cnt;
+
+ // _chan[_output].global = true;
+ _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] );
+#ifdef DRAGON_LATENCY
+ _chan[_output]->SetLatency(100);
+ _chan_cred[_output]->SetLatency(100);
+#endif
+ }
+
+
+ //********************************************
+ // connect INPUT channels
+ //********************************************
+ // # of non-local nodes
+ _num_ports_per_switch = (_k - _p);
+
+
+ // intra-group GROUP channels
+ for ( int dim = 0; dim < _n; ++dim ) {
+
+ _dim_size = powi(_k,dim);
+
+ _dim_ID = ((int) (node / ( powi(_p, dim))));
+
+
+
+ // NODE ID withing group
+ _dim_ID = node % _a;
+
+
+
+
+ for ( int cnt = 0; cnt < (2*_p-1); ++cnt ) {
+
+ if ( cnt < _dim_ID) {
+
+ _input = grp_ID * _num_ports_per_switch * _a -
+ (_dim_ID - cnt) * _num_ports_per_switch +
+ _dim_ID * _num_ports_per_switch +
+ (_dim_ID - 1);
+ }
+ else {
+
+ _input = grp_ID * _num_ports_per_switch * _a +
+ _dim_ID * _num_ports_per_switch +
+ (cnt - _dim_ID + 1) * _num_ports_per_switch +
+ _dim_ID;
+
+ }
+
+ if (_input < 0) {
+ cout << " ERROR: _input less than zero " << endl;
+ exit(-1);
+ }
+
+
+ _routers[node]->AddInputChannel( _chan[_input], _chan_cred[_input] );
+ }
+ }
+
+
+ // add INPUT channels -- "optical" channels connecting the groups
+ int _grp_num_routers;
+ int grp_output;
+ int grp_ID2;
+
+ for ( int cnt = 0; cnt < _p; ++cnt ) {
+ // _dim_ID
+ grp_output = _dim_ID* _p + cnt;
+
+ _grp_num_routers = powi(_k, _n-1);
+ grp_ID2 = (int) ((grp_ID - 1) / (_k - 1));
+
+ if ( grp_ID > grp_output) {
+
+ _input = (grp_output) * _num_ports_per_switch * _a + // starting point of group
+ (_num_ports_per_switch - _p) * (int) ((grp_ID - 1) / _p) + // find the correct router within grp
+ (_num_ports_per_switch - _p) + // add offset within router
+ grp_ID - 1;
+ } else {
+
+ _input = (grp_output + 1) * _num_ports_per_switch * _a +
+ (_num_ports_per_switch - _p) * (int) ((grp_ID) / _p) + // find the correct router within grp
+ (_num_ports_per_switch - _p) +
+ grp_ID;
+ }
+
+ _routers[node]->AddInputChannel( _chan[_input], _chan_cred[_input] );
+ }
+
+ }
+
+ cout<<"Done links"<<endl;
+}
+
+
+int DragonFlyNew::GetN( ) const
+{
+ return _n;
+}
+
+int DragonFlyNew::GetK( ) const
+{
+ return _k;
+}
+
+void DragonFlyNew::InsertRandomFaults( const Configuration &config )
+{
+
+}
+
+double DragonFlyNew::Capacity( ) const
+{
+ return (double)_k / 8.0;
+}
+
+void DragonFlyNew::RegisterRoutingFunctions(){
+
+ gRoutingFunctionMap["min_dragonflynew"] = &min_dragonflynew;
+ gRoutingFunctionMap["ugal_dragonflynew"] = &ugal_dragonflynew;
+}
+
+
+void min_dragonflynew( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+
+ if(inject) {
+ int inject_vc= RandomInt(gNumVCs-1);
+ outputs->AddRange(-1, inject_vc, inject_vc);
+ return;
+ }
+
+ int _grp_num_routers= gA;
+
+ int dest = f->dest;
+ int rID = r->GetID();
+
+ int grp_ID = int(rID / _grp_num_routers);
+ int debug = f->watch;
+ int out_port = -1;
+ int out_vc = 0;
+ int dest_grp_ID=-1;
+
+ if ( in_channel < gP ) {
+ out_vc = 0;
+ f->ph = 0;
+ if (dest_grp_ID == grp_ID) {
+ f->ph = 1;
+ }
+ }
+
+
+ out_port = dragonfly_port(rID, f->src, dest);
+
+ //optical dateline
+ if (out_port >=gP + (gA-1)) {
+ f->ph = 1;
+ }
+
+ out_vc = f->ph;
+ if (debug)
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << " through output port : " << out_port
+ << " out vc: " << out_vc << endl;
+ outputs->AddRange( out_port, out_vc, out_vc );
+}
+
+
+//Basic adaptive routign algorithm for the dragonfly
+void ugal_dragonflynew( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ //need 3 VCs for deadlock freedom
+
+ assert(gNumVCs==3);
+ outputs->Clear( );
+ if(inject) {
+ int inject_vc= RandomInt(gNumVCs-1);
+ outputs->AddRange(-1, inject_vc, inject_vc);
+ return;
+ }
+
+ //this constant biases the adaptive decision toward minimum routing
+ //negative value woudl biases it towards nonminimum routing
+ int adaptive_threshold = 30;
+
+ int _grp_num_routers= gA;
+ int _grp_num_nodes =_grp_num_routers*gP;
+ int _network_size = gA * gP * gG;
+
+
+ int dest = f->dest;
+ int rID = r->GetID();
+ int grp_ID = (int) (rID / _grp_num_routers);
+ int dest_grp_ID = int(dest/_grp_num_nodes);
+
+ int debug = f->watch;
+ int out_port = -1;
+ int out_vc = 0;
+ int min_queue_size, min_hopcnt;
+ int nonmin_queue_size, nonmin_hopcnt;
+ int intm_grp_ID;
+ int intm_rID;
+
+ if(debug){
+ cout<<"At router "<<rID<<endl;
+ }
+ int min_router_output, nonmin_router_output;
+
+ //at the source router, make the adaptive routing decision
+ if ( in_channel < gP ) {
+ //dest are in the same group, only use minimum routing
+ if (dest_grp_ID == grp_ID) {
+ f->ph = 2;
+ } else {
+ //select a random node
+ f->intm =RandomInt(_network_size - 1);
+ intm_grp_ID = (int)(f->intm/_grp_num_nodes);
+ if (debug){
+ cout<<"Intermediate node "<<f->intm<<" grp id "<<intm_grp_ID<<endl;
+ }
+
+ //random intermediate are in the same group, use minimum routing
+ if(grp_ID == intm_grp_ID){
+ f->ph = 1;
+ } else {
+ //congestion metrics using queue length, obtained by GetUsedCredit()
+ min_hopcnt = dragonflynew_hopcnt(f->src, f->dest);
+ min_router_output = dragonfly_port(rID, f->src, f->dest);
+ min_queue_size = max(r->GetUsedCredit(min_router_output), 0) ;
+
+
+ nonmin_hopcnt = dragonflynew_hopcnt(f->src, f->intm) +
+ dragonflynew_hopcnt(f->intm,f->dest);
+ nonmin_router_output = dragonfly_port(rID, f->src, f->intm);
+ nonmin_queue_size = max(r->GetUsedCredit(nonmin_router_output), 0);
+
+ //congestion comparison, could use hopcnt instead of 1 and 2
+ if ((1 * min_queue_size ) <= (2 * nonmin_queue_size)+adaptive_threshold ) {
+ if (debug) cout << " MINIMAL routing " << endl;
+ f->ph = 1;
+ } else {
+ f->ph = 0;
+ }
+ }
+ }
+ }
+
+ //transition from nonminimal phase to minimal
+ if(f->ph==0){
+ intm_rID= (int)(f->intm/gP);
+ if( rID == intm_rID){
+ f->ph = 1;
+ }
+ }
+
+ //port assignement based on the phase
+ if(f->ph == 0){
+ out_port = dragonfly_port(rID, f->src, f->intm);
+ } else if(f->ph == 1){
+ out_port = dragonfly_port(rID, f->src, f->dest);
+ } else if(f->ph == 2){
+ out_port = dragonfly_port(rID, f->src, f->dest);
+ } else {
+ assert(false);
+ }
+
+ //optical dateline
+ if (f->ph == 1 && out_port >=gP + (gA-1)) {
+ f->ph = 2;
+ }
+
+ //vc assignemnt based on phase
+ out_vc = f->ph;
+
+ outputs->AddRange( out_port, out_vc, out_vc );
+}
diff --git a/src/intersim2/networks/dragonfly.hpp b/src/intersim2/networks/dragonfly.hpp
new file mode 100644
index 0000000..02228ef
--- /dev/null
+++ b/src/intersim2/networks/dragonfly.hpp
@@ -0,0 +1,74 @@
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _DragonFly_HPP_
+#define _DragonFly_HPP_
+
+#include "network.hpp"
+#include "routefunc.hpp"
+
+class DragonFlyNew : public Network {
+
+ int _m;
+ int _n;
+ int _r;
+ int _k;
+ int _p, _a, _g;
+ int _radix;
+ int _net_size;
+ int _stageout;
+ int _numinput;
+ int _stages;
+ int _num_of_switch;
+ int _grp_num_routers;
+ int _grp_num_nodes;
+
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+
+
+
+public:
+ DragonFlyNew( const Configuration &config, const string & name );
+
+ int GetN( ) const;
+ int GetK( ) const;
+
+ double Capacity( ) const;
+ static void RegisterRoutingFunctions();
+ void InsertRandomFaults( const Configuration &config );
+
+};
+int dragonfly_port(int rID, int source, int dest);
+
+void ugal_dragonflynew( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void min_dragonflynew( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+
+#endif
diff --git a/src/intersim2/networks/fattree.cpp b/src/intersim2/networks/fattree.cpp
new file mode 100644
index 0000000..81cd2b1
--- /dev/null
+++ b/src/intersim2/networks/fattree.cpp
@@ -0,0 +1,270 @@
+// $Id: fattree.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// FatTree
+//
+// Each level of the hierarchical indirect Network has
+// k^(n-1) Routers. The Routers are organized such that
+// each node has k descendents, and each parent is
+// replicated k times.
+// most routers has 2K ports, excep the top level has only K
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/06/26 22:50:48 $
+// $Id: fattree.cpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include <cmath>
+
+#include "fattree.hpp"
+#include "misc_utils.hpp"
+
+
+ //#define FATTREE_DEBUG
+
+FatTree::FatTree( const Configuration& config,const string & name )
+ : Network( config ,name)
+{
+
+
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+
+}
+
+void FatTree::_ComputeSize( const Configuration& config )
+{
+
+ _k = config.GetInt( "k" );
+ _n = config.GetInt( "n" );
+
+ gK = _k; gN = _n;
+
+ _nodes = powi( _k, _n );
+
+ //levels * routers_per_level
+ _size = _n * powi( _k , _n - 1 );
+
+ //(channels per level = k*routers_per_level* up/down) * (levels-1)
+ _channels = (2*_k * powi( _k , _n-1 ))*(_n-1);
+
+
+}
+
+
+void FatTree::RegisterRoutingFunctions() {
+
+}
+
+void FatTree::_BuildNet( const Configuration& config )
+{
+ cout << "Fat Tree" << endl;
+ cout << " k = " << _k << " levels = " << _n << endl;
+ cout << " each switch - total radix = "<< 2*_k << endl;
+ cout << " # of switches = "<< _size << endl;
+ cout << " # of channels = "<< _channels << endl;
+ cout << " # of nodes ( size of network ) = " << _nodes << endl;
+
+
+ // Number of router positions at each depth of the network
+ const int nPos = powi( _k, _n-1);
+
+ //
+ // Allocate Routers
+ //
+ ostringstream name;
+ int level, pos, id, degree, port;
+ for ( level = 0 ; level < _n ; ++level ) {
+ for ( pos = 0 ; pos < nPos ; ++pos ) {
+
+ if ( level == 0 ) //top routers is zero
+ degree = _k;
+ else
+ degree = 2 * _k;
+
+ id = level * nPos + pos;
+
+ name.str("");
+ name << "router_level" << level << "_" << pos;
+ Router * r = Router::NewRouter( config, this, name.str( ), id,
+ degree, degree );
+ _Router( level, pos ) = r;
+ _timed_modules.push_back(r);
+ }
+ }
+
+ //
+ // Connect Channels to Routers
+ //
+
+ //
+ // Router Connection Rule: Output Ports <gK Move DOWN Network
+ // Output Ports >=gK Move UP Network
+ // Input Ports <gK from DOWN Network
+ // Input Ports >=gK from up Network
+
+ // Connecting Injection & Ejection Channels
+ for ( pos = 0 ; pos < nPos ; ++pos ) {
+ for(int index = 0; index<_k; index++){
+ int link = pos*_k + index;
+ _Router( _n-1, pos)->AddInputChannel( _inject[link],
+ _inject_cred[link]);
+ _Router( _n-1, pos)->AddOutputChannel( _eject[link],
+ _eject_cred[link]);
+ _inject[link]->SetLatency( 1 );
+ _inject_cred[link]->SetLatency( 1 );
+ _eject[link]->SetLatency( 1 );
+ _eject_cred[link]->SetLatency( 1 );
+ }
+ }
+
+#ifdef FATTREE_DEBUG
+ cout<<"\nAssigning output\n";
+#endif
+
+ //channels are numbered sequentially from an output channel perspective
+ int chan_per_direction = (_k * powi( _k , _n-1 )); //up or down
+ int chan_per_level = 2*(_k * powi( _k , _n-1 )); //up+down
+
+ //connect all down output channels
+ //level n-1's down channel are injection channels
+ for (level = 0; level<_n-1; level++){
+ for ( pos = 0; pos < nPos; ++pos ) {
+ for ( port = 0; port < _k; ++port ) {
+ int link = (level*chan_per_level) + pos*_k + port;
+ _Router(level, pos)->AddOutputChannel( _chan[link],
+ _chan_cred[link] );
+ _chan[link]->SetLatency( 1 );
+ _chan_cred[link]->SetLatency( 1 );
+#ifdef FATTREE_DEBUG
+ cout<<_Router(level, pos)->Name()<<" "
+ <<"down output "<<port<<" "
+ <<"channel_id "<<link<<endl;
+#endif
+
+ }
+ }
+ }
+ //connect all up output channels
+ //level 0 has no up chnanels
+ for (level = 1; level<_n; level++){
+ for ( pos = 0; pos < nPos; ++pos ) {
+ for ( port = 0; port < _k; ++port ) {
+ int link = (level*chan_per_level - chan_per_direction) + pos*_k + port ;
+ _Router(level, pos)->AddOutputChannel( _chan[link],
+ _chan_cred[link] );
+ _chan[link]->SetLatency( 1 );
+ _chan_cred[link]->SetLatency( 1 );
+#ifdef FATTREE_DEBUG
+ cout<<_Router(level, pos)->Name()<<" "
+ <<"up output "<<port<<" "
+ <<"channel_id "<<link<<endl;
+#endif
+ }
+ }
+ }
+
+#ifdef FATTREE_DEBUG
+ cout<<"\nAssigning Input\n";
+#endif
+
+ //connect all down input channels
+ for (level = 0; level<_n-1; level++){
+ //input channel are numbered interleavely, the interleaev depends on level
+ int routers_per_neighborhood = powi(_k,_n-1-(level));
+ int routers_per_branch = powi(_k,_n-1-(level+1));
+ int level_offset = routers_per_neighborhood*_k;
+ for ( pos = 0; pos < nPos; ++pos ) {
+ int neighborhood = pos/routers_per_neighborhood;
+ int neighborhood_pos = pos%routers_per_neighborhood;
+ for ( port = 0; port < _k; ++port ) {
+ int link =
+ ((level+1)*chan_per_level - chan_per_direction) //which levellevel
+ +neighborhood*level_offset //region in level
+ +port*routers_per_branch*gK //sub region in region
+ +(neighborhood_pos)%routers_per_branch*gK //router in subregion
+ +(neighborhood_pos)/routers_per_branch; //port on router
+
+ _Router(level, pos)->AddInputChannel( _chan[link],
+ _chan_cred[link] );
+#ifdef FATTREE_DEBUG
+ cout<<_Router(level, pos)->Name()<<" "
+ <<"down input "<<port<<" "
+ <<"channel_id "<<link<<endl;
+#endif
+ }
+ }
+ }
+
+
+ //connect all up input channels
+ for (level = 1; level<_n; level++){
+ //input channel are numbered interleavely, the interleaev depends on level
+ int routers_per_neighborhood = powi(_k,_n-1-(level-1));
+ int routers_per_branch = powi(_k,_n-1-(level));
+ int level_offset = routers_per_neighborhood*_k;
+ for ( pos = 0; pos < nPos; ++pos ) {
+ int neighborhood = pos/routers_per_neighborhood;
+ int neighborhood_pos = pos%routers_per_neighborhood;
+ for ( port = 0; port < _k; ++port ) {
+ int link =
+ ((level-1)*chan_per_level) //which levellevel
+ +neighborhood*level_offset //region in level
+ +port*routers_per_branch*gK //sub region in region
+ +(neighborhood_pos)%routers_per_branch*gK //router in subregion
+ +(neighborhood_pos)/routers_per_branch; //port on router
+
+ _Router(level, pos)->AddInputChannel( _chan[link],
+ _chan_cred[link] );
+#ifdef FATTREE_DEBUG
+ cout<<_Router(level, pos)->Name()<<" "
+ <<"up input "<<port<<" "
+ <<"channel_id "<<link<<endl;
+#endif
+ }
+ }
+ }
+#ifdef FATTREE_DEBUG
+ cout<<"\nChannel assigned\n";
+#endif
+}
+
+Router*& FatTree::_Router( int depth, int pos )
+{
+ assert( depth < _n && pos < powi( _k, _n-1) );
+ return _routers[depth * powi( _k, _n-1) + pos];
+}
diff --git a/src/intersim2/networks/fattree.hpp b/src/intersim2/networks/fattree.hpp
new file mode 100644
index 0000000..e537e5a
--- /dev/null
+++ b/src/intersim2/networks/fattree.hpp
@@ -0,0 +1,76 @@
+// $Id: fattree.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// FatTree
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/06/26 22:49:23 $
+// $Id: fattree.hpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifndef _FatTree_HPP_
+#define _FatTree_HPP_
+
+#include "network.hpp"
+
+class FatTree : public Network {
+
+ int _k;
+ int _n;
+
+
+ void _ComputeSize( const Configuration& config );
+ void _BuildNet( const Configuration& config );
+
+ Router*& _Router( int depth, int pos );
+
+ int _mapSize;
+ int* _inputChannelMap;
+ int* _outputChannelMap;
+ int* _latencyMap;
+
+
+
+public:
+
+ FatTree( const Configuration& config ,const string & name );
+ static void RegisterRoutingFunctions() ;
+
+ //
+ // Methods to Assit Routing Functions
+ //
+ static int PreferedPort( const Router* r, int index );
+
+};
+
+#endif
diff --git a/src/intersim2/networks/flatfly_onchip.cpp b/src/intersim2/networks/flatfly_onchip.cpp
new file mode 100644
index 0000000..fd17c1a
--- /dev/null
+++ b/src/intersim2/networks/flatfly_onchip.cpp
@@ -0,0 +1,1331 @@
+// $Id: flatfly_onchip.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//Flattened butterfly simulator
+//Created by John Kim
+//
+//Updated 11/6/2007 by Ted Jiang, now scales
+//with any n such that N = K^3, k is a power of 2
+//however, the change restrict it to a 2D FBfly
+//
+//updated sometimes in december by Ted Jiang, now works for updat to 4
+//dimension.
+//
+//Updated 2/4/08 by Ted Jiang disabling partial networks
+//change concentrations
+//
+//More update 3/31/08 to correctly assign the nodes to the routers
+//UGAL now has added a "mapping" to account for this new assignment
+//of the nodes to the routers
+//
+//Updated by mihelog 27 Aug to add progressive choice of intermediate destination.
+//Also, half of the total vcs are used for non-minimal routing, others for minimal (for UGAL and valiant).
+
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include <limits>
+#include <cmath>
+#include "flatfly_onchip.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+#include "globals.hpp"
+
+
+
+//#define DEBUG_FLATFLY
+
+static int _xcount;
+static int _ycount;
+static int _xrouter;
+static int _yrouter;
+
+FlatFlyOnChip::FlatFlyOnChip( const Configuration &config, const string & name ) :
+ Network( config, name )
+{
+
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void FlatFlyOnChip::_ComputeSize( const Configuration &config )
+{
+ _k = config.GetInt( "k" ); // # of routers per dimension
+ _n = config.GetInt( "n" ); // dimension
+ _c = config.GetInt( "c" ); //concentration, may be different from k
+ _r = _c + (_k-1)*_n ; // total radix of the switch ( # of inputs/outputs)
+
+ //how many routers in the x or y direction
+ _xcount = config.GetInt("x");
+ _ycount = config.GetInt("y");
+ assert(_xcount == _ycount);
+ //configuration of hohw many clients in X and Y per router
+ _xrouter = config.GetInt("xr");
+ _yrouter = config.GetInt("yr");
+ assert(_xrouter == _yrouter);
+ gK = _k;
+ gN = _n;
+ gC = _c;
+
+ assert(_c == _xrouter*_yrouter);
+
+ _nodes = powi( _k, _n )*_c; //network size
+
+ _num_of_switch = _nodes / _c;
+ _channels = _num_of_switch * (_r - _c);
+ _size = _num_of_switch;
+
+}
+
+void FlatFlyOnChip::_BuildNet( const Configuration &config )
+{
+ int _output;
+
+ ostringstream router_name;
+
+
+ if(gTrace){
+
+ cout<<"Setup Finished Router"<<endl;
+
+ }
+
+ //latency type, noc or conventional network
+ bool use_noc_latency;
+ use_noc_latency = (config.GetInt("use_noc_latency")==1);
+
+ cout << " Flat Bufferfly " << endl;
+ cout << " k = " << _k << " n = " << _n << " c = "<<_c<< endl;
+ cout << " each switch - total radix = "<< _r << endl;
+ cout << " # of switches = "<< _num_of_switch << endl;
+ cout << " # of channels = "<< _channels << endl;
+ cout << " # of nodes ( size of network ) = " << _nodes << endl;
+
+ for ( int node = 0; node < _num_of_switch; ++node ) {
+
+ router_name << "router";
+ router_name << "_" << node ;
+
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, _r, _r );
+ _timed_modules.push_back(_routers[node]);
+
+
+#ifdef DEBUG_FLATFLY
+ cout << " ======== router node : " << node << " ======== " << " router_" << router_name.str() << " router node # : " << node << endl;
+#endif
+
+ router_name.str("");
+
+ //******************************************************************
+ // add inject/eject channels connected to the processor nodes
+ //******************************************************************
+
+ //as accurately model the length of these channels as possible
+ int yleng = -_yrouter/2;
+ int xleng = -_xrouter/2;
+ bool yodd = _yrouter%2==1;
+ bool xodd = _xrouter%2==1;
+
+ int y_index = node/(_xcount);
+ int x_index = node%(_xcount);
+ //estimating distance from client to router
+ for (int y = 0; y < _yrouter ; y++) {
+ for (int x = 0; x < _xrouter ; x++) {
+ //Zero is a naughty number
+ if(yleng == 0 && !yodd){
+ yleng++;
+ }
+ if(xleng == 0 && !xodd){
+ xleng++;
+ }
+ int ileng = 1; //at least 1 away
+ //measure distance in the y direction
+ if(abs(yleng)>1){
+ ileng+=(abs(yleng)-1);
+ }
+ //measure distance in the x direction
+ if(abs(xleng)>1){
+ ileng+=(abs(xleng)-1);
+ }
+ //increment for the next client, add Y, if full, reset y add x
+ yleng++;
+ if(yleng>_yrouter/2){
+ yleng= -_yrouter/2;
+ xleng++;
+ }
+ //adopted from the CMESH, the first node has 0,1,8,9 (as an example)
+ int link = (_xcount * _xrouter) * (_yrouter * y_index + y) + (_xrouter * x_index + x) ;
+
+ if(use_noc_latency){
+ _inject[link]->SetLatency(ileng);
+ _inject_cred[link]->SetLatency(ileng);
+ _eject[link] ->SetLatency(ileng);
+ _eject_cred[link]->SetLatency(ileng);
+ } else {
+ _inject[link]->SetLatency(1);
+ _inject_cred[link]->SetLatency(1);
+ _eject[link] ->SetLatency(1);
+ _eject_cred[link]->SetLatency(1);
+ }
+ _routers[node]->AddInputChannel( _inject[link], _inject_cred[link] );
+
+#ifdef DEBUG_FLATFLY
+ cout << " Adding injection channel " << link << endl;
+#endif
+
+ _routers[node]->AddOutputChannel( _eject[link], _eject_cred[link] );
+#ifdef DEBUG_FLATFLY
+ cout << " Adding ejection channel " << link << endl;
+#endif
+ }
+ }
+ }
+ //******************************************************************
+ // add output inter-router channels
+ //******************************************************************
+
+ //for every router, in every dimension
+ for ( int node = 0; node < _num_of_switch; ++node ) {
+ for ( int dim = 0; dim < _n; ++dim ) {
+
+ //locate itself in every dimension
+ int xcurr = node%_k;
+ int ycurr = (int)(node/_k);
+ int curr3 = node%(_k*_k);
+ int curr4 = (int)(node/(_k*_k));
+ int curr5 = (int)(node/(_k*_k*_k));//mmm didn't mean to be racist
+ int curr6 = (node%(_k*_k*_k));//mmm didn't mean to be racist
+
+ //for every other router in the dimension
+ for ( int cnt = 0; cnt < (_k ); ++cnt ) {
+ int other=0; //the other router that we are trying to connect
+ int offset = 0; //silly ness when node< other or when node>other
+ //if xdimension
+ if(dim == 0){
+ other = ycurr * _k +cnt;
+ } else if (dim ==1){
+ other = cnt * _k + xcurr;
+ if(_n==3){
+ other+= curr4*_k*_k;
+ }
+ if(_n==4){
+ curr4=((int)(node/(_k*_k)))%_k;
+ other+= curr4*_k*_k+curr5*_k*_k*_k;
+ }
+ }else if (dim ==2){
+ other = cnt*_k*_k + curr3;
+ if(_n==4){
+ other+= curr5*_k*_k*_k;
+ }
+ }else if (dim ==3){
+ other = cnt*_k*_k*_k+curr6;
+ }
+ assert(dim < 4);
+ if(other == node){
+#ifdef DEBUG_FLATFLY
+ cout << "ignore channel : " << _output << " to node " << node <<" and "<<other<<endl;
+#endif
+ continue;
+ }
+ //calculate channel length
+ int length = 0;
+ int oned = abs((node%_xcount)-(other%_xcount));
+ int twod = abs(node/_xcount-other/_xcount);
+ length = _xrouter*oned + _yrouter *twod;
+ //oh the node<other silly ness
+ if(node<other){
+ offset = -1;
+ }
+ //node, dimension, router within dimension. Good luck understanding this
+ _output = (_k-1) * _n * node + (_k-1) * dim + cnt+offset;
+
+
+#ifdef DEBUG_FLATFLY
+ cout << "Adding channel : " << _output << " to node " << node <<" and "<<other<<" with length "<<length<<endl;
+#endif
+ if(use_noc_latency){
+ _chan[_output]->SetLatency(length);
+ _chan_cred[_output]->SetLatency(length);
+ } else {
+ _chan[_output]->SetLatency(1);
+ _chan_cred[_output]->SetLatency(1);
+ }
+ _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] );
+
+ _routers[other]->AddInputChannel( _chan[_output], _chan_cred[_output]);
+
+ if(gTrace){
+ cout<<"Link "<<_output<<" "<<node<<" "<<other<<" "<<length<<endl;
+ }
+
+ }
+ }
+ }
+ if(gTrace){
+ cout<<"Setup Finished Link"<<endl;
+ }
+}
+
+
+int FlatFlyOnChip::GetN( ) const
+{
+ return _n;
+}
+
+int FlatFlyOnChip::GetK( ) const
+{
+ return _k;
+}
+
+void FlatFlyOnChip::InsertRandomFaults( const Configuration &config )
+{
+
+}
+
+double FlatFlyOnChip::Capacity( ) const
+{
+ return (double)_k / 8.0;
+}
+
+
+void FlatFlyOnChip::RegisterRoutingFunctions(){
+
+
+ gRoutingFunctionMap["ran_min_flatfly"] = &min_flatfly;
+ gRoutingFunctionMap["adaptive_xyyx_flatfly"] = &adaptive_xyyx_flatfly;
+ gRoutingFunctionMap["xyyx_flatfly"] = &xyyx_flatfly;
+ gRoutingFunctionMap["valiant_flatfly"] = &valiant_flatfly;
+ gRoutingFunctionMap["ugal_flatfly"] = &ugal_flatfly_onchip;
+ gRoutingFunctionMap["ugal_pni_flatfly"] = &ugal_pni_flatfly_onchip;
+ gRoutingFunctionMap["ugal_xyyx_flatfly"] = &ugal_xyyx_flatfly_onchip;
+
+}
+
+//The initial XY or YX minimal routing direction is chosen adaptively
+void adaptive_xyyx_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+ int targetr = (int)(dest/gC);
+
+ if(targetr==r->GetID()){ //if we are at the final router, yay, output to client
+ out_port = dest % gC;
+
+ } else {
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ int out_port_xy = flatfly_outport(dest, r->GetID());
+ int out_port_yx = flatfly_outport_yx(dest, r->GetID());
+
+ // Route order (XY or YX) determined when packet is injected
+ // into the network, adaptively
+ bool x_then_y;
+ if(in_channel < gC){
+ int credit_xy = r->GetUsedCredit(out_port_xy);
+ int credit_yx = r->GetUsedCredit(out_port_yx);
+ if(credit_xy > credit_yx) {
+ x_then_y = false;
+ } else if(credit_xy < credit_yx) {
+ x_then_y = true;
+ } else {
+ x_then_y = (RandomInt(1) > 0);
+ }
+ } else {
+ x_then_y = (f->vc < (vcBegin + available_vcs));
+ }
+
+ if(x_then_y) {
+ out_port = out_port_xy;
+ vcEnd -= available_vcs;
+ } else {
+ out_port = out_port_yx;
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+//The initial XY or YX minimal routing direction is chosen randomly
+void xyyx_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+ int targetr = (int)(dest/gC);
+
+ if(targetr==r->GetID()){ //if we are at the final router, yay, output to client
+ out_port = dest % gC;
+
+ } else {
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ // randomly select dimension order at first hop
+ bool x_then_y = ((in_channel < gC) ?
+ (RandomInt(1) > 0) :
+ (f->vc < (vcBegin + available_vcs)));
+
+ if(x_then_y) {
+ out_port = flatfly_outport(dest, r->GetID());
+ vcEnd -= available_vcs;
+ } else {
+ out_port = flatfly_outport_yx(dest, r->GetID());
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+int flatfly_outport_yx(int dest, int rID) {
+ int dest_rID = (int) (dest / gC);
+ int _dim = gN;
+ int output = -1, dID, sID;
+
+ if(dest_rID==rID){
+ return dest % gC;
+ }
+
+ for (int d=_dim-1;d >= 0; d--) {
+ int power = powi(gK,d);
+ dID = int(dest_rID / power);
+ sID = int(rID / power);
+ if ( dID != sID ) {
+ output = gC + ((gK-1)*d) - 1;
+ if (dID > sID) {
+ output += dID;
+ } else {
+ output += dID + 1;
+ }
+ return output;
+ }
+ dest_rID = (int) (dest_rID %power);
+ rID = (int) (rID %power);
+ }
+ if (output == -1) {
+ cout << " ERROR ---- FLATFLY_OUTPORT function : output not found yx" << endl;
+ exit(-1);
+ }
+ return -1;
+}
+
+void valiant_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ if ( in_channel < gC ){
+ f->ph = 0;
+ f->intm = RandomInt( powi( gK, gN )*gC-1);
+ }
+
+ int intm = flatfly_transformation(f->intm);
+ int dest = flatfly_transformation(f->dest);
+
+ if((int)(intm/gC) == r->GetID() || (int)(dest/gC)== r->GetID()){
+ f->ph = 1;
+ }
+
+ if(f->ph == 0) {
+ out_port = flatfly_outport(intm, r->GetID());
+ } else {
+ assert(f->ph == 1);
+ out_port = flatfly_outport(dest, r->GetID());
+ }
+
+ if((int)(dest/gC) != r->GetID()) {
+
+ //each class must have at least 2 vcs assigned or else valiant valiant will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ if(f->ph == 0) {
+ vcEnd -= available_vcs;
+ } else {
+ // If routing to final destination use the second half of the VCs.
+ assert(f->ph == 1);
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+void min_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+ int targetr= (int)(dest/gC);
+ //int xdest = ((int)(dest/gC)) % gK;
+ //int xcurr = ((r->GetID())) % gK;
+
+ //int ydest = ((int)(dest/gC)) / gK;
+ //int ycurr = ((r->GetID())) / gK;
+
+ if(targetr==r->GetID()){ //if we are at the final router, yay, output to client
+ out_port = dest % gC;
+ } else{ //else select a dimension at random
+ out_port = flatfly_outport(dest, r->GetID());
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+//=============================================================^M
+// route UGAL in the flattened butterfly
+//=============================================================^M
+
+
+//same as ugal except uses xyyx routing
+void ugal_xyyx_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+
+ int rID = r->GetID();
+ int _concentration = gC;
+ int found;
+ int debug = 0;
+ int tmp_out_port, _ran_intm;
+ int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt;
+ int threshold = 2;
+
+
+ if ( in_channel < gC ){
+ if(gTrace){
+ cout<<"New Flit "<<f->src<<endl;
+ }
+ f->ph = 0;
+ }
+
+ if(gTrace){
+ int load = 0;
+ cout<<"Router "<<rID<<endl;
+ cout<<"Input Channel "<<in_channel<<endl;
+ //need to modify router to report the buffere depth
+ load +=r->GetBufferOccupancy(in_channel);
+ cout<<"Rload "<<load<<endl;
+ }
+
+ if (debug){
+ cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl;
+ }
+ // f->ph == 0 ==> make initial global adaptive decision
+ // f->ph == 1 ==> route nonminimaly to random intermediate node
+ // f->ph == 2 ==> route minimally to destination
+
+ found = 0;
+
+ if (f->ph == 1){
+ dest = f->intm;
+ }
+
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+ if (f->ph == 1) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ if (debug) cout << " done routing to intermediate ";
+ }
+ else {
+ found = 1;
+ out_port = dest % gC;
+ if (debug) cout << " final routing to destination ";
+ }
+ }
+
+ if (!found) {
+
+ int const xy_available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(xy_available_vcs > 0);
+
+ // randomly select dimension order at first hop
+ bool x_then_y = ((in_channel < gC) ?
+ (RandomInt(1) > 0) :
+ (f->vc < (vcBegin + xy_available_vcs)));
+
+ if (f->ph == 0) {
+ //find the min port and min distance
+ _min_hop = find_distance(flatfly_transformation(f->src),dest);
+ if(x_then_y){
+ tmp_out_port = flatfly_outport(dest, rID);
+ } else {
+ tmp_out_port = flatfly_outport_yx(dest, rID);
+ }
+ if (f->watch){
+ cout << " MIN tmp_out_port: " << tmp_out_port;
+ }
+ //sum over all vcs of that port
+ _min_queucnt = r->GetUsedCredit(tmp_out_port);
+
+ //find the nonmin router, nonmin port, nonmin count
+ _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest);
+ _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest);
+ if(x_then_y){
+ tmp_out_port = flatfly_outport(_ran_intm, rID);
+ } else {
+ tmp_out_port = flatfly_outport_yx(_ran_intm, rID);
+ }
+
+ if (f->watch){
+ cout << " NONMIN tmp_out_port: " << tmp_out_port << endl;
+ }
+ if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) {
+ _nonmin_queucnt = numeric_limits<int>::max();
+ } else {
+ _nonmin_queucnt = r->GetUsedCredit(tmp_out_port);
+ }
+
+ if (debug){
+ cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl;
+ }
+
+ if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) {
+
+ if (debug) cout << " Route MINIMALLY " << endl;
+ f->ph = 2;
+ } else {
+ // route non-minimally
+ if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; }
+ f->ph = 1;
+ f->intm = _ran_intm;
+ dest = f->intm;
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ }
+ }
+ }
+
+ //dest here should be == intm if ph==1, or dest == dest if ph == 2
+ if(x_then_y){
+ out_port = flatfly_outport(dest, rID);
+ if(out_port >= gC) {
+ vcEnd -= xy_available_vcs;
+ }
+ } else {
+ out_port = flatfly_outport_yx(dest, rID);
+ if(out_port >= gC) {
+ vcBegin += xy_available_vcs;
+ }
+ }
+
+ // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock
+ if(out_port >= gC) {
+
+ int const ph_available_vcs = xy_available_vcs / 2;
+ assert(ph_available_vcs > 0);
+
+ if(f->ph == 1) {
+ vcEnd -= ph_available_vcs;
+ } else {
+ assert(f->ph == 2);
+ vcBegin += ph_available_vcs;
+ }
+ }
+
+ found = 1;
+ }
+
+ if (!found) {
+ cout << " ERROR: output not found in routing. " << endl;
+ cout << *f; exit (-1);
+ }
+
+ if (out_port >= gN*(gK-1) + gC) {
+ cout << " ERROR: output port too big! " << endl;
+ cout << " OUTPUT select: " << out_port << endl;
+ cout << " router radix: " << gN*(gK-1) + gK << endl;
+ exit (-1);
+ }
+
+ if (debug) cout << " through output port : " << out_port << endl;
+ if(gTrace){cout<<"Outport "<<out_port<<endl;cout<<"Stop Mark"<<endl;}
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+
+
+//ugal now uses modified comparison, modefied getcredit
+void ugal_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+
+ int rID = r->GetID();
+ int _concentration = gC;
+ int found;
+ int debug = 0;
+ int tmp_out_port, _ran_intm;
+ int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt;
+ int threshold = 2;
+
+ if ( in_channel < gC ){
+ if(gTrace){
+ cout<<"New Flit "<<f->src<<endl;
+ }
+ f->ph = 0;
+ }
+
+ if(gTrace){
+ int load = 0;
+ cout<<"Router "<<rID<<endl;
+ cout<<"Input Channel "<<in_channel<<endl;
+ //need to modify router to report the buffere depth
+ load +=r->GetBufferOccupancy(in_channel);
+ cout<<"Rload "<<load<<endl;
+ }
+
+ if (debug){
+ cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl;
+ }
+ // f->ph == 0 ==> make initial global adaptive decision
+ // f->ph == 1 ==> route nonminimaly to random intermediate node
+ // f->ph == 2 ==> route minimally to destination
+
+ found = 0;
+
+ if (f->ph == 1){
+ dest = f->intm;
+ }
+
+
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+
+ if (f->ph == 1) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ if (debug) cout << " done routing to intermediate ";
+ }
+ else {
+ found = 1;
+ out_port = dest % gC;
+ if (debug) cout << " final routing to destination ";
+ }
+ }
+
+ if (!found) {
+
+ if (f->ph == 0) {
+ _min_hop = find_distance(flatfly_transformation(f->src),dest);
+ _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest);
+ tmp_out_port = flatfly_outport(dest, rID);
+ if (f->watch){
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << " MIN tmp_out_port: " << tmp_out_port;
+ }
+
+ _min_queucnt = r->GetUsedCredit(tmp_out_port);
+
+ _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest);
+ tmp_out_port = flatfly_outport(_ran_intm, rID);
+
+ if (f->watch){
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << " NONMIN tmp_out_port: " << tmp_out_port << endl;
+ }
+ if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) {
+ _nonmin_queucnt = numeric_limits<int>::max();
+ } else {
+ _nonmin_queucnt = r->GetUsedCredit(tmp_out_port);
+ }
+
+ if (debug){
+ cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl;
+ }
+
+ if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) {
+
+ if (debug) cout << " Route MINIMALLY " << endl;
+ f->ph = 2;
+ } else {
+ // route non-minimally
+ if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; }
+ f->ph = 1;
+ f->intm = _ran_intm;
+ dest = f->intm;
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ }
+ }
+ }
+
+ // find minimal correct dimension to route through
+ out_port = flatfly_outport(dest, rID);
+
+ // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock
+ if(out_port >= gC) {
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+ if(f->ph == 1) {
+ vcEnd -= available_vcs;
+ } else {
+ assert(f->ph == 2);
+ vcBegin += available_vcs;
+ }
+ }
+
+ found = 1;
+ }
+
+ if (!found) {
+ cout << " ERROR: output not found in routing. " << endl;
+ cout << *f; exit (-1);
+ }
+
+ if (out_port >= gN*(gK-1) + gC) {
+ cout << " ERROR: output port too big! " << endl;
+ cout << " OUTPUT select: " << out_port << endl;
+ cout << " router radix: " << gN*(gK-1) + gK << endl;
+ exit (-1);
+ }
+
+ if (debug) cout << " through output port : " << out_port << endl;
+ if(gTrace) {
+ cout<<"Outport "<<out_port<<endl;
+ cout<<"Stop Mark"<<endl;
+ }
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+
+// partially non-interfering (i.e., packets ordered by hash of destination) UGAL
+void ugal_pni_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ // ( Traffic Class , Routing Order ) -> Virtual Channel Range
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = flatfly_transformation(f->dest);
+
+ int rID = r->GetID();
+ int _concentration = gC;
+ int found;
+ int debug = 0;
+ int tmp_out_port, _ran_intm;
+ int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt;
+ int threshold = 2;
+
+ if ( in_channel < gC ){
+ if(gTrace){
+ cout<<"New Flit "<<f->src<<endl;
+ }
+ f->ph = 0;
+ }
+
+ if(gTrace){
+ int load = 0;
+ cout<<"Router "<<rID<<endl;
+ cout<<"Input Channel "<<in_channel<<endl;
+ //need to modify router to report the buffere depth
+ load +=r->GetBufferOccupancy(in_channel);
+ cout<<"Rload "<<load<<endl;
+ }
+
+ if (debug){
+ cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl;
+ }
+ // f->ph == 0 ==> make initial global adaptive decision
+ // f->ph == 1 ==> route nonminimaly to random intermediate node
+ // f->ph == 2 ==> route minimally to destination
+
+ found = 0;
+
+ if (f->ph == 1){
+ dest = f->intm;
+ }
+
+
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+
+ if (f->ph == 1) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ if (debug) cout << " done routing to intermediate ";
+ }
+ else {
+ found = 1;
+ out_port = dest % gC;
+ if (debug) cout << " final routing to destination ";
+ }
+ }
+
+ if (!found) {
+
+ if (f->ph == 0) {
+ _min_hop = find_distance(flatfly_transformation(f->src),dest);
+ _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest);
+ tmp_out_port = flatfly_outport(dest, rID);
+ if (f->watch){
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << " MIN tmp_out_port: " << tmp_out_port;
+ }
+
+ _min_queucnt = r->GetUsedCredit(tmp_out_port);
+
+ _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest);
+ tmp_out_port = flatfly_outport(_ran_intm, rID);
+
+ if (f->watch){
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << " NONMIN tmp_out_port: " << tmp_out_port << endl;
+ }
+ if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) {
+ _nonmin_queucnt = numeric_limits<int>::max();
+ } else {
+ _nonmin_queucnt = r->GetUsedCredit(tmp_out_port);
+ }
+
+ if (debug){
+ cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl;
+ }
+
+ if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) {
+
+ if (debug) cout << " Route MINIMALLY " << endl;
+ f->ph = 2;
+ } else {
+ // route non-minimally
+ if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; }
+ f->ph = 1;
+ f->intm = _ran_intm;
+ dest = f->intm;
+ if (dest >= rID*_concentration && dest < (rID+1)*_concentration) {
+ f->ph = 2;
+ dest = flatfly_transformation(f->dest);
+ }
+ }
+ }
+
+ // find minimal correct dimension to route through
+ out_port = flatfly_outport(dest, rID);
+
+ // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock
+ if(out_port >= gC) {
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+ if(f->ph == 1) {
+ vcEnd -= available_vcs;
+ } else {
+ assert(f->ph == 2);
+ vcBegin += available_vcs;
+ }
+ }
+
+ found = 1;
+ }
+
+ if (!found) {
+ cout << " ERROR: output not found in routing. " << endl;
+ cout << *f; exit (-1);
+ }
+
+ if (out_port >= gN*(gK-1) + gC) {
+ cout << " ERROR: output port too big! " << endl;
+ cout << " OUTPUT select: " << out_port << endl;
+ cout << " router radix: " << gN*(gK-1) + gK << endl;
+ exit (-1);
+ }
+
+ if (debug) cout << " through output port : " << out_port << endl;
+ if(gTrace) {
+ cout<<"Outport "<<out_port<<endl;
+ cout<<"Stop Mark"<<endl;
+ }
+ }
+
+ if(inject || (out_port >= gC)) {
+
+ // NOTE: for "proper" flattened butterfly configurations (i.e., ones
+ // derived from flattening an actual butterfly), gK and gC are the same!
+ assert(gK == gC);
+
+ assert(inject ? (f->ph == -1) : (f->ph == 1 || f->ph == 2));
+
+ int next_coord = flatfly_transformation(f->dest);
+ if(inject) {
+ next_coord /= gC;
+ next_coord %= gK;
+ } else {
+ int next_dim = (out_port - gC) / (gK - 1) + 1;
+ if(next_dim == gN) {
+ next_coord %= gC;
+ } else {
+ next_coord /= gC;
+ for(int d = 0; d < next_dim; ++d) {
+ next_coord /= gK;
+ }
+ next_coord %= gK;
+ }
+ }
+ assert(next_coord >= 0 && next_coord < gK);
+ int vcs_per_dest = (vcEnd - vcBegin + 1) / gK;
+ assert(vcs_per_dest > 0);
+ vcBegin += next_coord * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+
+//=============================================================^M
+// UGAL : calculate distance (hop cnt) between src and destination
+//=============================================================^M
+int find_distance (int src, int dest) {
+ int dist = 0;
+ int _dim = gN;
+ int _dim_size;
+
+ int src_tmp= (int) src / gC;
+ int dest_tmp = (int) dest / gC;
+ int src_id, dest_id;
+
+ // cout << " HOP CNT between src: " << src << " dest: " << dest;
+ for (int d=0;d < _dim; d++) {
+ _dim_size = powi(gK, d )*gC;
+ //if ((int)(src / _dim_size) != (int)(dest / _dim_size))
+ // dist++;
+ src_id = src_tmp % gK;
+ dest_id = dest_tmp % gK;
+ if (src_id != dest_id)
+ dist++;
+ src_tmp = (int) (src_tmp / gK);
+ dest_tmp = (int) (dest_tmp / gK);
+ }
+
+ // cout << " : " << dist << endl;
+
+ return dist;
+}
+
+//=============================================================^M
+// UGAL : find random node for load balancing
+//=============================================================^M
+int find_ran_intm (int src, int dest) {
+ int _dim = gN;
+ int _dim_size;
+ int _ran_dest = 0;
+ int debug = 0;
+
+ if (debug)
+ cout << " INTM node for src: " << src << " dest: " <<dest << endl;
+
+ src = (int) (src / gC);
+ dest = (int) (dest / gC);
+
+ _ran_dest = RandomInt(gC - 1);
+ if (debug) cout << " ............ _ran_dest : " << _ran_dest << endl;
+ for (int d=0;d < _dim; d++) {
+
+ _dim_size = powi(gK, d)*gC;
+ if ((src % gK) == (dest % gK)) {
+ _ran_dest += (src % gK) * _dim_size;
+ if (debug)
+ cout << " share same dimension : " << d << " int node : " << _ran_dest << " src ID : " << src % gK << endl;
+ } else {
+ // src and dest are in the same dimension "d" + 1
+ // ==> thus generate a random destination within
+ _ran_dest += RandomInt(gK - 1) * _dim_size;
+ if (debug)
+ cout << " different dimension : " << d << " int node : " << _ran_dest << " _dim_size: " << _dim_size << endl;
+ }
+ src = (int) (src / gK);
+ dest = (int) (dest / gK);
+ }
+
+ if (debug) cout << " intermediate destination NODE: " << _ran_dest << endl;
+ return _ran_dest;
+}
+
+
+
+//=============================================================
+// UGAL : calculated minimum distance output port for flatfly
+// given the dimension and destination
+//=============================================================
+// starting from DIM 0 (x first)
+int flatfly_outport(int dest, int rID) {
+ int dest_rID = (int) (dest / gC);
+ int _dim = gN;
+ int output = -1, dID, sID;
+
+ if(dest_rID==rID){
+ return dest % gC;
+ }
+
+
+ for (int d=0;d < _dim; d++) {
+ dID = (dest_rID % gK);
+ sID = (rID % gK);
+ if ( dID != sID ) {
+ output = gC + ((gK-1)*d) - 1;
+ if (dID > sID) {
+
+ output += dID;
+ } else {
+ output += dID + 1;
+ }
+
+ return output;
+ }
+ dest_rID = (int) (dest_rID / gK);
+ rID = (int) (rID / gK);
+ }
+ if (output == -1) {
+ cout << " ERROR ---- FLATFLY_OUTPORT function : output not found " << endl;
+ exit(-1);
+ }
+ return -1;
+}
+
+int flatfly_transformation(int dest){
+ //the magic of destination transformation
+
+ //destination transformation, translate how the nodes are actually arranged
+ //to the easier way of routing
+ //this transformation only support 64 nodes
+
+ //cout<<"ORiginal destination "<<dest<<endl;
+ //router in the x direction = find which column, and then mod by cY to find
+ //which horizontal router
+ int horizontal = (dest%(_xcount*_xrouter))/(_xrouter);
+ int horizontal_rem = (dest%(_xcount*_xrouter))%(_xrouter);
+ //router in the y direction = find which row, and then divided by cX to find
+ //vertical router
+ int vertical = (dest/(_xcount*_xrouter))/(_yrouter);
+ int vertical_rem = (dest/(_xcount*_xrouter))%(_yrouter);
+ //transform the destination to as if node0 was 0,1,2,3 and so forth
+ dest = (vertical*_xcount + horizontal)*gC+_xrouter*vertical_rem+horizontal_rem;
+ //cout<<"Transformed destination "<<dest<<endl<<endl;
+ return dest;
+}
diff --git a/src/intersim2/networks/flatfly_onchip.hpp b/src/intersim2/networks/flatfly_onchip.hpp
new file mode 100644
index 0000000..2f164be
--- /dev/null
+++ b/src/intersim2/networks/flatfly_onchip.hpp
@@ -0,0 +1,88 @@
+// $Id: flatfly_onchip.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _FlatFlyOnChip_HPP_
+#define _FlatFlyOnChip_HPP_
+
+#include "network.hpp"
+
+#include "routefunc.hpp"
+#include <cassert>
+
+
+class FlatFlyOnChip : public Network {
+
+ int _m;
+ int _n;
+ int _r;
+ int _k;
+ int _c;
+ int _radix;
+ int _net_size;
+ int _stageout;
+ int _numinput;
+ int _stages;
+ int _num_of_switch;
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+
+ int _OutChannel( int stage, int addr, int port, int outputs ) const;
+ int _InChannel( int stage, int addr, int port ) const;
+
+public:
+ FlatFlyOnChip( const Configuration &config, const string & name );
+
+ int GetN( ) const;
+ int GetK( ) const;
+
+ static void RegisterRoutingFunctions() ;
+ double Capacity( ) const;
+ void InsertRandomFaults( const Configuration &config );
+};
+void adaptive_xyyx_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void xyyx_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void min_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void ugal_xyyx_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void ugal_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void ugal_pni_flatfly_onchip( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+void valiant_flatfly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject );
+
+int find_distance (int src, int dest);
+int find_ran_intm (int src, int dest);
+int flatfly_outport(int dest, int rID);
+int flatfly_transformation(int dest);
+int flatfly_outport_yx(int dest, int rID);
+
+#endif
diff --git a/src/intersim2/networks/fly.cpp b/src/intersim2/networks/fly.cpp
new file mode 100644
index 0000000..8e0bdd7
--- /dev/null
+++ b/src/intersim2/networks/fly.cpp
@@ -0,0 +1,162 @@
+// $Id: fly.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+
+#include "fly.hpp"
+#include "misc_utils.hpp"
+
+//#define DEBUG_FLY
+
+KNFly::KNFly( const Configuration &config, const string & name ) :
+Network( config, name )
+{
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void KNFly::_ComputeSize( const Configuration &config )
+{
+ _k = config.GetInt( "k" );
+ _n = config.GetInt( "n" );
+
+ gK = _k; gN = _n;
+
+ _nodes = powi( _k, _n );
+
+ // n stages of k^(n-1) k x k switches
+ _size = _n*powi( _k, _n-1 );
+
+ // n-1 sets of wiring between the stages
+ _channels = (_n-1)*_nodes;
+}
+
+void KNFly::_BuildNet( const Configuration &config )
+{
+ ostringstream router_name;
+
+ int per_stage = powi( _k, _n-1 );
+
+ int node = 0;
+ int c;
+
+ for ( int stage = 0; stage < _n; ++stage ) {
+ for ( int addr = 0; addr < per_stage; ++addr ) {
+
+ router_name << "router_" << stage << "_" << addr;
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, _k, _k );
+ _timed_modules.push_back(_routers[node]);
+ router_name.str("");
+
+#ifdef DEBUG_FLY
+ cout << "connecting node " << node << " to:" << endl;
+#endif
+
+ for ( int port = 0; port < _k; ++port ) {
+ // Input connections
+ if ( stage == 0 ) {
+ c = addr*_k + port;
+ _routers[node]->AddInputChannel( _inject[c], _inject_cred[c] );
+#ifdef DEBUG_FLY
+ cout << " injection channel " << c << endl;
+#endif
+ } else {
+ c = _InChannel( stage, addr, port );
+ _routers[node]->AddInputChannel( _chan[c], _chan_cred[c] );
+ _chan[c]->SetLatency( 1 );
+
+#ifdef DEBUG_FLY
+ cout << " input channel " << c << endl;
+#endif
+ }
+
+ // Output connections
+ if ( stage == _n - 1 ) {
+ c = addr*_k + port;
+ _routers[node]->AddOutputChannel( _eject[c], _eject_cred[c] );
+#ifdef DEBUG_FLY
+ cout << " ejection channel " << c << endl;
+#endif
+ } else {
+ c = _OutChannel( stage, addr, port );
+ _routers[node]->AddOutputChannel( _chan[c], _chan_cred[c] );
+#ifdef DEBUG_FLY
+ cout << " output channel " << c << endl;
+#endif
+ }
+ }
+
+ ++node;
+ }
+ }
+}
+
+int KNFly::_OutChannel( int stage, int addr, int port ) const
+{
+ return stage*_nodes + addr*_k + port;
+}
+
+int KNFly::_InChannel( int stage, int addr, int port ) const
+{
+ int in_addr;
+ int in_port;
+
+ // Channels are between {node,port}
+ // { d_{n-1} ... d_{n-stage} ... d_0 } and
+ // { d_{n-1} ... d_0 ... d_{n-stage} }
+
+ int shift = powi( _k, _n-stage-1 );
+
+ int last_digit = port;
+ int zero_digit = ( addr / shift ) % _k;
+
+ // swap zero and last digit to get first node's address
+ in_addr = addr - zero_digit*shift + last_digit*shift;
+ in_port = zero_digit;
+
+ return (stage-1)*_nodes + in_addr*_k + in_port;
+}
+
+int KNFly::GetN( ) const
+{
+ return _n;
+}
+
+int KNFly::GetK( ) const
+{
+ return _k;
+}
+
+double KNFly::Capacity( ) const
+{
+ return 1.0;
+}
+
diff --git a/src/intersim2/networks/fly.hpp b/src/intersim2/networks/fly.hpp
new file mode 100644
index 0000000..c32062f
--- /dev/null
+++ b/src/intersim2/networks/fly.hpp
@@ -0,0 +1,53 @@
+// $Id: fly.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _FLY_HPP_
+#define _FLY_HPP_
+
+#include "network.hpp"
+
+class KNFly : public Network {
+
+ int _k;
+ int _n;
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+
+ int _OutChannel( int stage, int addr, int port ) const;
+ int _InChannel( int stage, int addr, int port ) const;
+
+public:
+ KNFly( const Configuration &config, const string & name );
+
+ int GetN( ) const;
+ int GetK( ) const;
+ static void RegisterRoutingFunctions(){};
+ double Capacity( ) const;
+};
+
+#endif
diff --git a/src/intersim2/networks/kncube.cpp b/src/intersim2/networks/kncube.cpp
new file mode 100644
index 0000000..6915f22
--- /dev/null
+++ b/src/intersim2/networks/kncube.cpp
@@ -0,0 +1,319 @@
+// $Id: kncube.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*kn.cpp
+ *
+ *Meshs, cube, torus
+ *
+ */
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include "kncube.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+ //#include "iq_router.hpp"
+
+
+KNCube::KNCube( const Configuration &config, const string & name, bool mesh ) :
+Network( config, name )
+{
+ _mesh = mesh;
+
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void KNCube::_ComputeSize( const Configuration &config )
+{
+ _k = config.GetInt( "k" );
+ _n = config.GetInt( "n" );
+
+ gK = _k; gN = _n;
+ _size = powi( _k, _n );
+ _channels = 2*_n*_size;
+
+ _nodes = _size;
+}
+
+void KNCube::RegisterRoutingFunctions() {
+
+}
+void KNCube::_BuildNet( const Configuration &config )
+{
+ int left_node;
+ int right_node;
+
+ int right_input;
+ int left_input;
+
+ int right_output;
+ int left_output;
+
+ ostringstream router_name;
+
+ //latency type, noc or conventional network
+ bool use_noc_latency;
+ use_noc_latency = (config.GetInt("use_noc_latency")==1);
+
+ for ( int node = 0; node < _size; ++node ) {
+
+ router_name << "router";
+
+ if ( _k > 1 ) {
+ for ( int dim_offset = _size / _k; dim_offset >= 1; dim_offset /= _k ) {
+ router_name << "_" << ( node / dim_offset ) % _k;
+ }
+ }
+
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, 2*_n + 1, 2*_n + 1 );
+ _timed_modules.push_back(_routers[node]);
+
+ router_name.str("");
+
+ for ( int dim = 0; dim < _n; ++dim ) {
+
+ //find the neighbor
+ left_node = _LeftNode( node, dim );
+ right_node = _RightNode( node, dim );
+
+ //
+ // Current (N)ode
+ // (L)eft node
+ // (R)ight node
+ //
+ // L--->N<---R
+ // L<---N--->R
+ //
+
+ // torus channel is longer due to wrap around
+ int latency = _mesh ? 1 : 2 ;
+
+ //get the input channel number
+ right_input = _LeftChannel( right_node, dim );
+ left_input = _RightChannel( left_node, dim );
+
+ //add the input channel
+ _routers[node]->AddInputChannel( _chan[right_input], _chan_cred[right_input] );
+ _routers[node]->AddInputChannel( _chan[left_input], _chan_cred[left_input] );
+
+ //set input channel latency
+ if(use_noc_latency){
+ _chan[right_input]->SetLatency( latency );
+ _chan[left_input]->SetLatency( latency );
+ _chan_cred[right_input]->SetLatency( latency );
+ _chan_cred[left_input]->SetLatency( latency );
+ } else {
+ _chan[left_input]->SetLatency( 1 );
+ _chan_cred[right_input]->SetLatency( 1 );
+ _chan_cred[left_input]->SetLatency( 1 );
+ _chan[right_input]->SetLatency( 1 );
+ }
+ //get the output channel number
+ right_output = _RightChannel( node, dim );
+ left_output = _LeftChannel( node, dim );
+
+ //add the output channel
+ _routers[node]->AddOutputChannel( _chan[right_output], _chan_cred[right_output] );
+ _routers[node]->AddOutputChannel( _chan[left_output], _chan_cred[left_output] );
+
+ //set output channel latency
+ if(use_noc_latency){
+ _chan[right_output]->SetLatency( latency );
+ _chan[left_output]->SetLatency( latency );
+ _chan_cred[right_output]->SetLatency( latency );
+ _chan_cred[left_output]->SetLatency( latency );
+ } else {
+ _chan[right_output]->SetLatency( 1 );
+ _chan[left_output]->SetLatency( 1 );
+ _chan_cred[right_output]->SetLatency( 1 );
+ _chan_cred[left_output]->SetLatency( 1 );
+
+ }
+ }
+ //injection and ejection channel, always 1 latency
+ _routers[node]->AddInputChannel( _inject[node], _inject_cred[node] );
+ _routers[node]->AddOutputChannel( _eject[node], _eject_cred[node] );
+ _inject[node]->SetLatency( 1 );
+ _eject[node]->SetLatency( 1 );
+ }
+}
+
+int KNCube::_LeftChannel( int node, int dim )
+{
+ // The base channel for a node is 2*_n*node
+ int base = 2*_n*node;
+ // The offset for a left channel is 2*dim + 1
+ int off = 2*dim + 1;
+
+ return ( base + off );
+}
+
+int KNCube::_RightChannel( int node, int dim )
+{
+ // The base channel for a node is 2*_n*node
+ int base = 2*_n*node;
+ // The offset for a right channel is 2*dim
+ int off = 2*dim;
+ return ( base + off );
+}
+
+int KNCube::_LeftNode( int node, int dim )
+{
+ int k_to_dim = powi( _k, dim );
+ int loc_in_dim = ( node / k_to_dim ) % _k;
+ int left_node;
+ // if at the left edge of the dimension, wraparound
+ if ( loc_in_dim == 0 ) {
+ left_node = node + (_k-1)*k_to_dim;
+ } else {
+ left_node = node - k_to_dim;
+ }
+
+ return left_node;
+}
+
+int KNCube::_RightNode( int node, int dim )
+{
+ int k_to_dim = powi( _k, dim );
+ int loc_in_dim = ( node / k_to_dim ) % _k;
+ int right_node;
+ // if at the right edge of the dimension, wraparound
+ if ( loc_in_dim == ( _k-1 ) ) {
+ right_node = node - (_k-1)*k_to_dim;
+ } else {
+ right_node = node + k_to_dim;
+ }
+
+ return right_node;
+}
+
+int KNCube::GetN( ) const
+{
+ return _n;
+}
+
+int KNCube::GetK( ) const
+{
+ return _k;
+}
+
+/*legacy, not sure how this fits into the own scheme of things*/
+void KNCube::InsertRandomFaults( const Configuration &config )
+{
+ int num_fails;
+ unsigned long prev_seed;
+
+ int node, chan;
+ int i, j, t, n, c;
+ bool available;
+
+ bool edge;
+
+ num_fails = config.GetInt( "link_failures" );
+
+ if ( num_fails ) {
+ prev_seed = RandomIntLong( );
+ RandomSeed( config.GetInt( "fail_seed" ) );
+
+ vector<bool> fail_nodes(_size);
+
+ for ( i = 0; i < _size; ++i ) {
+ node = i;
+
+ // edge test
+ edge = false;
+ for ( n = 0; n < _n; ++n ) {
+ if ( ( ( node % _k ) == 0 ) ||
+ ( ( node % _k ) == _k - 1 ) ) {
+ edge = true;
+ }
+ node /= _k;
+ }
+
+ if ( edge ) {
+ fail_nodes[i] = true;
+ } else {
+ fail_nodes[i] = false;
+ }
+ }
+
+ for ( i = 0; i < num_fails; ++i ) {
+ j = RandomInt( _size - 1 );
+ available = false;
+
+ for ( t = 0; ( t < _size ) && (!available); ++t ) {
+ node = ( j + t ) % _size;
+
+ if ( !fail_nodes[node] ) {
+ // check neighbors
+ c = RandomInt( 2*_n - 1 );
+
+ for ( n = 0; ( n < 2*_n ) && (!available); ++n ) {
+ chan = ( n + c ) % 2*_n;
+
+ if ( chan % 1 ) {
+ available = fail_nodes[_LeftNode( node, chan/2 )];
+ } else {
+ available = fail_nodes[_RightNode( node, chan/2 )];
+ }
+ }
+ }
+
+ if ( !available ) {
+ cout << "skipping " << node << endl;
+ }
+ }
+
+ if ( t == _size ) {
+ Error( "Could not find another possible fault channel" );
+ }
+
+
+ OutChannelFault( node, chan );
+ fail_nodes[node] = true;
+
+ for ( n = 0; ( n < _n ) && available ; ++n ) {
+ fail_nodes[_LeftNode( node, n )] = true;
+ fail_nodes[_RightNode( node, n )] = true;
+ }
+
+ cout << "failure at node " << node << ", channel "
+ << chan << endl;
+ }
+
+ RandomSeed( prev_seed );
+ }
+}
+
+double KNCube::Capacity( ) const
+{
+ return (double)_k / ( _mesh ? 8.0 : 4.0 );
+}
diff --git a/src/intersim2/networks/kncube.hpp b/src/intersim2/networks/kncube.hpp
new file mode 100644
index 0000000..b3ca1ca
--- /dev/null
+++ b/src/intersim2/networks/kncube.hpp
@@ -0,0 +1,62 @@
+// $Id: kncube.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _KNCUBE_HPP_
+#define _KNCUBE_HPP_
+
+#include "network.hpp"
+
+class KNCube : public Network {
+
+ bool _mesh;
+
+ int _k;
+ int _n;
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+
+ int _LeftChannel( int node, int dim );
+ int _RightChannel( int node, int dim );
+
+ int _LeftNode( int node, int dim );
+ int _RightNode( int node, int dim );
+
+public:
+ KNCube( const Configuration &config, const string & name, bool mesh );
+ static void RegisterRoutingFunctions();
+
+ int GetN( ) const;
+ int GetK( ) const;
+
+ double Capacity( ) const;
+
+ void InsertRandomFaults( const Configuration &config );
+
+};
+
+#endif
diff --git a/src/intersim2/networks/network.cpp b/src/intersim2/networks/network.cpp
new file mode 100644
index 0000000..2909429
--- /dev/null
+++ b/src/intersim2/networks/network.cpp
@@ -0,0 +1,290 @@
+// $Id: network.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*network.cpp
+ *
+ *This class is the basis of the entire network, it contains, all the routers
+ *channels in the network, and is extended by all the network topologies
+ *
+ */
+
+#include <cassert>
+#include <sstream>
+
+#include "booksim.hpp"
+#include "network.hpp"
+
+#include "kncube.hpp"
+#include "fly.hpp"
+#include "cmesh.hpp"
+#include "flatfly_onchip.hpp"
+#include "qtree.hpp"
+#include "tree4.hpp"
+#include "fattree.hpp"
+#include "anynet.hpp"
+#include "dragonfly.hpp"
+
+
+Network::Network( const Configuration &config, const string & name ) :
+ TimedModule( 0, name )
+{
+ _size = -1;
+ _nodes = -1;
+ _channels = -1;
+ _classes = config.GetInt("classes");
+}
+
+Network::~Network( )
+{
+ for ( int r = 0; r < _size; ++r ) {
+ if ( _routers[r] ) delete _routers[r];
+ }
+ for ( int s = 0; s < _nodes; ++s ) {
+ if ( _inject[s] ) delete _inject[s];
+ if ( _inject_cred[s] ) delete _inject_cred[s];
+ }
+ for ( int d = 0; d < _nodes; ++d ) {
+ if ( _eject[d] ) delete _eject[d];
+ if ( _eject_cred[d] ) delete _eject_cred[d];
+ }
+ for ( int c = 0; c < _channels; ++c ) {
+ if ( _chan[c] ) delete _chan[c];
+ if ( _chan_cred[c] ) delete _chan_cred[c];
+ }
+}
+
+Network * Network::New(const Configuration & config, const string & name)
+{
+ const string topo = config.GetStr( "topology" );
+ Network * n = NULL;
+ if ( topo == "torus" ) {
+ KNCube::RegisterRoutingFunctions() ;
+ n = new KNCube( config, name, false );
+ } else if ( topo == "mesh" ) {
+ KNCube::RegisterRoutingFunctions() ;
+ n = new KNCube( config, name, true );
+ } else if ( topo == "cmesh" ) {
+ CMesh::RegisterRoutingFunctions() ;
+ n = new CMesh( config, name );
+ } else if ( topo == "fly" ) {
+ KNFly::RegisterRoutingFunctions() ;
+ n = new KNFly( config, name );
+ } else if ( topo == "qtree" ) {
+ QTree::RegisterRoutingFunctions() ;
+ n = new QTree( config, name );
+ } else if ( topo == "tree4" ) {
+ Tree4::RegisterRoutingFunctions() ;
+ n = new Tree4( config, name );
+ } else if ( topo == "fattree" ) {
+ FatTree::RegisterRoutingFunctions() ;
+ n = new FatTree( config, name );
+ } else if ( topo == "flatfly" ) {
+ FlatFlyOnChip::RegisterRoutingFunctions() ;
+ n = new FlatFlyOnChip( config, name );
+ } else if ( topo == "anynet"){
+ AnyNet::RegisterRoutingFunctions() ;
+ n = new AnyNet(config, name);
+ } else if ( topo == "dragonflynew"){
+ DragonFlyNew::RegisterRoutingFunctions() ;
+ n = new DragonFlyNew(config, name);
+ } else {
+ cerr << "Unknown topology: " << topo << endl;
+ }
+
+ /*legacy code that insert random faults in the networks
+ *not sure how to use this
+ */
+ if ( n && ( config.GetInt( "link_failures" ) > 0 ) ) {
+ n->InsertRandomFaults( config );
+ }
+ return n;
+}
+
+void Network::_Alloc( )
+{
+ assert( ( _size != -1 ) &&
+ ( _nodes != -1 ) &&
+ ( _channels != -1 ) );
+
+ _routers.resize(_size);
+ gNodes = _nodes;
+
+ /*booksim used arrays of flits as the channels which makes have capacity of
+ *one. To simulate channel latency, flitchannel class has been added
+ *which are fifos with depth = channel latency and each cycle the channel
+ *shifts by one
+ *credit channels are the necessary counter part
+ */
+ _inject.resize(_nodes);
+ _inject_cred.resize(_nodes);
+ for ( int s = 0; s < _nodes; ++s ) {
+ ostringstream name;
+ name << Name() << "_fchan_ingress" << s;
+ _inject[s] = new FlitChannel(this, name.str(), _classes);
+ _inject[s]->SetSource(NULL, s);
+ _timed_modules.push_back(_inject[s]);
+ name.str("");
+ name << Name() << "_cchan_ingress" << s;
+ _inject_cred[s] = new CreditChannel(this, name.str());
+ _timed_modules.push_back(_inject_cred[s]);
+ }
+ _eject.resize(_nodes);
+ _eject_cred.resize(_nodes);
+ for ( int d = 0; d < _nodes; ++d ) {
+ ostringstream name;
+ name << Name() << "_fchan_egress" << d;
+ _eject[d] = new FlitChannel(this, name.str(), _classes);
+ _eject[d]->SetSink(NULL, d);
+ _timed_modules.push_back(_eject[d]);
+ name.str("");
+ name << Name() << "_cchan_egress" << d;
+ _eject_cred[d] = new CreditChannel(this, name.str());
+ _timed_modules.push_back(_eject_cred[d]);
+ }
+ _chan.resize(_channels);
+ _chan_cred.resize(_channels);
+ for ( int c = 0; c < _channels; ++c ) {
+ ostringstream name;
+ name << Name() << "_fchan_" << c;
+ _chan[c] = new FlitChannel(this, name.str(), _classes);
+ _timed_modules.push_back(_chan[c]);
+ name.str("");
+ name << Name() << "_cchan_" << c;
+ _chan_cred[c] = new CreditChannel(this, name.str());
+ _timed_modules.push_back(_chan_cred[c]);
+ }
+}
+
+void Network::ReadInputs( )
+{
+ for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin();
+ iter != _timed_modules.end();
+ ++iter) {
+ (*iter)->ReadInputs( );
+ }
+}
+
+void Network::Evaluate( )
+{
+ for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin();
+ iter != _timed_modules.end();
+ ++iter) {
+ (*iter)->Evaluate( );
+ }
+}
+
+void Network::WriteOutputs( )
+{
+ for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin();
+ iter != _timed_modules.end();
+ ++iter) {
+ (*iter)->WriteOutputs( );
+ }
+}
+
+void Network::WriteFlit( Flit *f, int source )
+{
+ assert( ( source >= 0 ) && ( source < _nodes ) );
+ _inject[source]->Send(f);
+}
+
+Flit *Network::ReadFlit( int dest )
+{
+ assert( ( dest >= 0 ) && ( dest < _nodes ) );
+ return _eject[dest]->Receive();
+}
+
+void Network::WriteCredit( Credit *c, int dest )
+{
+ assert( ( dest >= 0 ) && ( dest < _nodes ) );
+ _eject_cred[dest]->Send(c);
+}
+
+Credit *Network::ReadCredit( int source )
+{
+ assert( ( source >= 0 ) && ( source < _nodes ) );
+ return _inject_cred[source]->Receive();
+}
+
+void Network::InsertRandomFaults( const Configuration &config )
+{
+ Error( "InsertRandomFaults not implemented for this topology!" );
+}
+
+void Network::OutChannelFault( int r, int c, bool fault )
+{
+ assert( ( r >= 0 ) && ( r < _size ) );
+ _routers[r]->OutChannelFault( c, fault );
+}
+
+double Network::Capacity( ) const
+{
+ return 1.0;
+}
+
+/* this function can be heavily modified to display any information
+ * neceesary of the network, by default, call display on each router
+ * and display the channel utilization rate
+ */
+void Network::Display( ostream & os ) const
+{
+ for ( int r = 0; r < _size; ++r ) {
+ _routers[r]->Display( os );
+ }
+}
+
+void Network::DumpChannelMap( ostream & os, string const & prefix ) const
+{
+ os << prefix << "source_router,source_port,dest_router,dest_port" << endl;
+ for(int c = 0; c < _nodes; ++c)
+ os << prefix
+ << "-1,"
+ << _inject[c]->GetSourcePort() << ','
+ << _inject[c]->GetSink()->GetID() << ','
+ << _inject[c]->GetSinkPort() << endl;
+ for(int c = 0; c < _channels; ++c)
+ os << prefix
+ << _chan[c]->GetSource()->GetID() << ','
+ << _chan[c]->GetSourcePort() << ','
+ << _chan[c]->GetSink()->GetID() << ','
+ << _chan[c]->GetSinkPort() << endl;
+ for(int c = 0; c < _nodes; ++c)
+ os << prefix
+ << _eject[c]->GetSource()->GetID() << ','
+ << _eject[c]->GetSourcePort() << ','
+ << "-1,"
+ << _eject[c]->GetSinkPort() << endl;
+}
+
+void Network::DumpNodeMap( ostream & os, string const & prefix ) const
+{
+ os << prefix << "source_router,dest_router" << endl;
+ for(int s = 0; s < _nodes; ++s)
+ os << prefix
+ << _eject[s]->GetSource()->GetID() << ','
+ << _inject[s]->GetSink()->GetID() << endl;
+}
diff --git a/src/intersim2/networks/network.hpp b/src/intersim2/networks/network.hpp
new file mode 100644
index 0000000..fcf0253
--- /dev/null
+++ b/src/intersim2/networks/network.hpp
@@ -0,0 +1,118 @@
+// $Id: network.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _NETWORK_HPP_
+#define _NETWORK_HPP_
+
+#include <vector>
+#include <deque>
+
+#include "module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "router.hpp"
+#include "module.hpp"
+#include "timed_module.hpp"
+#include "flitchannel.hpp"
+#include "channel.hpp"
+#include "config_utils.hpp"
+#include "globals.hpp"
+
+typedef Channel<Credit> CreditChannel;
+
+
+class Network : public TimedModule {
+protected:
+
+ int _size;
+ int _nodes;
+ int _channels;
+ int _classes;
+
+ vector<Router *> _routers;
+
+ vector<FlitChannel *> _inject;
+ vector<CreditChannel *> _inject_cred;
+
+ vector<FlitChannel *> _eject;
+ vector<CreditChannel *> _eject_cred;
+
+ vector<FlitChannel *> _chan;
+ vector<CreditChannel *> _chan_cred;
+
+ deque<TimedModule *> _timed_modules;
+
+ virtual void _ComputeSize( const Configuration &config ) = 0;
+ virtual void _BuildNet( const Configuration &config ) = 0;
+
+ void _Alloc( );
+
+public:
+ Network( const Configuration &config, const string & name );
+ virtual ~Network( );
+
+ static Network *New( const Configuration &config, const string & name );
+
+ virtual void WriteFlit( Flit *f, int source );
+ virtual Flit *ReadFlit( int dest );
+
+ virtual void WriteCredit( Credit *c, int dest );
+ virtual Credit *ReadCredit( int source );
+
+ inline int NumNodes( ) const {return _nodes;}
+
+ virtual void InsertRandomFaults( const Configuration &config );
+ void OutChannelFault( int r, int c, bool fault = true );
+
+ virtual double Capacity( ) const;
+
+ virtual void ReadInputs( );
+ virtual void Evaluate( );
+ virtual void WriteOutputs( );
+
+ void Display( ostream & os = cout ) const;
+ void DumpChannelMap( ostream & os = cout, string const & prefix = "" ) const;
+ void DumpNodeMap( ostream & os = cout, string const & prefix = "" ) const;
+
+ int NumChannels() const {return _channels;}
+ const vector<FlitChannel *> & GetInject() {return _inject;}
+ FlitChannel * GetInject(int index) {return _inject[index];}
+ const vector<CreditChannel *> & GetInjectCred() {return _inject_cred;}
+ CreditChannel * GetInjectCred(int index) {return _inject_cred[index];}
+ const vector<FlitChannel *> & GetEject(){return _eject;}
+ FlitChannel * GetEject(int index) {return _eject[index];}
+ const vector<CreditChannel *> & GetEjectCred(){return _eject_cred;}
+ CreditChannel * GetEjectCred(int index) {return _eject_cred[index];}
+ const vector<FlitChannel *> & GetChannels(){return _chan;}
+ const vector<CreditChannel *> & GetChannelsCred(){return _chan_cred;}
+ const vector<Router *> & GetRouters(){return _routers;}
+ Router * GetRouter(int index) {return _routers[index];}
+ int NumRouters() const {return _size;}
+};
+
+#endif
+
diff --git a/src/intersim2/networks/qtree.cpp b/src/intersim2/networks/qtree.cpp
new file mode 100644
index 0000000..7214947
--- /dev/null
+++ b/src/intersim2/networks/qtree.cpp
@@ -0,0 +1,187 @@
+// $Id: qtree.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// QTree: A Quad-Tree Indirect Network.
+//
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/05/17 17:14:07 $
+// $Id: qtree.cpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include "qtree.hpp"
+#include "misc_utils.hpp"
+
+QTree::QTree( const Configuration& config, const string & name )
+: Network ( config, name )
+{
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+
+void QTree::_ComputeSize( const Configuration& config )
+{
+
+ _k = config.GetInt( "k" );
+ _n = config.GetInt( "n" );
+
+ assert( _k == 4 && _n == 3 );
+
+ gK = _k; gN = _n;
+
+ _nodes = powi( _k, _n );
+
+ _size = 0;
+ for (int i = 0; i < _n; i++)
+ _size += powi( _k, i );
+
+ _channels = 0;
+ for (int j = 1; j < _n; j++)
+ _channels += 2 * powi( _k, j );
+
+}
+
+void QTree::RegisterRoutingFunctions(){
+
+}
+
+void QTree::_BuildNet( const Configuration& config )
+{
+
+ ostringstream routerName;
+ int h, r, pos, port;
+
+ for (h = 0; h < _n; h++) {
+ for (pos = 0 ; pos < powi( _k, h ) ; ++pos ) {
+
+ int id = h * 256 + pos;
+ r = _RouterIndex( h, pos );
+
+ routerName << "router_" << h << "_" << pos;
+
+ int d = ( h == 0 ) ? _k : _k + 1;
+ _routers[r] = Router::NewRouter( config, this,
+ routerName.str( ),
+ id, d, d);
+ _timed_modules.push_back(_routers[r]);
+ routerName.str("");
+ }
+ }
+
+ // Injection & Ejection Channels
+ for ( pos = 0 ; pos < powi( _k, _n-1 ) ; ++pos ) {
+ r = _RouterIndex( _n-1, pos );
+ for ( port = 0 ; port < _k ; port++ ) {
+
+ _routers[r]->AddInputChannel( _inject[_k*pos+port],
+ _inject_cred[_k*pos+port]);
+
+ _routers[r]->AddOutputChannel( _eject[_k*pos+port],
+ _eject_cred[_k*pos+port]);
+ }
+ }
+
+ int c;
+ for ( h = 0 ; h < _n ; ++h ) {
+ for ( pos = 0 ; pos < powi( _k, h ) ; ++pos ) {
+ for ( port = 0 ; port < _k ; port++ ) {
+
+ r = _RouterIndex( h, pos );
+
+ if ( h < _n-1 ) {
+ // Channels to Children Nodes
+ c = _InputIndex( h , pos, port );
+ _routers[r]->AddInputChannel( _chan[c],
+ _chan_cred[c] );
+
+ c = _OutputIndex( h, pos, port );
+ _routers[r]->AddOutputChannel( _chan[c],
+ _chan_cred[c] );
+
+ }
+ }
+ if ( h > 0 ) {
+ // Channels to Parent Nodes
+ c = _OutputIndex( h - 1, pos / _k, pos % _k );
+ _routers[r]->AddInputChannel( _chan[c],
+ _chan_cred[c] );
+
+ c = _InputIndex( h - 1, pos / _k, pos % _k );
+ _routers[r]->AddOutputChannel( _chan[c],
+ _chan_cred[c]);
+ }
+ }
+ }
+}
+
+int QTree::_RouterIndex( int height, int pos )
+{
+ int r = 0;
+ for ( int h = 0; h < height; h++ )
+ r += powi( _k, h );
+ return (r + pos);
+}
+
+int QTree::_InputIndex( int height, int pos, int port )
+{
+ assert( height >= 0 && height < powi( _k,_n-1 ) );
+ int c = 0;
+ for ( int h = 0; h < height; h++)
+ c += powi( _k, h+1 );
+ return ( c + _k * pos + port );
+}
+
+int QTree::_OutputIndex( int height, int pos, int port )
+{
+ assert( height >= 0 && height < powi( _k,_n-1 ) );
+ int c = _channels / 2;
+ for ( int h = 0; h < height; h++)
+ c += powi( _k, h+1 );
+ return ( c + _k * pos + port );
+}
+
+
+int QTree::HeightFromID( int id )
+{
+ return id / 256;
+}
+
+int QTree::PosFromID( int id )
+{
+ return id % 256;
+}
diff --git a/src/intersim2/networks/qtree.hpp b/src/intersim2/networks/qtree.hpp
new file mode 100644
index 0000000..0a31a92
--- /dev/null
+++ b/src/intersim2/networks/qtree.hpp
@@ -0,0 +1,69 @@
+// $Id: qtree.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// QTree: A Quad-Tree Indirect Network.
+//
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/05/17 17:14:07 $
+// $Id: qtree.hpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifndef _QTREE_HPP_
+#define _QTREE_HPP_
+#include <cassert>
+#include "network.hpp"
+
+class QTree : public Network {
+
+ int _k;
+ int _n;
+
+ void _ComputeSize( const Configuration& config );
+ void _BuildNet( const Configuration& config );
+
+ int _RouterIndex( int height, int pos );
+ int _InputIndex( int height, int pos, int port );
+ int _OutputIndex( int height, int pos, int port );
+
+public:
+
+ QTree( const Configuration& config, const string & name );
+ static void RegisterRoutingFunctions() ;
+
+ static int HeightFromID( int id );
+ static int PosFromID( int id );
+
+};
+
+#endif
diff --git a/src/intersim2/networks/tree4.cpp b/src/intersim2/networks/tree4.cpp
new file mode 100644
index 0000000..5650fe4
--- /dev/null
+++ b/src/intersim2/networks/tree4.cpp
@@ -0,0 +1,289 @@
+// $Id: tree4.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// Tree4: Network with 64 Terminal Nodes arranged in a tree topology
+// with 4 routers at the root of the tree
+//
+// Level 0 : 4 8 x 8 Routers (8 Descending Links per Router)
+// Level 1 : 8 8 x 8 Routers (4 Descending Links per Router)
+// Level 2 : 16 6 x 6 Routers (4 Descending Links per Router)
+// Level 3 : 64 Terminal Nodes
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/06/26 22:49:23 $
+// $Id: tree4.cpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+#include <cmath>
+
+#include "tree4.hpp"
+#include "misc_utils.hpp"
+
+Tree4::Tree4( const Configuration& config, const string & name )
+: Network ( config, name )
+{
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void Tree4::_ComputeSize( const Configuration& config )
+{
+ int h;
+
+ _k = config.GetInt( "k" );
+ assert(_k == 4);
+ _n = config.GetInt( "n" );
+ assert(_n == 3);
+
+ gK = _k; gN = _n;
+
+ _nodes = powi( _k, _n );
+
+ _size = 0;
+ for ( h = 0; h < _n; ++h )
+ _size += (4 >> h) * powi( _k, h );
+
+ _channels = 2 // Two Channels per Connection
+ * ( 2 * powi( _k, 1) ) // Number of Middle Routers
+ * ( 2 * _k ); // Connectivity of Middle Routers
+}
+
+void Tree4::RegisterRoutingFunctions(){
+
+}
+
+void Tree4::_BuildNet( const Configuration& config )
+{
+
+ //
+ // Allocate Routers
+ //
+ ostringstream name;
+ int h, pos, nPos, degree, id;
+
+ for ( h = 0; h < _n; h++ ) {
+ nPos = (4 >> h) * powi( _k, h );
+ for ( pos = 0; pos < nPos; ++pos) {
+ if ( h < _n-1 )
+ degree = 8;
+ else
+ degree = 6;
+
+ name.str("");
+ name << "router_" << h << "_" << pos;
+ id = h * powi( _k, _n-1 ) + pos;
+ Router * r = Router::NewRouter( config, this, name.str( ),
+ id, degree, degree );
+ _Router( h, pos ) = r;
+ _timed_modules.push_back(r);
+ }
+ }
+
+ //
+ // Connect Channels to Routers
+ //
+ int pp, pc;
+ //
+ // Connection Rule: Output Ports 0:3 Move DOWN Network
+ // Output Ports 4:7 Move UP Network
+ //
+
+ // Injection & Ejection Channels
+ nPos = powi( _k, _n - 1 );
+ for ( pos = 0 ; pos < nPos ; ++pos ) {
+ for ( int port = 0 ; port < _k ; ++port ) {
+
+ _Router( _n-1, pos)->AddInputChannel( _inject[_k*pos+port],
+ _inject_cred[_k*pos+port]);
+
+
+ _inject[_k*pos+port]->SetLatency( 1 );
+ _inject_cred[_k*pos+port]->SetLatency( 1 );
+
+ _Router( _n-1, pos)->AddOutputChannel( _eject[_k*pos+port],
+ _eject_cred[_k*pos+port]);
+
+ _eject[_k*pos+port]->SetLatency( 1 );
+ _eject_cred[_k*pos+port]->SetLatency( 1 );
+
+ }
+ }
+
+ // Connections between h = 1 and h = 2 Levels
+ int c = 0;
+ nPos = 2 * powi( _k, 1 );
+ for ( pos = 0; pos < nPos; ++pos ) {
+ for ( int port = 0; port < _k; ++port ) {
+
+ pp = pos;
+ pc = _k * ( pos / 2 ) + port;
+
+ // cout << "connecting (1,"<<pp<<") <-> (2,"<<pc<<")"<<endl;
+
+ _Router( 1, pp)->AddOutputChannel( _chan[c], _chan_cred[c] );
+ _Router( 2, pc)->AddInputChannel( _chan[c], _chan_cred[c] );
+
+ //_chan[c]->SetLatency( L );
+ //_chan_cred[c]->SetLatency( L );
+
+ _chan[c]->SetLatency( 1 );
+ _chan_cred[c]->SetLatency( 1 );
+
+ c++;
+
+ _Router(1, pp)->AddInputChannel( _chan[c], _chan_cred[c] );
+ _Router(2, pc)->AddOutputChannel( _chan[c], _chan_cred[c] );
+
+ //_chan[c]->SetLatency( L );
+ //_chan_cred[c]->SetLatency( L );
+ _chan[c]->SetLatency( 1 );
+ _chan_cred[c]->SetLatency( 1 );
+
+ c++;
+ }
+ }
+
+ // Connections between h = 0 and h = 1 Levels
+ nPos = 4 * powi( _k, 0 );
+ for ( pos = 0; pos < nPos; ++pos ) {
+ for ( int port = 0; port < 2 * _k; ++port ) {
+ pp = pos;
+ pc = port;
+
+ // cout << "connecting (0,"<<pp<<") <-> (1,"<<pc<<")"<<endl;
+
+ _Router(0, pp)->AddOutputChannel( _chan[c], _chan_cred[c] );
+ _Router(1, pc)->AddInputChannel( _chan[c], _chan_cred[c] );
+
+ // _chan[c]->SetLatency( L );
+ //_chan_cred[c]->SetLatency( L );
+ _chan[c]->SetLatency( 1 );
+ _chan_cred[c]->SetLatency( 1 );
+
+ c++;
+
+ _Router(0, pp)->AddInputChannel( _chan[c], _chan_cred[c] );
+ _Router(1, pc)->AddOutputChannel( _chan[c], _chan_cred[c] );
+
+ // _chan[c]->SetLatency( L );
+ // _chan_cred[c]->SetLatency( L );
+ _chan[c]->SetLatency( 1 );
+ _chan_cred[c]->SetLatency( 1 );
+ c++;
+ }
+ }
+
+ // cout << "Used " << c << " of " << _channels << " channels" << endl;
+
+}
+
+Router*& Tree4::_Router( int height, int pos )
+{
+ assert( height < _n );
+ assert( pos < (4 >> height) * powi( _k, height) );
+
+ int i = 0;
+ for ( int h = 0; h < height; ++h )
+ i += (4 >> h) * powi( _k, h );
+ return _routers[i+pos];
+
+}
+
+int Tree4::_WireLatency( int height1, int pos1, int height2, int pos2 )
+{
+ int heightChild, heightParent, posChild, posParent;
+
+ int L;
+
+ if (height1 < height2) {
+ heightChild = height2;
+ posChild = pos2;
+ heightParent = height1;
+ posParent = pos1;
+ } else {
+ heightChild = height1;
+ posChild = pos1;
+ heightParent = height2;
+ posParent = pos2;
+ }
+
+ int _length_d2_d1 = 2 ;
+ int _length_d1_d0_0 = 2 ;
+ int _length_d1_d0_1 = 2 ;
+ int _length_d1_d0_2 = 6 ;
+ int _length_d1_d0_3 = 6 ;
+
+ assert( heightChild == heightParent+1 );
+
+ // We must decrement the delays by one to account for how the
+ // simulator interprets the specified delay (with 0 indicating one
+ // cycle of delay).
+
+ if ( heightChild == 2 )
+ L = _length_d2_d1;
+ else {
+ if ( posChild == 0 || posChild == 6 )
+ switch ( posParent ) {
+ case 0: L =_length_d1_d0_0; break;
+ case 1: L =_length_d1_d0_1; break;
+ case 2: L =_length_d1_d0_2; break;
+ case 3: L =_length_d1_d0_3; break;
+ }
+ if ( posChild == 1 || posChild == 7 )
+ switch ( posParent ) {
+ case 0: L =_length_d1_d0_3; break;
+ case 1: L =_length_d1_d0_2; break;
+ case 2: L =_length_d1_d0_1; break;
+ case 3: L =_length_d1_d0_0; break;
+ }
+ if ( posChild == 2 || posChild == 4 )
+ switch ( posParent ) {
+ case 0: L = _length_d1_d0_0; break;
+ case 1: L = _length_d1_d0_1; break;
+ case 2: L = _length_d1_d0_2; break;
+ case 3: L = _length_d1_d0_3; break;
+ }
+ if ( posChild == 3|| posChild == 5 )
+ switch ( posParent ) {
+ case 0: L =_length_d1_d0_3; break;
+ case 1: L =_length_d1_d0_2; break;
+ case 2: L =_length_d1_d0_1; break;
+ case 3: L =_length_d1_d0_0; break;
+ }
+ }
+ return L;
+}
diff --git a/src/intersim2/networks/tree4.hpp b/src/intersim2/networks/tree4.hpp
new file mode 100644
index 0000000..76e5be8
--- /dev/null
+++ b/src/intersim2/networks/tree4.hpp
@@ -0,0 +1,72 @@
+// $Id: tree4.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+////////////////////////////////////////////////////////////////////////
+//
+// Tree4: Network with 64 Terminal Nodes arranged in a tree topology
+// with 4 routers at the root of the tree
+//
+////////////////////////////////////////////////////////////////////////
+//
+// RCS Information:
+// $Author: jbalfour $
+// $Date: 2007/06/26 22:49:23 $
+// $Id: tree4.hpp 5188 2012-08-30 00:31:31Z dub $
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifndef _TREE4_HPP_
+#define _TREE4_HPP_
+#include <cassert>
+#include "network.hpp"
+
+class Tree4 : public Network {
+
+ int _k;
+ int _n;
+
+ int _channelWidth;
+
+ void _ComputeSize( const Configuration& config );
+ void _BuildNet( const Configuration& config );
+
+
+ Router*& _Router( int height, int pos );
+
+ int _WireLatency( int height1, int pos1, int height2, int pos2 );
+
+public:
+
+ Tree4( const Configuration& config, const string & name );
+ static void RegisterRoutingFunctions() ;
+
+ static int HeightFromID( int id );
+ static int PosFromID( int id );
+ static int SpeedUp( int height );
+};
+
+#endif
diff --git a/src/intersim2/outputset.cpp b/src/intersim2/outputset.cpp
new file mode 100644
index 0000000..1b50a1a
--- /dev/null
+++ b/src/intersim2/outputset.cpp
@@ -0,0 +1,153 @@
+// $Id: outputset.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*outputset.cpp
+ *
+ *output set assigns a flit which output to go to in a router
+ *used by the VC class
+ *the output assignment is done by the routing algorithms..
+ *
+ */
+
+#include <cassert>
+
+#include "booksim.hpp"
+#include "outputset.hpp"
+
+void OutputSet::Clear( )
+{
+ _outputs.clear( );
+}
+
+void OutputSet::Add( int output_port, int vc, int pri )
+{
+ AddRange( output_port, vc, vc, pri );
+}
+
+void OutputSet::AddRange( int output_port, int vc_start, int vc_end, int pri )
+{
+
+ sSetElement s;
+
+ s.vc_start = vc_start;
+ s.vc_end = vc_end;
+ s.pri = pri;
+ s.output_port = output_port;
+ _outputs.insert( s );
+}
+
+//legacy support, for performance, just use GetSet()
+int OutputSet::NumVCs( int output_port ) const
+{
+ int total = 0;
+ set<sSetElement>::const_iterator i = _outputs.begin( );
+ while(i!=_outputs.end( )){
+ if(i->output_port == output_port){
+ total += (i->vc_end - i->vc_start + 1);
+ }
+ i++;
+ }
+ return total;
+}
+
+bool OutputSet::OutputEmpty( int output_port ) const
+{
+ set<sSetElement>::const_iterator i = _outputs.begin( );
+ while(i!=_outputs.end( )){
+ if(i->output_port == output_port){
+ return false;
+ }
+ i++;
+ }
+ return true;
+}
+
+
+const set<OutputSet::sSetElement> & OutputSet::GetSet() const{
+ return _outputs;
+}
+
+//legacy support, for performance, just use GetSet()
+int OutputSet::GetVC( int output_port, int vc_index, int *pri ) const
+{
+
+ int range;
+ int remaining = vc_index;
+ int vc = -1;
+
+ if ( pri ) { *pri = -1; }
+
+ set<sSetElement>::const_iterator i = _outputs.begin( );
+ while(i!=_outputs.end( )){
+ if(i->output_port == output_port){
+ range = i->vc_end - i->vc_start + 1;
+ if ( remaining >= range ) {
+ remaining -= range;
+ } else {
+ vc = i->vc_start + remaining;
+ if ( pri ) {
+ *pri = i->pri;
+ }
+ break;
+ }
+ }
+ i++;
+ }
+ return vc;
+}
+
+//legacy support, for performance, just use GetSet()
+bool OutputSet::GetPortVC( int *out_port, int *out_vc ) const
+{
+
+
+ bool single_output = false;
+ int used_outputs = 0;
+
+ set<sSetElement>::const_iterator i = _outputs.begin( );
+ if(i!=_outputs.end( )){
+ used_outputs = i->output_port;
+ }
+ while(i!=_outputs.end( )){
+
+ if ( i->vc_start == i->vc_end ) {
+ *out_vc = i->vc_start;
+ *out_port = i->output_port;
+ single_output = true;
+ } else {
+ // multiple vc's selected
+ break;
+ }
+ if (used_outputs != i->output_port) {
+ // multiple outputs selected
+ single_output = false;
+ break;
+ }
+ i++;
+ }
+ return single_output;
+}
diff --git a/src/intersim2/outputset.hpp b/src/intersim2/outputset.hpp
new file mode 100644
index 0000000..7f3e0fd
--- /dev/null
+++ b/src/intersim2/outputset.hpp
@@ -0,0 +1,66 @@
+// $Id: outputset.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _OUTPUTSET_HPP_
+#define _OUTPUTSET_HPP_
+
+#include <set>
+
+class OutputSet {
+
+
+public:
+ struct sSetElement {
+ int vc_start;
+ int vc_end;
+ int pri;
+ int output_port;
+ };
+
+ void Clear( );
+ void Add( int output_port, int vc, int pri = 0 );
+ void AddRange( int output_port, int vc_start, int vc_end, int pri = 0 );
+
+ bool OutputEmpty( int output_port ) const;
+ int NumVCs( int output_port ) const;
+
+ const set<sSetElement> & GetSet() const;
+
+ int GetVC( int output_port, int vc_index, int *pri = 0 ) const;
+ bool GetPortVC( int *out_port, int *out_vc ) const;
+private:
+ set<sSetElement> _outputs;
+};
+
+inline bool operator<(const OutputSet::sSetElement & se1,
+ const OutputSet::sSetElement & se2) {
+ return se1.pri > se2.pri; // higher priorities first!
+}
+
+#endif
+
+
diff --git a/src/intersim2/packet_reply_info.cpp b/src/intersim2/packet_reply_info.cpp
new file mode 100644
index 0000000..7372882
--- /dev/null
+++ b/src/intersim2/packet_reply_info.cpp
@@ -0,0 +1,57 @@
+// $Id: packet_reply_info.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "packet_reply_info.hpp"
+
+stack<PacketReplyInfo*> PacketReplyInfo::_all;
+stack<PacketReplyInfo*> PacketReplyInfo::_free;
+
+PacketReplyInfo * PacketReplyInfo::New()
+{
+ PacketReplyInfo * pr;
+ if(_free.empty()) {
+ pr = new PacketReplyInfo();
+ _all.push(pr);
+ } else {
+ pr = _free.top();
+ _free.pop();
+ }
+ return pr;
+}
+
+void PacketReplyInfo::Free()
+{
+ _free.push(this);
+}
+
+void PacketReplyInfo::FreeAll()
+{
+ while(!_all.empty()) {
+ delete _all.top();
+ _all.pop();
+ }
+}
diff --git a/src/intersim2/packet_reply_info.hpp b/src/intersim2/packet_reply_info.hpp
new file mode 100644
index 0000000..392dc85
--- /dev/null
+++ b/src/intersim2/packet_reply_info.hpp
@@ -0,0 +1,57 @@
+// $Id: packet_reply_info.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _PACKET_REPLY_INFO_HPP_
+#define _PACKET_REPLY_INFO_HPP_
+
+#include <stack>
+
+#include "flit.hpp"
+
+//register the requests to a node
+class PacketReplyInfo {
+
+public:
+ int source;
+ int time;
+ bool record;
+ Flit::FlitType type;
+
+ static PacketReplyInfo* New();
+ void Free();
+ static void FreeAll();
+
+private:
+
+ static stack<PacketReplyInfo*> _all;
+ static stack<PacketReplyInfo*> _free;
+
+ PacketReplyInfo() {}
+ ~PacketReplyInfo() {}
+};
+
+#endif
diff --git a/src/intersim2/pipefifo.hpp b/src/intersim2/pipefifo.hpp
new file mode 100644
index 0000000..03563b5
--- /dev/null
+++ b/src/intersim2/pipefifo.hpp
@@ -0,0 +1,97 @@
+// $Id: pipefifo.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _PIPEFIFO_HPP_
+#define _PIPEFIFO_HPP_
+
+#include <vector>
+
+#include "module.hpp"
+
+template<class T> class PipelineFIFO : public Module {
+ int _lanes;
+ int _depth;
+
+ int _pipe_len;
+ int _pipe_ptr;
+
+ vector<vector<T*> > _data;
+
+public:
+ PipelineFIFO( Module *parent, const string& name, int lanes, int depth );
+ ~PipelineFIFO( );
+
+ void Write( T* val, int lane = 0 );
+ void WriteAll( T* val );
+
+ T* Read( int lane = 0 );
+
+ void Advance( );
+};
+
+template<class T> PipelineFIFO<T>::PipelineFIFO( Module *parent,
+ const string& name,
+ int lanes, int depth ) :
+ Module( parent, name ),
+ _lanes( lanes ), _depth( depth )
+{
+ _pipe_len = depth + 1;
+ _pipe_ptr = 0;
+
+ _data.resize(_lanes);
+ for ( int l = 0; l < _lanes; ++l ) {
+ _data[l].resize(_pipe_len, 0);
+ }
+}
+
+template<class T> PipelineFIFO<T>::~PipelineFIFO( )
+{
+}
+
+template<class T> void PipelineFIFO<T>::Write( T* val, int lane )
+{
+ _data[lane][_pipe_ptr] = val;
+}
+
+template<class T> void PipelineFIFO<T>::WriteAll( T* val )
+{
+ for ( int l = 0; l < _lanes; ++l ) {
+ _data[l][_pipe_ptr] = val;
+ }
+}
+
+template<class T> T* PipelineFIFO<T>::Read( int lane )
+{
+ return _data[lane][_pipe_ptr];
+}
+
+template<class T> void PipelineFIFO<T>::Advance( )
+{
+ _pipe_ptr = ( _pipe_ptr + 1 ) % _pipe_len;
+}
+
+#endif
diff --git a/src/intersim2/power/buffer_monitor.cpp b/src/intersim2/power/buffer_monitor.cpp
new file mode 100644
index 0000000..aaf71f0
--- /dev/null
+++ b/src/intersim2/power/buffer_monitor.cpp
@@ -0,0 +1,71 @@
+// $Id: buffer_monitor.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "buffer_monitor.hpp"
+
+#include "flit.hpp"
+
+BufferMonitor::BufferMonitor( int inputs, int classes )
+: _cycles(0), _inputs(inputs), _classes(classes) {
+ _reads.resize(inputs * classes, 0) ;
+ _writes.resize(inputs * classes, 0) ;
+}
+
+int BufferMonitor::index( int input, int cl ) const {
+ assert((input >= 0) && (input < _inputs));
+ assert((cl >= 0) && (cl < _classes));
+ return cl + _classes * input ;
+}
+
+void BufferMonitor::cycle() {
+ _cycles++ ;
+}
+
+void BufferMonitor::write( int input, Flit const * f ) {
+ _writes[ index(input, f->cl) ]++ ;
+}
+
+void BufferMonitor::read( int input, Flit const * f ) {
+ _reads[ index(input, f->cl) ]++ ;
+}
+
+void BufferMonitor::display(ostream & os) const {
+ for ( int i = 0 ; i < _inputs ; i++ ) {
+ os << "[ " << i << " ] " ;
+ for ( int c = 0 ; c < _classes ; c++ ) {
+ os << "Type=" << c
+ << ":(R#" << _reads[ index( i, c) ] << ","
+ << "W#" << _writes[ index( i, c) ] << ")" << " " ;
+ }
+ os << endl ;
+ }
+}
+
+ostream & operator<<( ostream & os, BufferMonitor const & obj ) {
+ obj.display(os);
+ return os ;
+}
diff --git a/src/intersim2/power/buffer_monitor.hpp b/src/intersim2/power/buffer_monitor.hpp
new file mode 100644
index 0000000..41b719f
--- /dev/null
+++ b/src/intersim2/power/buffer_monitor.hpp
@@ -0,0 +1,68 @@
+// $Id: buffer_monitor.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _BUFFER_MONITOR_HPP_
+#define _BUFFER_MONITOR_HPP_
+
+#include <vector>
+#include <iostream>
+
+using namespace std;
+
+class Flit;
+
+class BufferMonitor {
+ int _cycles ;
+ int _inputs ;
+ int _classes ;
+ vector<int> _reads ;
+ vector<int> _writes ;
+ int index( int input, int cl ) const ;
+public:
+ BufferMonitor( int inputs, int classes ) ;
+ void cycle() ;
+ void write( int input, Flit const * f ) ;
+ void read( int input, Flit const * f ) ;
+ inline const vector<int> & GetReads() const {
+ return _reads;
+ }
+ inline const vector<int> & GetWrites() const {
+ return _writes;
+ }
+ inline int NumInputs() const {
+ return _inputs;
+ }
+ inline int NumClasses() const {
+ return _classes;
+ }
+ void display(ostream & os) const;
+
+} ;
+
+ostream & operator<<( ostream & os, BufferMonitor const & obj ) ;
+
+#endif
diff --git a/src/intersim2/power/power_module.cpp b/src/intersim2/power/power_module.cpp
new file mode 100644
index 0000000..e319f4b
--- /dev/null
+++ b/src/intersim2/power/power_module.cpp
@@ -0,0 +1,532 @@
+// $Id: power_module.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "power_module.hpp"
+#include "booksim_config.hpp"
+#include "buffer_monitor.hpp"
+#include "switch_monitor.hpp"
+#include "iq_router.hpp"
+
+Power_Module::Power_Module(Network * n , const Configuration &config)
+ : Module( 0, "power_module" ){
+
+
+ string pfile = config.GetStr("tech_file");
+ PowerConfig pconfig;
+ pconfig.ParseFile(pfile);
+
+ net = n;
+ output_file_name = config.GetStr("power_output_file");
+ classes = config.GetInt("classes");
+ channel_width = (double)config.GetInt("channel_width");
+ channel_sweep = (double)config.GetInt("channel_sweep");
+
+ numVC = (double)config.GetInt("num_vcs");
+ depthVC = (double)config.GetInt("vc_buf_size");
+
+ //////////////////////////////////Constants/////////////////////////////
+ //wire length in (mm)
+ wire_length = pconfig.GetFloat("wire_length");
+ //////////Metal Parameters////////////
+ // Wire left/right coupling capacitance [ F/mm ]
+ Cw_cpl = pconfig.GetFloat("Cw_cpl");
+ // Wire up/down groudn capacitance [ F/mm ]
+ Cw_gnd = pconfig.GetFloat("Cw_gnd");
+ Cw = 2.0 * Cw_cpl + 2.0 * Cw_gnd ;
+ Rw = pconfig.GetFloat("Rw");
+ // metal pitch [mm]
+ MetalPitch = pconfig.GetFloat("MetalPitch");
+
+ //////////Device Parameters////////////
+
+ LAMBDA = pconfig.GetFloat("LAMBDA") ; // [um/LAMBDA]
+ Cd = pconfig.GetFloat("Cd"); // [F/um] (for Delay)
+ Cg = pconfig.GetFloat("Cg"); // [F/um] (for Delay)
+ Cgdl = pconfig.GetFloat("Cgdl"); // [F/um] (for Delay)
+
+ Cd_pwr = pconfig.GetFloat("Cd_pwr") ; // [F/um] (for Power)
+ Cg_pwr = pconfig.GetFloat("Cg_pwr") ; // [F/um] (for Power)
+
+ IoffN = pconfig.GetFloat("IoffN"); // [A/um]
+ IoffP = pconfig.GetFloat("IoffP"); // [A/um]
+ // Leakage from bitlines, two-port cell [A]
+ IoffSRAM = pconfig.GetFloat("IoffSRAM");
+ // [Ohm] ( D1=1um Inverter)
+ R = pconfig.GetFloat("R");
+ // [F] ( D1=1um Inverter - for Power )
+ Ci_delay = (1.0 + 2.0) * ( Cg + Cgdl );
+ // [F] ( D1=1um Inverter - for Power )
+ Co_delay = (1.0 + 2.0) * Cd ;
+
+
+ Ci = (1.0 + 2.0) * Cg_pwr ;
+ Co = (1.0 + 2.0) * Cd_pwr ;
+
+ Vdd = pconfig.GetFloat("Vdd");
+ FO4 = R * ( 3.0 * Cd + 12 * Cg + 12 * Cgdl);
+ tCLK = 20 * FO4;
+ fCLK = 1.0 / tCLK;
+
+ H_INVD2=(double)pconfig.GetInt("H_INVD2");
+ W_INVD2=(double)pconfig.GetInt("W_INVD2") ;
+ H_DFQD1=(double)pconfig.GetInt("H_DFQD1");
+ W_DFQD1= (double)pconfig.GetInt("W_DFQD1");
+ H_ND2D1= (double)pconfig.GetInt("H_ND2D1");
+ W_ND2D1=(double)pconfig.GetInt("W_ND2D1");
+ H_SRAM=(double)pconfig.GetInt("H_SRAM");
+ W_SRAM=(double)pconfig.GetInt("W_SRAM");
+
+ ChannelPitch = 2.0 * MetalPitch ;
+ CrossbarPitch = 2.0 * MetalPitch ;
+}
+
+Power_Module::~Power_Module(){
+
+
+}
+
+
+//////////////////////////////////////////////
+//Channels
+//////////////////////////////////////////////
+
+void Power_Module::calcChannel(const FlitChannel* f){
+ double channelLength = f->GetLatency()* wire_length;
+ wire const this_wire = wireOptimize(channelLength);
+ double const & K = this_wire.K;
+ double const & N = this_wire.N;
+ double const & M = this_wire.M;
+ //area
+ channelArea += areaChannel(K,N,M);
+
+ //activity factor;
+ const vector<int> temp = f->GetActivity();
+ vector<double> a(classes);
+ for(int i = 0; i< classes; i++){
+
+ a[i] = ((double)temp[i])/totalTime;
+ }
+
+ //power calculation
+ double const bitPower = powerRepeatedWire(channelLength, K,M,N);
+
+ channelClkPower += powerWireClk(M,channel_width);
+ for(int i = 0; i< classes; i++){
+ channelWirePower += bitPower * a[i]*channel_width;
+ channelDFFPower += powerWireDFF(M, channel_width, a[i]);
+ }
+ channelLeakPower+= powerRepeatedWireLeak(K,M,N)*channel_width;
+}
+
+wire const & Power_Module::wireOptimize(double L){
+ map<double, wire>::iterator iter = wire_map.find(L);
+ if(iter == wire_map.end()){
+
+ double W = 64;
+ double bestMetric = 100000000 ;
+ double bestK = -1;
+ double bestM = -1;
+ double bestN = -1;
+ for (double K = 1.0 ; K < 10 ; K+=0.1 ) {
+ for (double N = 1.0 ; N < 40 ; N += 1.0 ) {
+ for (double M = 1.0 ; M < 40.0 ; M +=1.0 ) {
+ double l = 1.0 * L/( N * M) ;
+
+ double k0 = R * (Co_delay + Ci_delay) ;
+ double k1 = R/K * Cw + K * Rw * Ci_delay ;
+ double k2 = 0.5 * Rw * Cw ;
+ double Tw = k0 + (k1 * l) + k2 * (l * l) ;
+ double alpha = 0.2 ;
+ double power = alpha * W * powerRepeatedWire( L, K, M, N) + powerWireDFF( M, W, alpha ) ;
+ double metric = M * M * M * M * power ;
+ if ( (N*Tw) < (0.8 * tCLK) ) {
+ if ( metric < bestMetric ) {
+ bestMetric = metric ;
+ bestK = K ;
+ bestM = M ;
+ bestN = N ;
+ }
+ }
+ }
+ }
+ }
+ cout<<"L = "<<L<<" K = "<<bestK<<" M = "<<bestM<<" N = "<<bestN<<endl;
+
+ wire const temp = {L, bestK, bestM, bestN};
+ iter = wire_map.insert(make_pair(L, temp)).first;
+ }
+ return iter->second;
+}
+
+double Power_Module::powerRepeatedWire(double L, double K, double M, double N){
+
+ double segments = 1.0 * M * N ;
+ double Ca = K * (Ci + Co) + Cw * (L/segments) ;
+ double Pa = 0.5 * Ca * Vdd * Vdd * fCLK;
+ return Pa * M * N ;
+
+}
+
+double Power_Module::powerRepeatedWireLeak (double K, double M, double N){
+ double Pl = K * 0.5 * ( IoffN + 2.0 * IoffP ) * Vdd ;
+ return Pl * M * N ;
+
+}
+
+double Power_Module:: powerWireClk (double M, double W){
+ // number of clock wires running down one repeater bank
+ double columns = H_DFQD1 * MetalPitch / ChannelPitch ;
+
+ // length of clock wire
+ double clockLength = W * ChannelPitch ;
+ double Cclk = (1 + 5.0/16.0 * (1+Co_delay/Ci_delay)) * (clockLength * Cw * columns +W * Ci_delay);
+
+ return M * Cclk * (Vdd * Vdd) * fCLK ;
+
+}
+
+double Power_Module::powerWireDFF(double M, double W, double alpha){
+ double Cdin = 2 * 0.8 * (Ci + Co) + 2 * ( 2.0/3.0 * 0.8 * Co ) ;
+ double Cclk = 2 * 0.8 * (Ci + Co) + 2 * ( 2.0/3.0 * 0.8 * Cg_pwr) ;
+ double Cint = (alpha * 0.5) * Cdin + alpha * Cclk ;
+
+ return Cint * M * W * (Vdd*Vdd) * fCLK ;
+}
+
+
+///////////////////////////////////////////////////////////////
+//Memory
+//////////////////////////////////////////////////////////////
+void Power_Module::calcBuffer(const BufferMonitor *bm){
+ double depth = numVC * depthVC ;
+ double Pleak = powerMemoryBitLeak( depth ) * channel_width ;
+ //area
+
+ const vector<int> reads = bm->GetReads();
+ const vector<int> writes = bm->GetWrites();
+ for(int i = 0; i<bm->NumInputs(); i++){
+ inputArea += areaInputModule( depth );
+ inputLeakagePower += Pleak ;
+ for(int j = 0; j< classes; j++){
+ double ar = ((double)reads[i* classes+j])/totalTime;
+ double aw = ((double)writes[i* classes+j])/totalTime;
+ if(ar>1 ||aw >1){
+ cout<<"activity factor is greater than one, soemthing is stomping memory\n"; exit(-1);
+ }
+ double Pwl = powerWordLine( channel_width, depth) ;
+ double Prd = powerMemoryBitRead( depth ) * channel_width ;
+ double Pwr = powerMemoryBitWrite( depth ) * channel_width ;
+ inputReadPower += ar * ( Pwl + Prd ) ;
+ inputWritePower += aw * ( Pwl + Pwr ) ;
+ }
+ }
+}
+
+
+double Power_Module::powerWordLine(double memoryWidth, double memoryDepth){
+ // wordline capacitance
+ double Ccell = 2 * ( 4.0 * LAMBDA ) * Cg_pwr + 6 * MetalPitch * Cw ;
+ double Cwl = memoryWidth * Ccell ;
+
+ // wordline circuits
+ double Warray = 8 * MetalPitch + memoryDepth ;
+ double x = 1.0 + (5.0/16.0) * (1 + Co/Ci) ;
+ double Cpredecode = x * (Cw * Warray * Ci) ;
+ double Cdecode = x * Cwl ;
+
+ // bitline circuits
+ double Harray = 6 * memoryWidth * MetalPitch ;
+ double y = (1 + 0.25) * (1 + Co/Ci) ;
+ double Cprecharge = y * ( Cw * Harray + 3 * channel_width * Ci ) ;
+ double Cwren = y * ( Cw * Harray + 2 * channel_width * Ci ) ;
+
+ double Cbd = Cprecharge + Cwren ;
+ double Cwd = 2 * Cpredecode + Cdecode ;
+
+ return ( Cbd + Cwd ) * Vdd * Vdd * fCLK ;
+
+}
+
+double Power_Module::powerMemoryBitRead(double memoryDepth){
+ // bitline capacitance
+ double Ccell = 4.0 * LAMBDA * Cd_pwr + 8 * MetalPitch * Cw ;
+ double Cbl = memoryDepth * Ccell ;
+ double Vswing = Vdd ;
+ return ( Cbl ) * ( Vdd * Vswing ) * fCLK ;
+}
+
+double Power_Module:: powerMemoryBitWrite(double memoryDepth){
+ // bitline capacitance
+ double Ccell = 4.0 * LAMBDA * Cd_pwr + 8 * MetalPitch * Cw ;
+ double Cbl = memoryDepth * Ccell ;
+
+ // internal capacitance
+ double Ccc = 2 * (Co + Ci) ;
+
+ return (0.5 * Ccc * (Vdd*Vdd)) + ( Cbl ) * ( Vdd * Vdd ) * fCLK ;
+}
+
+double Power_Module::powerMemoryBitLeak(double memoryDepth ){
+
+ return memoryDepth * IoffSRAM * Vdd ;
+}
+
+///////////////////////////////////////////////////////////////
+//switch
+//////////////////////////////////////////////////////////////
+
+void Power_Module::calcSwitch(const SwitchMonitor* sm){
+
+ switchArea += areaCrossbar(sm->NumInputs(), sm->NumOutputs());
+ outputArea += areaOutputModule(sm->NumOutputs());
+ switchPowerLeak += powerCrossbarLeak(channel_width, sm->NumInputs(), sm->NumOutputs());
+
+ const vector<int> activity = sm->GetActivity();
+ vector<double> type_activity(classes);
+
+ for(int i = 0; i<sm->NumOutputs(); i++){
+ for(int k = 0; k<classes; k++){
+ type_activity[k] = 0;
+ }
+ for(int j = 0; j<sm->NumInputs(); j++){
+ for(int k = 0; k<classes; k++){
+ double a = activity[k+classes*(i+sm->NumOutputs()*j)];
+ a = a/totalTime;
+ if(a>1){
+ cout<<"Switcht activity factor is greater than 1!!!\n";exit(-1);
+ }
+ double Px = powerCrossbar(channel_width, sm->NumInputs(),sm->NumOutputs(),j,i);
+ switchPower += a*channel_width*Px;
+ switchPowerCtrl += a *powerCrossbarCtrl(channel_width, sm->NumInputs(),sm->NumOutputs());
+ type_activity[k]+=a;
+ }
+ }
+ outputPowerClk += powerWireClk( 1, channel_width ) ;
+ for(int k = 0; k<classes; k++){
+ outputPower += type_activity[k] * powerWireDFF( 1, channel_width, 1.0 ) ;
+ outputCtrlPower += type_activity[k] * powerOutputCtrl(channel_width ) ;
+ }
+ }
+
+}
+
+double Power_Module::powerCrossbar(double width, double inputs, double outputs, double from, double to){
+ // datapath traversal power
+ double Wxbar = width * outputs * CrossbarPitch ;
+ double Hxbar = width * inputs * CrossbarPitch ;
+
+ // wires
+ double CwIn = Wxbar * Cw ;
+ double CwOut = Hxbar * Cw ;
+
+ // cross-points
+ double Cxi = (1.0/16.0) * CwOut ;
+ double Cxo = 4.0 * Cxi * (Co_delay/Ci_delay) ;
+
+ // drivers
+ double Cti = (1.0/16.0) * CwIn ;
+ double Cto = 4.0 * Cti * (Co_delay/Ci_delay) ;
+
+ double CinputDriver = 5.0/16.0 * (1 + Co_delay/Ci_delay) * (0.5 * Cw * Wxbar + Cti) ;
+
+ // total switched capacitance
+
+ //this maybe missing +Cto
+ double Cin = CinputDriver + CwIn + Cti + (outputs * Cxi) ;
+ if ( to < outputs/2 ) {
+ Cin -= ( 0.5 * CwIn + outputs/2 * Cxi) ;
+ }
+ //this maybe missing +cti
+ double Cout = CwOut + Cto + (inputs * Cxo) ;
+ if ( from < inputs/2) {
+ Cout -= ( 0.5 * CwOut + (inputs/2 * Cxo)) ;
+ }
+ return 0.5 * (Cin + Cout) * (Vdd * Vdd * fCLK) ;
+}
+
+
+double Power_Module::powerCrossbarCtrl(double width, double inputs, double outputs){
+
+ // datapath traversal power
+ double Wxbar = width * outputs * CrossbarPitch ;
+ double Hxbar = width * inputs * CrossbarPitch ;
+
+ // wires
+ double CwIn = Wxbar * Cw ;
+
+ // drivers
+ double Cti = (5.0/16.0) * CwIn ;
+
+ // need some estimate of how many control wires are required
+ double Cctrl = width * Cti + (Wxbar + Hxbar) * Cw ;
+ double Cdrive = (5.0/16.0) * (1 + Co_delay/Ci_delay) * Cctrl ;
+
+ return (Cdrive + Cctrl) * (Vdd*Vdd) * fCLK ;
+
+}
+
+double Power_Module::powerCrossbarLeak (double width, double inputs, double outputs){
+ // datapath traversal power
+ double Wxbar = width * outputs * CrossbarPitch ;
+ double Hxbar = width * inputs * CrossbarPitch ;
+
+ // wires
+ double CwIn = Wxbar * Cw ;
+ double CwOut = Hxbar * Cw ;
+ // cross-points
+ double Cxi = (1.0/16.0) * CwOut ;
+ // drivers
+ double Cti = (1.0/16.0) * CwIn ;
+
+ return 0.5 * (IoffN + 2 * IoffP)*width*(inputs*outputs*Cxi+inputs*Cti+outputs*Cti)/Ci;
+}
+
+//////////////////////////////////////////////////////////////////
+//output module
+//////////////////////////////////////////////////////////////////
+double Power_Module:: powerOutputCtrl(double width) {
+
+ double Woutmod = channel_width * ChannelPitch ;
+ double Cen = Ci ;
+
+ double Cenable = (1 + 5.0/16.0)*(1.0+Co/Ci)*(Woutmod* Cw + width* Cen) ;
+
+ return Cenable * (Vdd*Vdd) * fCLK ;
+
+}
+
+//////////////////////////////////////////////////////////////////
+//area
+//////////////////////////////////////////////////////////////////
+
+double Power_Module:: areaChannel (double K, double N, double M){
+
+ double Adff = M * W_DFQD1 * H_DFQD1 ;
+ double Ainv = M * N * ( W_INVD2 + 3 * K) * H_INVD2 ;
+
+ return channel_width * (Adff + Ainv) * MetalPitch * MetalPitch ;
+}
+
+double Power_Module:: areaCrossbar(double Inputs, double Outputs) {
+ return (Inputs * channel_width * CrossbarPitch) * (Outputs * channel_width * CrossbarPitch) ;
+}
+
+double Power_Module:: areaInputModule(double Words) {
+ double Asram = ( channel_width * H_SRAM ) * (Words * W_SRAM) ;
+ return Asram * (MetalPitch * MetalPitch) ;
+}
+
+double Power_Module:: areaOutputModule(double Outputs) {
+ double Adff = Outputs * W_DFQD1 * H_DFQD1 ;
+ return channel_width * Adff * MetalPitch * MetalPitch ;
+}
+
+void Power_Module::run(){
+ totalTime = GetSimTime();
+ channelWirePower=0;
+ channelClkPower=0;
+ channelDFFPower=0;
+ channelLeakPower=0;
+ inputReadPower=0;
+ inputWritePower=0;
+ inputLeakagePower=0;
+ switchPower=0;
+ switchPowerCtrl=0;
+ switchPowerLeak=0;
+ outputPower=0;
+ outputPowerClk=0;
+ outputCtrlPower=0;
+ channelArea=0;
+ switchArea=0;
+ inputArea=0;
+ outputArea=0;
+ maxInputPort = 0;
+ maxOutputPort = 0;
+
+ vector<FlitChannel *> inject = net->GetInject();
+ vector<FlitChannel *> eject = net->GetEject();
+ vector<FlitChannel *> chan = net->GetChannels();
+
+ for(int i = 0; i<net->NumNodes(); i++){
+ calcChannel(inject[i]);
+ }
+
+ for(int i = 0; i<net->NumNodes(); i++){
+ calcChannel(eject[i]);
+ }
+
+ for(int i = 0; i<net->NumChannels();i++){
+ calcChannel(chan[i]);
+ }
+
+ vector<Router*> routers = net->GetRouters();
+ for(size_t i = 0; i < routers.size(); i++){
+ IQRouter* temp = dynamic_cast<IQRouter*>(routers[i]);
+ const BufferMonitor * bm = temp->GetBufferMonitor();
+ calcBuffer(bm);
+ const SwitchMonitor * sm = temp->GetSwitchMonitor();
+ calcSwitch(sm);
+ }
+
+ double totalpower = channelWirePower+channelClkPower+channelDFFPower+channelLeakPower+ inputReadPower+inputWritePower+inputLeakagePower+ switchPower+switchPowerCtrl+switchPowerLeak+outputPower+outputPowerClk+outputCtrlPower;
+ double totalarea = channelArea+switchArea+inputArea+outputArea;
+ cout<< "-----------------------------------------\n" ;
+ cout<< "- OCN Power Summary\n" ;
+ cout<< "- Completion Time: "<<totalTime <<"\n" ;
+ cout<< "- Flit Widths: "<<channel_width<<"\n" ;
+ cout<< "- Channel Wire Power: "<<channelWirePower <<"\n" ;
+ cout<< "- Channel Clock Power: "<<channelClkPower <<"\n" ;
+ cout<< "- Channel Retiming Power: "<<channelDFFPower <<"\n" ;
+ cout<< "- Channel Leakage Power: "<<channelLeakPower <<"\n" ;
+
+ cout<< "- Input Read Power: "<<inputReadPower <<"\n" ;
+ cout<< "- Input Write Power: "<<inputWritePower <<"\n" ;
+ cout<< "- Input Leakage Power: "<<inputLeakagePower <<"\n" ;
+
+ cout<< "- Switch Power: "<<switchPower <<"\n" ;
+ cout<< "- Switch Control Power: "<<switchPowerCtrl <<"\n" ;
+ cout<< "- Switch Leakage Power: "<<switchPowerLeak <<"\n" ;
+
+ cout<< "- Output DFF Power: "<<outputPower <<"\n" ;
+ cout<< "- Output Clk Power: "<<outputPowerClk <<"\n" ;
+ cout<< "- Output Control Power: "<<outputCtrlPower <<"\n" ;
+ cout<< "- Total Power: "<<totalpower <<"\n";
+ cout<< "-----------------------------------------\n" ;
+ cout<< "\n" ;
+ cout<< "-----------------------------------------\n" ;
+ cout<< "- OCN Area Summary\n" ;
+ cout<< "- Channel Area: "<<channelArea<<"\n" ;
+ cout<< "- Switch Area: "<<switchArea<<"\n" ;
+ cout<< "- Input Area: "<<inputArea<<"\n" ;
+ cout<< "- Output Area: "<<outputArea<<"\n" ;
+ cout<< "- Total Area: "<<totalarea<<endl;
+ cout<< "-----------------------------------------\n" ;
+
+
+
+
+}
diff --git a/src/intersim2/power/power_module.hpp b/src/intersim2/power/power_module.hpp
new file mode 100644
index 0000000..58be23c
--- /dev/null
+++ b/src/intersim2/power/power_module.hpp
@@ -0,0 +1,186 @@
+// $Id: power_module.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _POWER_MODULE_HPP_
+#define _POWER_MODULE_HPP_
+
+#include <map>
+
+#include "module.hpp"
+#include "network.hpp"
+#include "config_utils.hpp"
+#include "flitchannel.hpp"
+#include "switch_monitor.hpp"
+#include "buffer_monitor.hpp"
+
+struct wire{
+ double L;
+ double K;
+ double M;
+ double N;
+};
+
+class Power_Module : public Module {
+
+protected:
+ //network undersimulation
+ Network * net;
+ int classes;
+ //all channels are this width
+ double channel_width;
+ //resimulate all with channel_width decremented by channel_sweep until 0
+ double channel_sweep;
+ //write result to a tabbed format to file
+ string output_file_name;
+
+ //buffer depth
+ double depthVC;
+ //vcs
+ double numVC;
+
+ //store the property of wires based on length
+ map<double, wire> wire_map;
+
+ //////////////////////////////////Constants/////////////////////////////
+ //wire length in (mm)
+ double wire_length;
+ //////////Metal Parameters////////////
+ // Wire left/right coupling capacitance [ F/mm ]
+ double Cw_cpl ;
+ // Wire up/down groudn capacitance [ F/mm ]
+ double Cw_gnd ;
+ double Cw ;
+ double Rw ;
+ // metal pitch [mm]
+ double MetalPitch ;
+
+
+ //////////Device Parameters////////////
+
+ double LAMBDA ; // [um/LAMBDA]
+ double Cd ; // [F/um] (for Delay)
+ double Cg ; // [F/um] (for Delay)
+ double Cgdl ; // [F/um] (for Delay)
+
+ double Cd_pwr; // [F/um] (for Power)
+ double Cg_pwr ; // [F/um] (for Power)
+
+ double IoffN ; // [A/um]
+ double IoffP ; // [A/um]
+ // Leakage from bitlines, two-port cell [A]
+ double IoffSRAM;
+ // [Ohm] ( D1=1um Inverter)
+ double R ;
+ // [F] ( D1=1um Inverter - for Power )
+ double Ci_delay;
+ // [F] ( D1=1um Inverter - for Power )
+ double Co_delay ;
+
+ double Ci ;
+ double Co ;
+ double Vdd ;
+ double FO4 ;
+ double tCLK ;
+ double fCLK ;
+
+ double H_INVD2;
+ double W_INVD2;
+ double H_DFQD1;
+ double W_DFQD1;
+ double H_ND2D1;
+ double W_ND2D1;
+ double H_SRAM;
+ double W_SRAM;
+ double ChannelPitch ;
+ double CrossbarPitch;
+ ////////////////////////////////End of Constants/////////////////////////////
+
+ /////////////results///////////////////
+ double totalTime;
+ double channelWirePower;
+ double channelClkPower;
+ double channelDFFPower;
+ double channelLeakPower;
+ double inputReadPower;
+ double inputWritePower;
+ double inputLeakagePower;
+ double switchPower;
+ double switchPowerCtrl;
+ double switchPowerLeak;
+ double outputPower;
+ double outputPowerClk;
+ double outputCtrlPower;
+ double channelArea;
+ double switchArea;
+ double inputArea;
+ double outputArea;
+ double maxInputPort;
+ double maxOutputPort;
+
+
+ ////////////////////////
+
+ //channels
+ void calcChannel(const FlitChannel * f);
+ wire const & wireOptimize(double l);
+ double powerRepeatedWire(double L, double K, double M, double N);
+ double powerRepeatedWireLeak (double K, double M, double N);
+ double powerWireClk (double M, double W);
+ double powerWireDFF(double M, double W, double alpha);
+
+ //memory
+ void calcBuffer(const BufferMonitor *bm);
+ double powerWordLine(double memoryWidth, double memoryDepth);
+ double powerMemoryBitRead(double memoryDepth);
+ double powerMemoryBitWrite(double memoryDepth);
+ double powerMemoryBitLeak(double memoryDepth );
+
+ //switch
+ void calcSwitch(const SwitchMonitor *sm);
+ double powerCrossbar(double width, double inputs, double outputs, double from, double to);
+ double powerCrossbarCtrl(double width, double inputs, double outputs);
+ double powerCrossbarLeak (double width, double inputs, double outputs);
+
+ //output
+ double powerOutputCtrl(double width);
+
+ //area
+
+ double areaChannel (double K, double N, double M);
+ double areaCrossbar(double Inputs, double Outputs) ;
+ double areaInputModule(double Words) ;
+ double areaOutputModule(double Outputs);
+
+public:
+ Power_Module(Network * net, const Configuration &config);
+ ~Power_Module();
+
+ void run();
+
+
+};
+#endif
diff --git a/src/intersim2/power/switch_monitor.cpp b/src/intersim2/power/switch_monitor.cpp
new file mode 100644
index 0000000..f998cb1
--- /dev/null
+++ b/src/intersim2/power/switch_monitor.cpp
@@ -0,0 +1,67 @@
+// $Id: switch_monitor.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "switch_monitor.hpp"
+
+#include "flit.hpp"
+
+SwitchMonitor::SwitchMonitor( int inputs, int outputs, int classes )
+: _cycles(0), _inputs(inputs), _outputs(outputs), _classes(classes) {
+ _event.resize(inputs * outputs * classes, 0) ;
+}
+
+int SwitchMonitor::index( int input, int output, int cl ) const {
+ assert((input >= 0) && (input < _inputs));
+ assert((output >= 0) && (output < _outputs));
+ assert((cl >= 0) && (cl < _classes));
+ return cl + _classes * ( output + _outputs * input ) ;
+}
+
+void SwitchMonitor::cycle() {
+ _cycles++ ;
+}
+
+void SwitchMonitor::traversal( int input, int output, Flit const * f ) {
+ _event[ index( input, output, f->cl) ]++ ;
+}
+
+void SwitchMonitor::display(ostream & os) const {
+ for ( int i = 0 ; i < _inputs ; i++ ) {
+ for ( int o = 0 ; o < _outputs ; o++) {
+ os << "[" << i << " -> " << o << "] " ;
+ for ( int c = 0 ; c < _classes ; c++ ) {
+ os << c << ":" << _event[index(i,o,c)] << " " ;
+ }
+ os << endl ;
+ }
+ }
+}
+
+ostream & operator<<( ostream & os, SwitchMonitor const & obj ) {
+ obj.display(os);
+ return os ;
+}
diff --git a/src/intersim2/power/switch_monitor.hpp b/src/intersim2/power/switch_monitor.hpp
new file mode 100644
index 0000000..dcc1276
--- /dev/null
+++ b/src/intersim2/power/switch_monitor.hpp
@@ -0,0 +1,66 @@
+// $Id: switch_monitor.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _SWITCH_MONITOR_HPP_
+#define _SWITCH_MONITOR_HPP_
+
+#include <vector>
+#include <iostream>
+
+using namespace std;
+
+class Flit;
+
+class SwitchMonitor {
+ int _cycles ;
+ int _inputs ;
+ int _outputs ;
+ int _classes ;
+ vector<int> _event ;
+ int index( int input, int output, int cl ) const ;
+public:
+ SwitchMonitor( int inputs, int outputs, int classes ) ;
+ void cycle() ;
+ vector<int> const & GetActivity() const {
+ return _event;
+ }
+ inline int const & NumInputs() const {
+ return _inputs;
+ }
+ inline int const & NumOutputs() const {
+ return _outputs;
+ }
+ inline int const & NumClasses() const {
+ return _classes;
+ }
+ void traversal( int input, int output, Flit const * f ) ;
+ void display(ostream & os) const;
+} ;
+
+ostream & operator<<( ostream & os, SwitchMonitor const & obj ) ;
+
+#endif
diff --git a/src/intersim2/power/techfile.txt b/src/intersim2/power/techfile.txt
new file mode 100755
index 0000000..c953713
--- /dev/null
+++ b/src/intersim2/power/techfile.txt
@@ -0,0 +1,26 @@
+// 2007 ITRS predictions for a 32nm high-performance library
+H_INVD2 = 8;//int
+W_INVD2 = 3;//int
+H_DFQD1 = 8;//int
+W_DFQD1 = 16;//int
+H_ND2D1 = 8;//int
+W_ND2D1 = 3;//int
+H_SRAM = 8;//int
+W_SRAM = 6;//int
+Vdd = 0.9;//float
+R = 606.321;//float
+IoffSRAM = 0.00000032;//float
+// 70 C
+IoffP = 0.00000102;//float
+IoffN = 0.00000102;//float
+Cg_pwr = 0.000000000000000534;//float
+Cd_pwr = 0.000000000000000267;//float
+Cgdl = 0.0000000000000001068;//float
+Cg = 0.000000000000000534;//float
+Cd = 0.000000000000000267;//float
+LAMBDA = 0.016;//float
+MetalPitch = 0.000080;//float
+Rw = 0.720044;//float
+Cw_gnd = 0.000000000000267339;//float
+Cw_cpl = 0.000000000000267339;//float
+wire_length = 2.0;//float \ No newline at end of file
diff --git a/src/intersim2/random_utils.hpp b/src/intersim2/random_utils.hpp
new file mode 100644
index 0000000..1150b08
--- /dev/null
+++ b/src/intersim2/random_utils.hpp
@@ -0,0 +1,61 @@
+// $Id: random_utils.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RANDOM_UTILS_HPP_
+#define _RANDOM_UTILS_HPP_
+
+ // interface to Knuth's RANARRAY RNG
+void ran_start(long seed);
+long ran_next( );
+void ranf_start(long seed);
+double ranf_next( );
+
+inline void RandomSeed( long seed ) {
+ ran_start( seed );
+ ranf_start( seed );
+}
+
+inline unsigned long RandomIntLong( ) {
+ return ran_next( );
+}
+
+// Returns a random integer in the range [0,max]
+inline int RandomInt( int max ) {
+ return ( ran_next( ) % (max+1) );
+}
+
+// Returns a random floating-point value in the rage [0,1]
+inline double RandomFloat( ) {
+ return ranf_next( );
+}
+
+// Returns a random floating-point value in the rage [0,max]
+inline double RandomFloat( double max ) {
+ return ( ranf_next( ) * max );
+}
+
+#endif
diff --git a/src/intersim2/rng-double.c b/src/intersim2/rng-double.c
new file mode 100644
index 0000000..27428d9
--- /dev/null
+++ b/src/intersim2/rng-double.c
@@ -0,0 +1,112 @@
+/* This program by D E Knuth is in the public domain and freely copyable.
+ * It is explained in Seminumerical Algorithms, 3rd edition, Section 3.6
+ * (or in the errata to the 2nd edition --- see
+ * http://www-cs-faculty.stanford.edu/~knuth/taocp.html
+ * in the changes to Volume 2 on pages 171 and following). */
+
+/* N.B. The MODIFICATIONS introduced in the 9th printing (2002) are
+ included here; there's no backwards compatibility with the original. */
+
+/* This version also adopts Brendan McKay's suggestion to
+ accommodate naive users who forget to call ranf_start(seed). */
+
+/* If you find any bugs, please report them immediately to
+ * (and you will be rewarded if the bug is genuine). Thanks! */
+
+/************ see the book for explanations and caveats! *******************/
+/************ in particular, you need two's complement arithmetic **********/
+
+#define KK 100 /* the long lag */
+#define LL 37 /* the short lag */
+#define mod_sum(x,y) (((x)+(y))-(int)((x)+(y))) /* (x+y) mod 1.0 */
+
+double ran_u[KK]; /* the generator state */
+
+#ifdef __STDC__
+void ranf_array(double aa[], int n)
+#else
+void ranf_array(aa,n) /* put n new random fractions in aa */
+ double *aa; /* destination */
+ int n; /* array length (must be at least KK) */
+#endif
+{
+ register int i,j;
+ for (j=0;j<KK;j++) aa[j]=ran_u[j];
+ for (;j<n;j++) aa[j]=mod_sum(aa[j-KK],aa[j-LL]);
+ for (i=0;i<LL;i++,j++) ran_u[i]=mod_sum(aa[j-KK],aa[j-LL]);
+ for (;i<KK;i++,j++) ran_u[i]=mod_sum(aa[j-KK],ran_u[i-LL]);
+}
+
+/* the following routines are adapted from exercise 3.6--15 */
+/* after calling ranf_start, get new randoms by, e.g., "x=ranf_arr_next()" */
+
+#define QUALITY 1009 /* recommended quality level for high-res use */
+double ranf_arr_buf[QUALITY];
+double ranf_arr_dummy=-1.0, ranf_arr_started=-1.0;
+double *ranf_arr_ptr=&ranf_arr_dummy; /* the next random fraction, or -1 */
+
+#define TT 70 /* guaranteed separation between streams */
+#define is_odd(s) ((s)&1)
+
+#ifdef __STDC__
+void ranf_start(long seed)
+#else
+void ranf_start(seed) /* do this before using ranf_array */
+ long seed; /* selector for different streams */
+#endif
+{
+ register int t,s,j;
+ double u[KK+KK-1];
+ double ulp=(1.0/(1L<<30))/(1L<<22); /* 2 to the -52 */
+ double ss=2.0*ulp*((seed&0x3fffffff)+2);
+
+ for (j=0;j<KK;j++) {
+ u[j]=ss; /* bootstrap the buffer */
+ ss+=ss; if (ss>=1.0) ss-=1.0-2*ulp; /* cyclic shift of 51 bits */
+ }
+ u[1]+=ulp; /* make u[1] (and only u[1]) "odd" */
+ for (s=seed&0x3fffffff,t=TT-1; t; ) {
+ for (j=KK-1;j>0;j--)
+ u[j+j]=u[j],u[j+j-1]=0.0; /* "square" */
+ for (j=KK+KK-2;j>=KK;j--) {
+ u[j-(KK-LL)]=mod_sum(u[j-(KK-LL)],u[j]);
+ u[j-KK]=mod_sum(u[j-KK],u[j]);
+ }
+ if (is_odd(s)) { /* "multiply by z" */
+ for (j=KK;j>0;j--) u[j]=u[j-1];
+ u[0]=u[KK]; /* shift the buffer cyclically */
+ u[LL]=mod_sum(u[LL],u[KK]);
+ }
+ if (s) s>>=1; else t--;
+ }
+ for (j=0;j<LL;j++) ran_u[j+KK-LL]=u[j];
+ for (;j<KK;j++) ran_u[j-LL]=u[j];
+ for (j=0;j<10;j++) ranf_array(u,KK+KK-1); /* warm things up */
+ ranf_arr_ptr=&ranf_arr_started;
+}
+
+#define ranf_arr_next() (*ranf_arr_ptr>=0? *ranf_arr_ptr++: ranf_arr_cycle())
+double ranf_arr_cycle()
+{
+ if (ranf_arr_ptr==&ranf_arr_dummy)
+ ranf_start(314159L); /* the user forgot to initialize */
+ ranf_array(ranf_arr_buf,QUALITY);
+ ranf_arr_buf[KK]=-1;
+ ranf_arr_ptr=ranf_arr_buf+1;
+ return ranf_arr_buf[0];
+}
+
+#include <stdio.h>
+int main()
+{
+ register int m; double a[2009]; /* a rudimentary test */
+ ranf_start(310952);
+ for (m=0;m<2009;m++) ranf_array(a,1009);
+ printf("%.20f\n", ran_u[0]); /* 0.36410514377569680455 */
+ /* beware of buggy printf routines that do not give full accuracy here! */
+ ranf_start(310952);
+ for (m=0;m<1009;m++) ranf_array(a,2009);
+ printf("%.20f\n", ran_u[0]); /* 0.36410514377569680455 */
+ return 0;
+}
diff --git a/src/intersim2/rng.c b/src/intersim2/rng.c
new file mode 100644
index 0000000..c27740f
--- /dev/null
+++ b/src/intersim2/rng.c
@@ -0,0 +1,108 @@
+/* This program by D E Knuth is in the public domain and freely copyable.
+ * It is explained in Seminumerical Algorithms, 3rd edition, Section 3.6
+ * (or in the errata to the 2nd edition --- see
+ * http://www-cs-faculty.stanford.edu/~knuth/taocp.html
+ * in the changes to Volume 2 on pages 171 and following). */
+
+/* N.B. The MODIFICATIONS introduced in the 9th printing (2002) are
+ included here; there's no backwards compatibility with the original. */
+
+/* This version also adopts Brendan McKay's suggestion to
+ accommodate naive users who forget to call ran_start(seed). */
+
+/* If you find any bugs, please report them immediately to
+ * (and you will be rewarded if the bug is genuine). Thanks! */
+
+/************ see the book for explanations and caveats! *******************/
+/************ in particular, you need two's complement arithmetic **********/
+
+#define KK 100 /* the long lag */
+#define LL 37 /* the short lag */
+#define MM (1L<<30) /* the modulus */
+#define mod_diff(x,y) (((x)-(y))&(MM-1)) /* subtraction mod MM */
+
+long ran_x[KK]; /* the generator state */
+
+#ifdef __STDC__
+void ran_array(long aa[],int n)
+#else
+void ran_array(aa,n) /* put n new random numbers in aa */
+ long *aa; /* destination */
+ int n; /* array length (must be at least KK) */
+#endif
+{
+ register int i,j;
+ for (j=0;j<KK;j++) aa[j]=ran_x[j];
+ for (;j<n;j++) aa[j]=mod_diff(aa[j-KK],aa[j-LL]);
+ for (i=0;i<LL;i++,j++) ran_x[i]=mod_diff(aa[j-KK],aa[j-LL]);
+ for (;i<KK;i++,j++) ran_x[i]=mod_diff(aa[j-KK],ran_x[i-LL]);
+}
+
+/* the following routines are from exercise 3.6--15 */
+/* after calling ran_start, get new randoms by, e.g., "x=ran_arr_next()" */
+
+#define QUALITY 1009 /* recommended quality level for high-res use */
+long ran_arr_buf[QUALITY];
+long ran_arr_dummy=-1, ran_arr_started=-1;
+long *ran_arr_ptr=&ran_arr_dummy; /* the next random number, or -1 */
+
+#define TT 70 /* guaranteed separation between streams */
+#define is_odd(x) ((x)&1) /* units bit of x */
+
+#ifdef __STDC__
+void ran_start(long seed)
+#else
+void ran_start(seed) /* do this before using ran_array */
+ long seed; /* selector for different streams */
+#endif
+{
+ register int t,j;
+ long x[KK+KK-1]; /* the preparation buffer */
+ register long ss=(seed+2)&(MM-2);
+ for (j=0;j<KK;j++) {
+ x[j]=ss; /* bootstrap the buffer */
+ ss<<=1; if (ss>=MM) ss-=MM-2; /* cyclic shift 29 bits */
+ }
+ x[1]++; /* make x[1] (and only x[1]) odd */
+ for (ss=seed&(MM-1),t=TT-1; t; ) {
+ for (j=KK-1;j>0;j--) x[j+j]=x[j], x[j+j-1]=0; /* "square" */
+ for (j=KK+KK-2;j>=KK;j--)
+ x[j-(KK-LL)]=mod_diff(x[j-(KK-LL)],x[j]),
+ x[j-KK]=mod_diff(x[j-KK],x[j]);
+ if (is_odd(ss)) { /* "multiply by z" */
+ for (j=KK;j>0;j--) x[j]=x[j-1];
+ x[0]=x[KK]; /* shift the buffer cyclically */
+ x[LL]=mod_diff(x[LL],x[KK]);
+ }
+ if (ss) ss>>=1; else t--;
+ }
+ for (j=0;j<LL;j++) ran_x[j+KK-LL]=x[j];
+ for (;j<KK;j++) ran_x[j-LL]=x[j];
+ for (j=0;j<10;j++) ran_array(x,KK+KK-1); /* warm things up */
+ ran_arr_ptr=&ran_arr_started;
+}
+
+#define ran_arr_next() (*ran_arr_ptr>=0? *ran_arr_ptr++: ran_arr_cycle())
+long ran_arr_cycle()
+{
+ if (ran_arr_ptr==&ran_arr_dummy)
+ ran_start(314159L); /* the user forgot to initialize */
+ ran_array(ran_arr_buf,QUALITY);
+ ran_arr_buf[KK]=-1;
+ ran_arr_ptr=ran_arr_buf+1;
+ return ran_arr_buf[0];
+}
+
+#include <stdio.h>
+int main()
+{
+ register int m; long a[2009];
+ ran_start(310952L);
+ for (m=0;m<=2009;m++) ran_array(a,1009);
+ printf("%ld\n", a[0]); /* 995235265 */
+ ran_start(310952L);
+ for (m=0;m<=1009;m++) ran_array(a,2009);
+ printf("%ld\n", a[0]); /* 995235265 */
+ return 0;
+}
diff --git a/src/intersim2/rng_double_wrapper.cpp b/src/intersim2/rng_double_wrapper.cpp
new file mode 100644
index 0000000..ad4844c
--- /dev/null
+++ b/src/intersim2/rng_double_wrapper.cpp
@@ -0,0 +1,34 @@
+// $Id: rng_double_wrapper.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define main rng_double_main
+#include "rng-double.c"
+
+double ranf_next( )
+{
+ return ranf_arr_next( );
+}
diff --git a/src/intersim2/rng_wrapper.cpp b/src/intersim2/rng_wrapper.cpp
new file mode 100644
index 0000000..2e0cc2e
--- /dev/null
+++ b/src/intersim2/rng_wrapper.cpp
@@ -0,0 +1,34 @@
+// $Id: rng_wrapper.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define main rng_main
+#include "rng.c"
+
+long ran_next( )
+{
+ return ran_arr_next( );
+}
diff --git a/src/intersim2/routefunc.cpp b/src/intersim2/routefunc.cpp
new file mode 100644
index 0000000..567dcae
--- /dev/null
+++ b/src/intersim2/routefunc.cpp
@@ -0,0 +1,1999 @@
+// $Id: routefunc.cpp 5507 2013-05-23 14:54:38Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*routefunc.cpp
+ *
+ *This is where most of the routing functions reside. Some of the topologies
+ *has their own "register routing functions" which must be called to access
+ *those routing functions.
+ *
+ *After writing a routing function, don't forget to register it. The reg
+ *format is rfname_topologyname.
+ *
+ */
+
+#include <map>
+#include <cstdlib>
+#include <cassert>
+
+#include "booksim.hpp"
+#include "routefunc.hpp"
+#include "kncube.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+#include "fattree.hpp"
+#include "tree4.hpp"
+#include "qtree.hpp"
+#include "cmesh.hpp"
+
+
+
+map<string, tRoutingFunction> gRoutingFunctionMap;
+
+/* Global information used by routing functions */
+
+int gNumVCs;
+
+/* Add more functions here
+ *
+ */
+
+// ============================================================
+// Balfour-Schultz
+int gReadReqBeginVC, gReadReqEndVC;
+int gWriteReqBeginVC, gWriteReqEndVC;
+int gReadReplyBeginVC, gReadReplyEndVC;
+int gWriteReplyBeginVC, gWriteReplyEndVC;
+
+// ============================================================
+// QTree: Nearest Common Ancestor
+// ===
+void qtree_nca( const Router *r, const Flit *f,
+ int in_channel, OutputSet* outputs, bool inject)
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int height = QTree::HeightFromID( r->GetID() );
+ int pos = QTree::PosFromID( r->GetID() );
+
+ int dest = f->dest;
+
+ for (int i = height+1; i < gN; i++)
+ dest /= gK;
+ if ( pos == dest / gK )
+ // Route down to child
+ out_port = dest % gK ;
+ else
+ // Route up to parent
+ out_port = gK;
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+// ============================================================
+// Tree4: Nearest Common Ancestor w/ Adaptive Routing Up
+// ===
+void tree4_anca( const Router *r, const Flit *f,
+ int in_channel, OutputSet* outputs, bool inject)
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int range = 1;
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = f->dest;
+
+ const int NPOS = 16;
+
+ int rH = r->GetID( ) / NPOS;
+ int rP = r->GetID( ) % NPOS;
+
+ if ( rH == 0 ) {
+ dest /= 16;
+ out_port = 2 * dest + RandomInt(1);
+ } else if ( rH == 1 ) {
+ dest /= 4;
+ if ( dest / 4 == rP / 2 )
+ out_port = dest % 4;
+ else {
+ out_port = gK;
+ range = gK;
+ }
+ } else {
+ if ( dest/4 == rP )
+ out_port = dest % 4;
+ else {
+ out_port = gK;
+ range = 2;
+ }
+ }
+
+ // cout << "Router("<<rH<<","<<rP<<"): id= " << f->id << " dest= " << f->dest << " out_port = "
+ // << out_port << endl;
+
+ }
+
+ outputs->Clear( );
+
+ for (int i = 0; i < range; ++i)
+ outputs->AddRange( out_port + i, vcBegin, vcEnd );
+}
+
+// ============================================================
+// Tree4: Nearest Common Ancestor w/ Random Routing Up
+// ===
+void tree4_nca( const Router *r, const Flit *f,
+ int in_channel, OutputSet* outputs, bool inject)
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = f->dest;
+
+ const int NPOS = 16;
+
+ int rH = r->GetID( ) / NPOS;
+ int rP = r->GetID( ) % NPOS;
+
+ if ( rH == 0 ) {
+ dest /= 16;
+ out_port = 2 * dest + RandomInt(1);
+ } else if ( rH == 1 ) {
+ dest /= 4;
+ if ( dest / 4 == rP / 2 )
+ out_port = dest % 4;
+ else
+ out_port = gK + RandomInt(gK-1);
+ } else {
+ if ( dest/4 == rP )
+ out_port = dest % 4;
+ else
+ out_port = gK + RandomInt(1);
+ }
+
+ // cout << "Router("<<rH<<","<<rP<<"): id= " << f->id << " dest= " << f->dest << " out_port = "
+ // << out_port << endl;
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+// ============================================================
+// FATTREE: Nearest Common Ancestor w/ Random Routing Up
+// ===
+void fattree_nca( const Router *r, const Flit *f,
+ int in_channel, OutputSet* outputs, bool inject)
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int dest = f->dest;
+ int router_id = r->GetID(); //routers are numbered with smallest at the top level
+ int routers_per_level = powi(gK, gN-1);
+ int pos = router_id%routers_per_level;
+ int router_depth = router_id/ routers_per_level; //which level
+ int routers_per_neighborhood = powi(gK,gN-router_depth-1);
+ int router_neighborhood = pos/routers_per_neighborhood; //coverage of this tree
+ int router_coverage = powi(gK, gN-router_depth); //span of the tree from this router
+
+
+ //NCA reached going down
+ if(dest <(router_neighborhood+1)* router_coverage &&
+ dest >=router_neighborhood* router_coverage){
+ //down ports are numbered first
+
+ //ejection
+ if(router_depth == gN-1){
+ out_port = dest%gK;
+ } else {
+ //find the down port for the destination
+ int router_branch_coverage = powi(gK, gN-(router_depth+1));
+ out_port = (dest-router_neighborhood* router_coverage)/router_branch_coverage;
+ }
+ } else {
+ //up ports are numbered last
+ assert(in_channel<gK);//came from a up channel
+ out_port = gK+RandomInt(gK-1);
+ }
+ }
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+// ============================================================
+// FATTREE: Nearest Common Ancestor w/ Adaptive Routing Up
+// ===
+void fattree_anca( const Router *r, const Flit *f,
+ int in_channel, OutputSet* outputs, bool inject)
+{
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+
+ int dest = f->dest;
+ int router_id = r->GetID(); //routers are numbered with smallest at the top level
+ int routers_per_level = powi(gK, gN-1);
+ int pos = router_id%routers_per_level;
+ int router_depth = router_id/ routers_per_level; //which level
+ int routers_per_neighborhood = powi(gK,gN-router_depth-1);
+ int router_neighborhood = pos/routers_per_neighborhood; //coverage of this tree
+ int router_coverage = powi(gK, gN-router_depth); //span of the tree from this router
+
+
+ //NCA reached going down
+ if(dest <(router_neighborhood+1)* router_coverage &&
+ dest >=router_neighborhood* router_coverage){
+ //down ports are numbered first
+
+ //ejection
+ if(router_depth == gN-1){
+ out_port = dest%gK;
+ } else {
+ //find the down port for the destination
+ int router_branch_coverage = powi(gK, gN-(router_depth+1));
+ out_port = (dest-router_neighborhood* router_coverage)/router_branch_coverage;
+ }
+ } else {
+ //up ports are numbered last
+ assert(in_channel<gK);//came from a up channel
+ out_port = gK;
+ int random1 = RandomInt(gK-1); // Chose two ports out of the possible at random, compare loads, choose one.
+ int random2 = RandomInt(gK-1);
+ if (r->GetUsedCredit(out_port + random1) > r->GetUsedCredit(out_port + random2)){
+ out_port = out_port + random2;
+ }else{
+ out_port = out_port + random1;
+ }
+ }
+ }
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+
+
+
+// ============================================================
+// Mesh - adatpive XY,YX Routing
+// pick xy or yx min routing adaptively at the source router
+// ===
+
+int dor_next_mesh( int cur, int dest, bool descending = false );
+
+void adaptive_xy_yx_mesh( const Router *r, const Flit *f,
+ int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else if(r->GetID() == f->dest) {
+
+ // at destination router, we don't need to separate VCs by dim order
+ out_port = 2*gN;
+
+ } else {
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ int out_port_xy = dor_next_mesh( r->GetID(), f->dest, false );
+ int out_port_yx = dor_next_mesh( r->GetID(), f->dest, true );
+
+ // Route order (XY or YX) determined when packet is injected
+ // into the network, adaptively
+ bool x_then_y;
+ if(in_channel < 2*gN){
+ x_then_y = (f->vc < (vcBegin + available_vcs));
+ } else {
+ int credit_xy = r->GetUsedCredit(out_port_xy);
+ int credit_yx = r->GetUsedCredit(out_port_yx);
+ if(credit_xy > credit_yx) {
+ x_then_y = false;
+ } else if(credit_xy < credit_yx) {
+ x_then_y = true;
+ } else {
+ x_then_y = (RandomInt(1) > 0);
+ }
+ }
+
+ if(x_then_y) {
+ out_port = out_port_xy;
+ vcEnd -= available_vcs;
+ } else {
+ out_port = out_port_yx;
+ vcBegin += available_vcs;
+ }
+
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+
+}
+
+void xy_yx_mesh( const Router *r, const Flit *f,
+ int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else if(r->GetID() == f->dest) {
+
+ // at destination router, we don't need to separate VCs by dim order
+ out_port = 2*gN;
+
+ } else {
+
+ //each class must have at least 2 vcs assigned or else xy_yx will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ // Route order (XY or YX) determined when packet is injected
+ // into the network
+ bool x_then_y = ((in_channel < 2*gN) ?
+ (f->vc < (vcBegin + available_vcs)) :
+ (RandomInt(1) > 0));
+
+ if(x_then_y) {
+ out_port = dor_next_mesh( r->GetID(), f->dest, false );
+ vcEnd -= available_vcs;
+ } else {
+ out_port = dor_next_mesh( r->GetID(), f->dest, true );
+ vcBegin += available_vcs;
+ }
+
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+
+}
+
+//
+// End Balfour-Schultz
+//=============================================================
+
+//=============================================================
+
+int dor_next_mesh( int cur, int dest, bool descending )
+{
+ if ( cur == dest ) {
+ return 2*gN; // Eject
+ }
+
+ int dim_left;
+
+ if(descending) {
+ for ( dim_left = ( gN - 1 ); dim_left > 0; --dim_left ) {
+ if ( ( cur * gK / gNodes ) != ( dest * gK / gNodes ) ) { break; }
+ cur = (cur * gK) % gNodes; dest = (dest * gK) % gNodes;
+ }
+ cur = (cur * gK) / gNodes;
+ dest = (dest * gK) / gNodes;
+ } else {
+ for ( dim_left = 0; dim_left < ( gN - 1 ); ++dim_left ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) { break; }
+ cur /= gK; dest /= gK;
+ }
+ cur %= gK;
+ dest %= gK;
+ }
+
+ if ( cur < dest ) {
+ return 2*dim_left; // Right
+ } else {
+ return 2*dim_left + 1; // Left
+ }
+}
+
+//=============================================================
+
+void dor_next_torus( int cur, int dest, int in_port,
+ int *out_port, int *partition,
+ bool balance = false )
+{
+ int dim_left;
+ int dir;
+ int dist2;
+
+ for ( dim_left = 0; dim_left < gN; ++dim_left ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) { break; }
+ cur /= gK; dest /= gK;
+ }
+
+ if ( dim_left < gN ) {
+
+ if ( (in_port/2) != dim_left ) {
+ // Turning into a new dimension
+
+ cur %= gK; dest %= gK;
+ dist2 = gK - 2 * ( ( dest - cur + gK ) % gK );
+
+ if ( ( dist2 > 0 ) ||
+ ( ( dist2 == 0 ) && ( RandomInt( 1 ) ) ) ) {
+ *out_port = 2*dim_left; // Right
+ dir = 0;
+ } else {
+ *out_port = 2*dim_left + 1; // Left
+ dir = 1;
+ }
+
+ if ( partition ) {
+ if ( balance ) {
+ // Cray's "Partition" allocation
+ // Two datelines: one between k-1 and 0 which forces VC 1
+ // another between ((k-1)/2) and ((k-1)/2 + 1) which
+ // forces VC 0 otherwise any VC can be used
+
+ if ( ( ( dir == 0 ) && ( cur > dest ) ) ||
+ ( ( dir == 1 ) && ( cur < dest ) ) ) {
+ *partition = 1;
+ } else if ( ( ( dir == 0 ) && ( cur <= (gK-1)/2 ) && ( dest > (gK-1)/2 ) ) ||
+ ( ( dir == 1 ) && ( cur > (gK-1)/2 ) && ( dest <= (gK-1)/2 ) ) ) {
+ *partition = 0;
+ } else {
+ *partition = RandomInt( 1 ); // use either VC set
+ }
+ } else {
+ // Deterministic, fixed dateline between nodes k-1 and 0
+
+ if ( ( ( dir == 0 ) && ( cur > dest ) ) ||
+ ( ( dir == 1 ) && ( dest < cur ) ) ) {
+ *partition = 1;
+ } else {
+ *partition = 0;
+ }
+ }
+ }
+ } else {
+ // Inverting the least significant bit keeps
+ // the packet moving in the same direction
+ *out_port = in_port ^ 0x1;
+ }
+
+ } else {
+ *out_port = 2*gN; // Eject
+ }
+}
+
+//=============================================================
+
+void dim_order_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port = inject ? -1 : dor_next_mesh( r->GetID( ), f->dest );
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ if ( !inject && f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ outputs->Clear();
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void dim_order_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port = inject ? -1 : dor_next_mesh( r->GetID( ), f->dest );
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ // at the destination router, we don't need to separate VCs by destination
+ if(inject || (r->GetID() != f->dest)) {
+
+ int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes;
+ assert(vcs_per_dest > 0);
+
+ vcBegin += f->dest * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+
+ }
+
+ if( !inject && f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void dim_order_pni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port = inject ? -1 : dor_next_mesh( r->GetID(), f->dest );
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ if(inject || (r->GetID() != f->dest)) {
+ int next_coord = f->dest;
+ if(!inject) {
+ int out_dim = out_port / 2;
+ for(int d = 0; d < out_dim; ++d) {
+ next_coord /= gK;
+ }
+ }
+ next_coord %= gK;
+ assert(next_coord >= 0 && next_coord < gK);
+ int vcs_per_dest = (vcEnd - vcBegin + 1) / gK;
+ assert(vcs_per_dest > 0);
+ vcBegin += next_coord * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+ }
+
+ if( !inject && f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+// Random intermediate in the minimal quadrant defined
+// by the source and destination
+int rand_min_intr_mesh( int src, int dest )
+{
+ int dist;
+
+ int intm = 0;
+ int offset = 1;
+
+ for ( int n = 0; n < gN; ++n ) {
+ dist = ( dest % gK ) - ( src % gK );
+
+ if ( dist > 0 ) {
+ intm += offset * ( ( src % gK ) + RandomInt( dist ) );
+ } else {
+ intm += offset * ( ( dest % gK ) + RandomInt( -dist ) );
+ }
+
+ offset *= gK;
+ dest /= gK; src /= gK;
+ }
+
+ return intm;
+}
+
+//=============================================================
+
+void romm_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 0; // Phase 0
+ f->intm = rand_min_intr_mesh( f->src, f->dest );
+ }
+
+ if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 1; // Go to phase 1
+ }
+
+ out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest );
+
+ // at the destination router, we don't need to separate VCs by phase
+ if(r->GetID() != f->dest) {
+
+ //each class must have at least 2 vcs assigned or else valiant valiant will deadlock
+ int available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ if(f->ph == 0) {
+ vcEnd -= available_vcs;
+ } else {
+ assert(f->ph == 1);
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void romm_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ // at the destination router, we don't need to separate VCs by destination
+ if(inject || (r->GetID() != f->dest)) {
+
+ int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes;
+ assert(vcs_per_dest > 0);
+
+ vcBegin += f->dest * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+
+ }
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 0; // Phase 0
+ f->intm = rand_min_intr_mesh( f->src, f->dest );
+ }
+
+ if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 1; // Go to phase 1
+ }
+
+ out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest );
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void min_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ outputs->Clear( );
+
+ if(inject) {
+ // injection can use all VCs
+ outputs->AddRange(-1, vcBegin, vcEnd);
+ return;
+ } else if(r->GetID() == f->dest) {
+ // ejection can also use all VCs
+ outputs->AddRange(2*gN, vcBegin, vcEnd);
+ return;
+ }
+
+ int in_vc;
+
+ if ( in_channel == 2*gN ) {
+ in_vc = vcEnd; // ignore the injection VC
+ } else {
+ in_vc = f->vc;
+ }
+
+ // DOR for the escape channel (VC 0), low priority
+ int out_port = dor_next_mesh( r->GetID( ), f->dest );
+ outputs->AddRange( out_port, 0, vcBegin, vcBegin );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcBegin << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ if ( in_vc != vcBegin ) { // If not in the escape VC
+ // Minimal adaptive for all other channels
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ // Add minimal direction in dimension 'n'
+ if ( ( cur % gK ) < ( dest % gK ) ) { // Right
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << (vcBegin+1) << ","
+ << vcEnd << "]"
+ << " at output port " << 2*n
+ << " with priority " << 1
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+ outputs->AddRange( 2*n, vcBegin+1, vcEnd, 1 );
+ } else { // Left
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << (vcBegin+1) << ","
+ << vcEnd << "]"
+ << " at output port " << 2*n+1
+ << " with priority " << 1
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+ outputs->AddRange( 2*n + 1, vcBegin+1, vcEnd, 1 );
+ }
+ }
+ cur /= gK;
+ dest /= gK;
+ }
+ }
+}
+
+//=============================================================
+
+void planar_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ outputs->Clear( );
+
+ if(inject) {
+ // injection can use all VCs
+ outputs->AddRange(-1, vcBegin, vcEnd);
+ return;
+ }
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ if ( cur != dest ) {
+
+ int in_vc = f->vc;
+ int vc_mult = (vcEnd - vcBegin + 1) / 3;
+
+ // Find the first unmatched dimension -- except
+ // for when we're in the first dimension because
+ // of misrouting in the last adaptive plane.
+ // In this case, go to the last dimension instead.
+
+ int n;
+ for ( n = 0; n < gN; ++n ) {
+ if ( ( ( cur % gK ) != ( dest % gK ) ) &&
+ !( ( in_channel/2 == 0 ) &&
+ ( n == 0 ) &&
+ ( in_vc < vcBegin+2*vc_mult ) ) ) {
+ break;
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+
+ assert( n < gN );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "PLANAR ADAPTIVE: flit " << f->id
+ << " in adaptive plane " << n << "." << endl;
+ }
+
+ // We're in adaptive plane n
+
+ // Can route productively in d_{i,2}
+ bool increase;
+ bool fault;
+ if ( ( cur % gK ) < ( dest % gK ) ) { // Increasing
+ increase = true;
+ if ( !r->IsFaultyOutput( 2*n ) ) {
+ outputs->AddRange( 2*n, vcBegin+2*vc_mult, vcEnd );
+ fault = false;
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "PLANAR ADAPTIVE: increasing in dimension " << n
+ << "." << endl;
+ }
+ } else {
+ fault = true;
+ }
+ } else { // Decreasing
+ increase = false;
+ if ( !r->IsFaultyOutput( 2*n + 1 ) ) {
+ outputs->AddRange( 2*n + 1, vcBegin+2*vc_mult, vcEnd );
+ fault = false;
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "PLANAR ADAPTIVE: decreasing in dimension " << n
+ << "." << endl;
+ }
+ } else {
+ fault = true;
+ }
+ }
+
+ n = ( n + 1 ) % gN;
+ cur /= gK;
+ dest /= gK;
+
+ if ( !increase ) {
+ vcBegin += vc_mult;
+ }
+ vcEnd = vcBegin + vc_mult - 1;
+
+ int d1_min_c;
+ if ( ( cur % gK ) < ( dest % gK ) ) { // Increasing in d_{i+1}
+ d1_min_c = 2*n;
+ } else if ( ( cur % gK ) != ( dest % gK ) ) { // Decreasing in d_{i+1}
+ d1_min_c = 2*n + 1;
+ } else {
+ d1_min_c = -1;
+ }
+
+ // do we want to 180? if so, the last
+ // route was a misroute in this dimension,
+ // if there is no fault in d_i, just ignore
+ // this dimension, otherwise continue to misroute
+ if ( d1_min_c == in_channel ) {
+ if ( fault ) {
+ d1_min_c = in_channel ^ 1;
+ } else {
+ d1_min_c = -1;
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "PLANAR ADAPTIVE: avoiding 180 in dimension " << n
+ << "." << endl;
+ }
+ }
+
+ if ( d1_min_c != -1 ) {
+ if ( !r->IsFaultyOutput( d1_min_c ) ) {
+ outputs->AddRange( d1_min_c, vcBegin, vcEnd );
+ } else if ( fault ) {
+ // major problem ... fault in d_i and d_{i+1}
+ r->Error( "There seem to be faults in d_i and d_{i+1}" );
+ }
+ } else if ( fault ) { // need to misroute!
+ bool atedge;
+ if ( cur % gK == 0 ) {
+ d1_min_c = 2*n;
+ atedge = true;
+ } else if ( cur % gK == gK - 1 ) {
+ d1_min_c = 2*n + 1;
+ atedge = true;
+ } else {
+ d1_min_c = 2*n + RandomInt( 1 ); // random misroute
+
+ if ( d1_min_c == in_channel ) { // don't 180
+ d1_min_c = in_channel ^ 1;
+ }
+ atedge = false;
+ }
+
+ if ( !r->IsFaultyOutput( d1_min_c ) ) {
+ outputs->AddRange( d1_min_c, vcBegin, vcEnd );
+ } else if ( !atedge && !r->IsFaultyOutput( d1_min_c ^ 1 ) ) {
+ outputs->AddRange( d1_min_c ^ 1, vcBegin, vcEnd );
+ } else {
+ // major problem ... fault in d_i and d_{i+1}
+ r->Error( "There seem to be faults in d_i and d_{i+1}" );
+ }
+ }
+ } else {
+ outputs->AddRange( 2*gN, vcBegin, vcEnd );
+ }
+}
+
+//=============================================================
+/*
+ FIXME: This is broken (note that f->dr is never actually modified).
+ Even if it were, this should really use f->ph instead of introducing a single-
+ use field.
+
+void limited_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ if ( inject ) {
+ outputs->AddRange( -1, vcBegin, vcEnd - 1 );
+ f->dr = 0; // zero dimension reversals
+ return;
+ }
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ if ( cur != dest ) {
+ if ( ( f->vc != vcEnd ) &&
+ ( f->dr != vcEnd - 1 ) ) {
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ int min_port;
+ if ( ( cur % gK ) < ( dest % gK ) ) {
+ min_port = 2*n; // Right
+ } else {
+ min_port = 2*n + 1; // Left
+ }
+
+ // Go in a productive direction with high priority
+ outputs->AddRange( min_port, vcBegin, vcEnd - 1, 2 );
+
+ // Go in the non-productive direction with low priority
+ outputs->AddRange( min_port ^ 0x1, vcBegin, vcEnd - 1, 1 );
+ } else {
+ // Both directions are non-productive
+ outputs->AddRange( 2*n, vcBegin, vcEnd - 1, 1 );
+ outputs->AddRange( 2*n+1, vcBegin, vcEnd - 1, 1 );
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+
+ } else {
+ outputs->AddRange( dor_next_mesh( cur, dest ),
+ vcEnd, vcEnd, 0 );
+ }
+
+ } else { // at destination
+ outputs->AddRange( 2*gN, vcBegin, vcEnd );
+ }
+}
+*/
+//=============================================================
+
+void valiant_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 0; // Phase 0
+ f->intm = RandomInt( gNodes - 1 );
+ }
+
+ if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 1; // Go to phase 1
+ }
+
+ out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest );
+
+ // at the destination router, we don't need to separate VCs by phase
+ if(r->GetID() != f->dest) {
+
+ //each class must have at least 2 vcs assigned or else valiant valiant will deadlock
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ if(f->ph == 0) {
+ vcEnd -= available_vcs;
+ } else {
+ assert(f->ph == 1);
+ vcBegin += available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void valiant_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int phase;
+ if ( in_channel == 2*gN ) {
+ phase = 0; // Phase 0
+ f->intm = RandomInt( gNodes - 1 );
+ } else {
+ phase = f->ph / 2;
+ }
+
+ if ( ( phase == 0 ) && ( r->GetID( ) == f->intm ) ) {
+ phase = 1; // Go to phase 1
+ in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2
+ }
+
+ int ring_part;
+ dor_next_torus( r->GetID( ), (phase == 0) ? f->intm : f->dest, in_channel,
+ &out_port, &ring_part, false );
+
+ f->ph = 2 * phase + ring_part;
+
+ // at the destination router, we don't need to separate VCs by phase, etc.
+ if(r->GetID() != f->dest) {
+
+ int const ring_available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(ring_available_vcs > 0);
+
+ if(ring_part == 0) {
+ vcEnd -= ring_available_vcs;
+ } else {
+ assert(ring_part == 1);
+ vcBegin += ring_available_vcs;
+ }
+
+ int const ph_available_vcs = ring_available_vcs / 2;
+ assert(ph_available_vcs > 0);
+
+ if(phase == 0) {
+ vcEnd -= ph_available_vcs;
+ } else {
+ assert(phase == 1);
+ vcBegin += ph_available_vcs;
+ }
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void valiant_ni_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ // at the destination router, we don't need to separate VCs by destination
+ if(inject || (r->GetID() != f->dest)) {
+
+ int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes;
+ assert(vcs_per_dest > 0);
+
+ vcBegin += f->dest * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+
+ }
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int phase;
+ if ( in_channel == 2*gN ) {
+ phase = 0; // Phase 0
+ f->intm = RandomInt( gNodes - 1 );
+ } else {
+ phase = f->ph / 2;
+ }
+
+ if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 1; // Go to phase 1
+ in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2
+ }
+
+ int ring_part;
+ dor_next_torus( r->GetID( ), (f->ph == 0) ? f->intm : f->dest, in_channel,
+ &out_port, &ring_part, false );
+
+ f->ph = 2 * phase + ring_part;
+
+ // at the destination router, we don't need to separate VCs by phase, etc.
+ if(r->GetID() != f->dest) {
+
+ int const ring_available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(ring_available_vcs > 0);
+
+ if(ring_part == 0) {
+ vcEnd -= ring_available_vcs;
+ } else {
+ assert(ring_part == 1);
+ vcBegin += ring_available_vcs;
+ }
+
+ int const ph_available_vcs = ring_available_vcs / 2;
+ assert(ph_available_vcs > 0);
+
+ if(phase == 0) {
+ vcEnd -= ph_available_vcs;
+ } else {
+ assert(phase == 1);
+ vcBegin += ph_available_vcs;
+ }
+ }
+
+ if (f->watch) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void dim_order_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ph, false );
+
+
+ // at the destination router, we don't need to separate VCs by ring partition
+ if(cur != dest) {
+
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ if ( f->ph == 0 ) {
+ vcEnd -= available_vcs;
+ } else {
+ vcBegin += available_vcs;
+ }
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void dim_order_ni_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, NULL, false );
+
+ // at the destination router, we don't need to separate VCs by destination
+ if(cur != dest) {
+
+ int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes;
+ assert(vcs_per_dest);
+
+ vcBegin += f->dest * vcs_per_dest;
+ vcEnd = vcBegin + vcs_per_dest - 1;
+
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void dim_order_bal_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ph, true );
+
+ // at the destination router, we don't need to separate VCs by ring partition
+ if(cur != dest) {
+
+ int const available_vcs = (vcEnd - vcBegin + 1) / 2;
+ assert(available_vcs > 0);
+
+ if ( f->ph == 0 ) {
+ vcEnd -= available_vcs;
+ } else {
+ assert(f->ph == 1);
+ vcBegin += available_vcs;
+ }
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << r->FullName() << " | "
+ << "Adding VC range ["
+ << vcBegin << ","
+ << vcEnd << "]"
+ << " at output port " << out_port
+ << " for flit " << f->id
+ << " (input port " << in_channel
+ << ", destination " << f->dest << ")"
+ << "." << endl;
+ }
+
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+//=============================================================
+
+void min_adapt_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ outputs->Clear( );
+
+ if(inject) {
+ // injection can use all VCs
+ outputs->AddRange(-1, vcBegin, vcEnd);
+ return;
+ } else if(r->GetID() == f->dest) {
+ // ejection can also use all VCs
+ outputs->AddRange(2*gN, vcBegin, vcEnd);
+ }
+
+ int in_vc;
+ if ( in_channel == 2*gN ) {
+ in_vc = vcEnd; // ignore the injection VC
+ } else {
+ in_vc = f->vc;
+ }
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ int out_port;
+
+ if ( in_vc > ( vcBegin + 1 ) ) { // If not in the escape VCs
+ // Minimal adaptive for all other channels
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ int dist2 = gK - 2 * ( ( ( dest % gK ) - ( cur % gK ) + gK ) % gK );
+
+ if ( dist2 > 0 ) { /*) ||
+ ( ( dist2 == 0 ) && ( RandomInt( 1 ) ) ) ) {*/
+ outputs->AddRange( 2*n, vcBegin+3, vcBegin+3, 1 ); // Right
+ } else {
+ outputs->AddRange( 2*n + 1, vcBegin+3, vcBegin+3, 1 ); // Left
+ }
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+
+ // DOR for the escape channel (VCs 0-1), low priority ---
+ // trick the algorithm with the in channel. want VC assignment
+ // as if we had injected at this node
+ dor_next_torus( r->GetID( ), f->dest, 2*gN,
+ &out_port, &f->ph, false );
+ } else {
+ // DOR for the escape channel (VCs 0-1), low priority
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ph, false );
+ }
+
+ if ( f->ph == 0 ) {
+ outputs->AddRange( out_port, vcBegin, vcBegin, 0 );
+ } else {
+ outputs->AddRange( out_port, vcBegin+1, vcBegin+1, 0 );
+ }
+}
+
+//=============================================================
+
+void dest_tag_fly( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+ assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0)));
+
+ int out_port;
+
+ if(inject) {
+
+ out_port = -1;
+
+ } else {
+
+ int stage = ( r->GetID( ) * gK ) / gNodes;
+ int dest = f->dest;
+
+ while( stage < ( gN - 1 ) ) {
+ dest /= gK;
+ ++stage;
+ }
+
+ out_port = dest % gK;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port, vcBegin, vcEnd );
+}
+
+
+
+//=============================================================
+
+void chaos_torus( const Router *r, const Flit *f,
+ int in_channel, OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+
+ if(inject) {
+ outputs->AddRange(-1, 0, 0);
+ return;
+ }
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ if ( cur != dest ) {
+ for ( int n = 0; n < gN; ++n ) {
+
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ int dist2 = gK - 2 * ( ( ( dest % gK ) - ( cur % gK ) + gK ) % gK );
+
+ if ( dist2 >= 0 ) {
+ outputs->AddRange( 2*n, 0, 0 ); // Right
+ }
+
+ if ( dist2 <= 0 ) {
+ outputs->AddRange( 2*n + 1, 0, 0 ); // Left
+ }
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+ } else {
+ outputs->AddRange( 2*gN, 0, 0 );
+ }
+}
+
+
+//=============================================================
+
+void chaos_mesh( const Router *r, const Flit *f,
+ int in_channel, OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+
+ if(inject) {
+ outputs->AddRange(-1, 0, 0);
+ return;
+ }
+
+ int cur = r->GetID( );
+ int dest = f->dest;
+
+ if ( cur != dest ) {
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ // Add minimal direction in dimension 'n'
+ if ( ( cur % gK ) < ( dest % gK ) ) { // Right
+ outputs->AddRange( 2*n, 0, 0 );
+ } else { // Left
+ outputs->AddRange( 2*n + 1, 0, 0 );
+ }
+ }
+ cur /= gK;
+ dest /= gK;
+ }
+ } else {
+ outputs->AddRange( 2*gN, 0, 0 );
+ }
+}
+
+//=============================================================
+
+void InitializeRoutingMap( const Configuration & config )
+{
+
+ gNumVCs = config.GetInt( "num_vcs" );
+
+ //
+ // traffic class partitions
+ //
+ gReadReqBeginVC = config.GetInt("read_request_begin_vc");
+ if(gReadReqBeginVC < 0) {
+ gReadReqBeginVC = 0;
+ }
+ gReadReqEndVC = config.GetInt("read_request_end_vc");
+ if(gReadReqEndVC < 0) {
+ gReadReqEndVC = gNumVCs / 2 - 1;
+ }
+ gWriteReqBeginVC = config.GetInt("write_request_begin_vc");
+ if(gWriteReqBeginVC < 0) {
+ gWriteReqBeginVC = 0;
+ }
+ gWriteReqEndVC = config.GetInt("write_request_end_vc");
+ if(gWriteReqEndVC < 0) {
+ gWriteReqEndVC = gNumVCs / 2 - 1;
+ }
+ gReadReplyBeginVC = config.GetInt("read_reply_begin_vc");
+ if(gReadReplyBeginVC < 0) {
+ gReadReplyBeginVC = gNumVCs / 2;
+ }
+ gReadReplyEndVC = config.GetInt("read_reply_end_vc");
+ if(gReadReplyEndVC < 0) {
+ gReadReplyEndVC = gNumVCs - 1;
+ }
+ gWriteReplyBeginVC = config.GetInt("write_reply_begin_vc");
+ if(gWriteReplyBeginVC < 0) {
+ gWriteReplyBeginVC = gNumVCs / 2;
+ }
+ gWriteReplyEndVC = config.GetInt("write_reply_end_vc");
+ if(gWriteReplyEndVC < 0) {
+ gWriteReplyEndVC = gNumVCs - 1;
+ }
+
+ /* Register routing functions here */
+
+ // ===================================================
+ // Balfour-Schultz
+ gRoutingFunctionMap["nca_fattree"] = &fattree_nca;
+ gRoutingFunctionMap["anca_fattree"] = &fattree_anca;
+ gRoutingFunctionMap["nca_qtree"] = &qtree_nca;
+ gRoutingFunctionMap["nca_tree4"] = &tree4_nca;
+ gRoutingFunctionMap["anca_tree4"] = &tree4_anca;
+ gRoutingFunctionMap["dor_mesh"] = &dim_order_mesh;
+ gRoutingFunctionMap["xy_yx_mesh"] = &xy_yx_mesh;
+ gRoutingFunctionMap["adaptive_xy_yx_mesh"] = &adaptive_xy_yx_mesh;
+ // End Balfour-Schultz
+ // ===================================================
+
+ gRoutingFunctionMap["dim_order_mesh"] = &dim_order_mesh;
+ gRoutingFunctionMap["dim_order_ni_mesh"] = &dim_order_ni_mesh;
+ gRoutingFunctionMap["dim_order_pni_mesh"] = &dim_order_pni_mesh;
+ gRoutingFunctionMap["dim_order_torus"] = &dim_order_torus;
+ gRoutingFunctionMap["dim_order_ni_torus"] = &dim_order_ni_torus;
+ gRoutingFunctionMap["dim_order_bal_torus"] = &dim_order_bal_torus;
+
+ gRoutingFunctionMap["romm_mesh"] = &romm_mesh;
+ gRoutingFunctionMap["romm_ni_mesh"] = &romm_ni_mesh;
+
+ gRoutingFunctionMap["min_adapt_mesh"] = &min_adapt_mesh;
+ gRoutingFunctionMap["min_adapt_torus"] = &min_adapt_torus;
+
+ gRoutingFunctionMap["planar_adapt_mesh"] = &planar_adapt_mesh;
+
+ // FIXME: This is broken.
+ // gRoutingFunctionMap["limited_adapt_mesh"] = &limited_adapt_mesh;
+
+ gRoutingFunctionMap["valiant_mesh"] = &valiant_mesh;
+ gRoutingFunctionMap["valiant_torus"] = &valiant_torus;
+ gRoutingFunctionMap["valiant_ni_torus"] = &valiant_ni_torus;
+
+ gRoutingFunctionMap["dest_tag_fly"] = &dest_tag_fly;
+
+ gRoutingFunctionMap["chaos_mesh"] = &chaos_mesh;
+ gRoutingFunctionMap["chaos_torus"] = &chaos_torus;
+}
diff --git a/src/intersim2/routefunc.hpp b/src/intersim2/routefunc.hpp
new file mode 100644
index 0000000..bf0c756
--- /dev/null
+++ b/src/intersim2/routefunc.hpp
@@ -0,0 +1,48 @@
+// $Id: routefunc.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ROUTEFUNC_HPP_
+#define _ROUTEFUNC_HPP_
+
+#include "flit.hpp"
+#include "router.hpp"
+#include "outputset.hpp"
+#include "config_utils.hpp"
+
+typedef void (*tRoutingFunction)( const Router *, const Flit *, int in_channel, OutputSet *, bool );
+
+void InitializeRoutingMap( const Configuration & config );
+
+extern map<string, tRoutingFunction> gRoutingFunctionMap;
+
+extern int gNumVCs;
+extern int gReadReqBeginVC, gReadReqEndVC;
+extern int gWriteReqBeginVC, gWriteReqEndVC;
+extern int gReadReplyBeginVC, gReadReplyEndVC;
+extern int gWriteReplyBeginVC, gWriteReplyEndVC;
+
+#endif
diff --git a/src/intersim2/routers/chaos_router.cpp b/src/intersim2/routers/chaos_router.cpp
new file mode 100644
index 0000000..10c6277
--- /dev/null
+++ b/src/intersim2/routers/chaos_router.cpp
@@ -0,0 +1,673 @@
+// $Id: chaos_router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstdlib>
+
+#include "chaos_router.hpp"
+#include "random_utils.hpp"
+#include "globals.hpp"
+
+ChaosRouter::ChaosRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+ : Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ int i;
+
+ if ( inputs != outputs ) {
+ Error( "Chaos router must have equal number of input and output ports" );
+ }
+
+ _buffer_size = config.GetInt( "vc_buf_size" );
+ assert(_buffer_size >= config.GetInt( "const_flits_per_packet" ));
+
+ _multi_queue_size = config.GetInt( "multi_queue_size" );
+
+ _cur_channel = 0;
+ _read_stall = 0;
+
+ // Routing
+
+ string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ _input_route.resize(_inputs);
+
+ for ( i = 0; i < _inputs; ++i ) {
+ _input_route[i] = new OutputSet( );
+ }
+
+ _mq_route.resize(_multi_queue_size);
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ _mq_route[i] = new OutputSet( );
+ }
+
+ // Alloc pipelines (to simulate processing/transmission delays)
+
+ _crossbar_pipe =
+ new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs,
+ _crossbar_delay );
+
+ // Input and output queues
+
+ _input_frame.resize(_inputs);
+ _output_frame.resize(_outputs);
+ _multi_queue.resize(_multi_queue_size);
+
+ _credit_queue.resize(_inputs);
+
+ _input_state.resize(_inputs, empty);
+ _input_output_match.resize(_inputs, -1);
+ _input_mq_match.resize(_inputs, -1);
+
+ _output_matched.resize(_outputs, false);
+ _next_queue_cnt.resize(_outputs, 0);
+
+ _multi_match.resize(_multi_queue_size, -1);
+ _mq_age.resize(_multi_queue_size);
+ _mq_matched.resize(_multi_queue_size, false);
+ _multi_state.resize(_multi_queue_size, empty);
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ _multi_state[i] = empty;
+ _multi_match[i] = -1;
+ _mq_matched[i] = false;
+ }
+}
+
+ChaosRouter::~ChaosRouter( )
+{
+ int i;
+
+ delete _crossbar_pipe;
+
+ for ( i = 0; i < _inputs; ++i ) {
+ delete _input_route[i];
+ }
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ delete _mq_route[i];
+ }
+}
+
+void ChaosRouter::ReadInputs( )
+{
+ Flit *f;
+ Credit *c;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ f = _input_channels[input]->Receive();
+
+ if ( f ) {
+ _input_frame[input].push( f );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit arriving at " << FullName()
+ << " on channel " << input << endl
+ << *f;
+ }
+
+ switch( _input_state[input] ) {
+ case empty:
+ if ( f->head ) {
+ if ( f->tail ) {
+ _input_state[input] = full;
+ } else {
+ _input_state[input] = filling;
+ }
+ _rf( this, f, input, _input_route[input], false );
+ } else {
+ cout << *f;
+ Error( "Empty buffer received non-head flit!" );
+ }
+ break;
+
+ case filling:
+ if ( f->tail ) {
+ _input_state[input] = full;
+ } else if ( f->head ) {
+ Error( "Input buffer received another head before previous tail!" );
+ }
+ break;
+
+ case full:
+ Error( "Received flit while full!" );
+ break;
+
+ case leaving:
+ if ( f->head ) {
+ _input_state[input] = shared;
+
+ if ( f->tail ) {
+ Error( "Received single-flit packet in leaving state!" );
+ }
+ } else {
+ cout << *f;
+ Error( "Received non-head flit while packet leaving!" );
+ }
+ break;
+
+ case cut_through:
+ if ( f->tail ) {
+ _input_state[input] = leaving;
+ }
+ if ( f->head ) {
+ cout << *f;
+ Error( "Received head flit in cut through buffer!" );
+ }
+ break;
+
+ case shared:
+ if ( f->head ) {
+ Error( "Shared buffer received another head!" );
+ } else if ( f->tail ) {
+ cout << "Input " << input << endl;
+ cout << *f;
+ Error( "Shared buffer received another tail!" );
+ }
+ break;
+ }
+ }
+ }
+
+ // Process incoming credits
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = _output_credits[output]->Receive();
+
+ if ( c ) {
+ _next_queue_cnt[output]--;
+
+ if ( _next_queue_cnt[output] < 0 ) {
+ Error( "Next queue count fell below zero!" );
+ }
+
+ c->Free();
+ }
+ }
+}
+
+void ChaosRouter::_InternalStep( )
+{
+ _NextInterestingChannel( );
+ _OutputAdvance( );
+
+ _crossbar_pipe->Advance( );
+}
+
+void ChaosRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+bool ChaosRouter::_IsInjectionChan( int chan ) const
+{
+ return ( chan == _inputs - 1 );
+}
+
+bool ChaosRouter::_IsEjectionChan( int chan ) const
+{
+ return ( chan == _outputs - 1 );
+}
+
+bool ChaosRouter::_InputReady( int input ) const
+{
+ bool ready = false;
+
+ if ( ( _input_state[input] == filling ) ||
+ ( _input_state[input] == full ) ) {
+ ready = true;
+ }
+
+ return ready;
+}
+
+bool ChaosRouter::_OutputFull( int out ) const
+{
+ return ( _output_frame[out].size( ) >= (size_t)_buffer_size );
+}
+
+bool ChaosRouter::_OutputAvail( int out ) const
+{
+ return ( ( !_output_matched[out] ) && ( _output_frame[out].empty( ) ) );
+ //&& ( _next_queue_cnt[out] == 0 ) );
+ //return ( ( !_output_matched[out] ) && !_OutputFull( out ) );
+}
+
+bool ChaosRouter::_MultiQueueFull( int mq ) const
+{
+ return ( _multi_queue[mq].size( ) >= (size_t)_buffer_size );
+}
+
+int ChaosRouter::_InputForOutput( int output ) const
+{
+ // return an input that prefers this output
+
+ int input;
+ int offset = RandomInt( _inputs - 1 );
+ bool match = false;
+
+ for ( int i = 0; ( i < _inputs ) && ( !match ); ++i ) {
+ input = ( i + offset ) % _inputs;
+
+ if ( _InputReady( input ) &&
+ ( ! _input_route[input]->OutputEmpty( output ) ) ) {
+ match = true;
+ }
+ }
+
+ return match ? input : -1;
+}
+
+int ChaosRouter::_MultiQueueForOutput( int output ) const
+{
+ // return oldest multi queue that prefers the output,
+ // or if none prefer and the multi queue is full,
+ // return a random entry
+
+ int mq_oldest = -1;
+ int mq_age;
+
+ int m, r;
+
+ bool isfull = true;
+
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ if ( ( _multi_match[i] == -1 ) &&
+ ( ( _multi_state[i] == full ) ||
+ ( _multi_state[i] == filling ) ) ) {
+
+ if ( ( !_mq_route[i]->OutputEmpty( output ) ) &&
+ ( ( mq_oldest == -1 ) || ( _mq_age[i] > mq_age ) ) ) {
+ mq_oldest = i;
+ mq_age = _mq_age[i];
+ }
+ }
+
+ // deroute only if all queues contain head flits ...
+
+ if ( ( _multi_state[i] != full ) &&
+ ( _multi_state[i] != filling ) &&
+ ( _multi_state[i] != shared ) ) {
+ isfull = false;
+ }
+ }
+
+ // Don't deroute MQs to the ejection channel
+ if ( ( mq_oldest == -1 ) && isfull &&
+ ( !_IsEjectionChan( output ) ) ) {
+ r = RandomInt( _multi_queue_size - 1 );
+
+ // Find first routable multi-queue
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ m = ( i + r ) % _multi_queue_size;
+ if ( ( _multi_state[m] == filling ) ||
+ ( _multi_state[m] == full ) ) {
+ mq_oldest = m;
+ //cout << "DEROUTING at " << FullName() << endl;
+ break;
+ }
+ }
+
+ if ( mq_oldest == -1 ) {
+ cout << "write stall" << endl;
+ }
+ }
+
+ return mq_oldest;
+}
+
+int ChaosRouter::_FindAvailMultiQueue( ) const
+{
+ // return any empty multi queue slot
+
+ int avail = -1;
+
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ if ( ( !_MultiQueueFull( i ) ) &&
+ ( !_mq_matched[i] ) ) {
+ avail = i;
+ break;
+ }
+ }
+
+ return avail;
+}
+
+void ChaosRouter::_NextInterestingChannel( )
+{
+ bool interesting;
+
+ int mq_index;
+ int in_index;
+ int mq_avail;
+
+ int c;
+
+ interesting = false;
+ mq_index = -1;
+ in_index = -1;
+
+ // A channel is interesting if
+ //
+ // ( output frame available and
+ // ( ( a multiqueue packet wants output channel ) or
+ // ( an input packet wants output channel ) or
+ // ( the multiqueue is full ) ) )
+ // or
+ // ( the packet at the input channel is stalled )
+
+ for ( c = 0; ( c < _inputs ) && ( !interesting ); ++c ) {
+ if ( _OutputAvail( _cur_channel ) ) {
+ mq_index = _MultiQueueForOutput( _cur_channel );
+ in_index = _InputForOutput( _cur_channel );
+
+ if ( ( mq_index != -1 ) || ( in_index != -1 ) ) {
+ interesting = true;
+ }
+ }
+
+ if ( _input_state[_cur_channel] == full ) {
+ interesting = true;
+ }
+
+ if ( !interesting ) {
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ }
+ }
+
+ if ( interesting ) {
+ //cout << _cur_channel << " is interesting at " << FullName() << endl;
+
+ if ( mq_index != -1 ) {
+ //cout << "Match for multi-queue " << mq_index << " at " << FullName()
+ // << ", output matched = " << _output_matched[_cur_channel] << endl;
+
+ _output_matched[_cur_channel] = true;
+ _multi_match[mq_index] = _cur_channel;
+ } else if ( in_index != -1 ) {
+ _output_matched[_cur_channel] = true;
+ _input_output_match[in_index] = _cur_channel;
+
+ //cout << "Match for input " << in_index << " at " << FullName() << endl;
+
+ if ( _input_state[in_index] == full ) {
+ _input_state[in_index] = leaving;
+ } else if ( _input_state[in_index] == filling ) {
+ _input_state[in_index] = cut_through;
+ } else {
+ Error( "Tried to route input through crossbar that was not full or filling!" );
+ }
+ }
+
+ // Any non-injection channel that is routable is
+ // directed to the multi-queue
+ if ( ( ( _input_state[_cur_channel] == filling ) ||
+ ( _input_state[_cur_channel] == full ) ) &&
+ ( !_IsInjectionChan( _cur_channel ) ) ) {
+ ++_read_stall;
+ } else {
+ // go to next channel for the next cycle
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ _read_stall = 0;
+ }
+ }
+
+ if ( _read_stall > 0 ) {
+ mq_avail = _FindAvailMultiQueue( );
+
+ if ( mq_avail != -1 ) {
+ if ( _input_state[_cur_channel] == full ) {
+ _input_state[_cur_channel] = leaving;
+ } else if ( _input_state[_cur_channel] == filling ) {
+ _input_state[_cur_channel] = cut_through;
+ } else {
+ cout << "Input " << _cur_channel << " state = "
+ << _input_state[_cur_channel] << endl;
+ Error( "Tried to route input throught multi-queue that was not full or filling!" );
+ }
+
+ _input_mq_match[_cur_channel] = mq_avail;
+ _mq_matched[mq_avail] = true;
+
+ // go to next channel for the next cycle
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ _read_stall = 0;
+ } else {
+ ++_read_stall;
+ //cout << "stalling at input " << _cur_channel << " (count = " << _read_stall << ")" << endl;
+ }
+ }
+}
+
+void ChaosRouter::_OutputAdvance( )
+{
+ Flit *f, *f2;
+ Credit *c;
+ bool advanced;
+ int mq;
+
+ _crossbar_pipe->WriteAll( 0 );
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ if ( ( ( _input_output_match[i] != -1 ) ||
+ ( _input_mq_match[i] != -1 ) ) &&
+ ( !_input_frame[i].empty( ) ) ) {
+
+ advanced = false;
+ f = _input_frame[i].front( );
+
+ /*if ( ! ) {
+
+ } else {
+ cout << "Input = " << i
+ << ", input_output_match = " << _input_output_match[i]
+ << ", input_mq_match = " << _input_mq_match[i] << endl;
+ Error( "Input queue empty, but matched!" );
+ }*/
+
+ if ( _input_output_match[i] != -1 ) {
+ if ( f->tail ) {
+ _output_matched[_input_output_match[i]] = false;
+ }
+
+ _crossbar_pipe->Write( f, _input_output_match[i] );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit traversing crossbar from input queue "
+ << i << " at "
+ << FullName() << endl
+ << *f;
+ }
+
+ advanced = true;
+
+ } else if ( !_MultiQueueFull( _input_mq_match[i] ) ) {
+
+ mq = _input_mq_match[i];
+
+ if ( f->head ) {
+ _rf( this, f, i, _mq_route[mq], false );
+ _mq_age[mq] = 0;
+
+ if ( _multi_state[mq] == empty ) {
+ _multi_state[mq] = filling;
+ } else if ( _multi_state[mq] == leaving ) {
+ _multi_state[mq] = shared;
+ } else {
+ Error( "Multi-queue received head while not empty or leaving!" );
+ }
+ }
+
+ if ( f->tail ) {
+ _mq_matched[mq] = false;
+
+ if ( _multi_state[mq] == filling ) {
+ _multi_state[mq] = full;
+ } else if ( _multi_state[mq] == cut_through ) {
+ _multi_state[mq] = leaving;
+ } else {
+ Error( "Multi-queue received tail while not filling or cutting-through!" );
+ }
+ }
+
+ _multi_queue[mq].push( f );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit stored in multiqueue at "
+ << FullName() << endl
+ << "State = " << _multi_state[mq] << endl
+ << *f;
+ }
+
+ advanced = true;
+ }
+
+ if ( advanced ) {
+ _input_frame[i].pop( );
+
+ if ( f->tail ) { // last in packet, update state
+ if ( _input_state[i] == leaving ) {
+ _input_state[i] = empty;
+ } else if ( _input_state[i] == shared ) {
+ _input_state[i] = filling;
+ f2 = _input_frame[i].front( );
+ // update routes
+ _rf( this, f2, i, _input_route[i], false );
+ }
+
+ _input_output_match[i] = -1;
+ _input_mq_match[i] = -1;
+ }
+
+ c = Credit::New( );
+ c->vc.insert(0);
+ _credit_queue[i].push( c );
+ }
+ }
+ }
+
+ for ( int m = 0; m < _multi_queue_size; ++m ) {
+ if ( _multi_match[m] != -1 ) {
+ if ( !_multi_queue[m].empty( ) ) {
+ f = _multi_queue[m].front( );
+ _multi_queue[m].pop( );
+ } else {
+ cout << "State = " << _multi_state[m] << endl;
+ Error( "Multi queue empty, but matched!" );
+ }
+
+ _crossbar_pipe->Write( f, _multi_match[m] );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit traversing crossbar from multiqueue slot "
+ << m << " at "
+ << FullName() << endl
+ << *f;
+ }
+
+ if ( f->head ) {
+ if ( _multi_state[m] == filling ) {
+ _multi_state[m] = cut_through;
+ } else if ( _multi_state[m] == full ) {
+ _multi_state[m] = leaving;
+ } else {
+ Error( "Multi-queue sent head while not filling or full!" );
+ }
+ }
+
+ if ( f->tail ) {
+ _output_matched[_multi_match[m]] = false;
+ _multi_match[m] = -1;
+
+ if ( _multi_state[m] == shared ) {
+ _multi_state[m] = filling;
+ } else if ( _multi_state[m] == leaving ) {
+ _multi_state[m] = empty;
+ } else {
+ cout << "State = " << _multi_state[m] << endl;
+ cout << *f;
+ Error( "Multi-queue sent tail while not leaving or shared!" );
+ }
+ }
+ }
+
+ _mq_age[m]++;
+ }
+}
+
+
+void ChaosRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ Flit *f = _crossbar_pipe->Read( output );
+
+ if ( f ) {
+ _output_frame[output].push( f );
+ f->hops++;
+ }
+
+ if ( ( _next_queue_cnt[output] < _buffer_size ) &&
+ ( !_output_frame[output].empty( ) ) ) {
+ _output_channels[output]->Send( _output_frame[output].front( ) );
+ _output_frame[output].pop( );
+ ++_next_queue_cnt[output];
+ }
+ }
+}
+
+void ChaosRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_credit_queue[input].empty( ) ) {
+ Credit *c = _credit_queue[input].front( );
+ _credit_queue[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+void ChaosRouter::Display( ostream & os ) const
+{
+}
diff --git a/src/intersim2/routers/chaos_router.hpp b/src/intersim2/routers/chaos_router.hpp
new file mode 100644
index 0000000..df843ff
--- /dev/null
+++ b/src/intersim2/routers/chaos_router.hpp
@@ -0,0 +1,132 @@
+// $Id: chaos_router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CHAOS_ROUTER_HPP_
+#define _CHAOS_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "allocator.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "buffer_state.hpp"
+#include "pipefifo.hpp"
+#include "vc.hpp"
+
+class ChaosRouter : public Router {
+
+ tRoutingFunction _rf;
+
+ vector<OutputSet*> _input_route;
+ vector<OutputSet*> _mq_route;
+
+ enum eQState {
+ empty, // input avail
+ filling, // >**H ready to send
+ full, // T****H ready to send
+ leaving, // T***> input avail
+ cut_through, // >***>
+ shared // >**HT**>
+ };
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+
+ int _multi_queue_size;
+ int _buffer_size;
+
+ vector<queue<Flit *> > _input_frame;
+ vector<queue<Flit *> > _output_frame;
+ vector<queue<Flit *> > _multi_queue;
+
+ vector<int> _next_queue_cnt;
+
+ vector<queue<Credit *> > _credit_queue;
+
+ vector<eQState> _input_state;
+ vector<eQState> _multi_state;
+
+ vector<int> _input_output_match;
+ vector<int> _input_mq_match;
+ vector<int> _multi_match;
+
+ vector<int> _mq_age;
+
+ vector<bool> _output_matched;
+ vector<bool> _mq_matched;
+
+ int _cur_channel;
+ int _read_stall;
+
+ bool _IsInjectionChan( int chan ) const;
+ bool _IsEjectionChan( int chan ) const;
+
+ bool _InputReady( int input ) const;
+ bool _OutputFull( int out ) const;
+ bool _OutputAvail( int out ) const;
+ bool _MultiQueueFull( int mq ) const;
+
+ int _InputForOutput( int output ) const;
+ int _MultiQueueForOutput( int output ) const;
+ int _FindAvailMultiQueue( ) const;
+
+ void _NextInterestingChannel( );
+ void _OutputAdvance( );
+ void _SendFlits( );
+ void _SendCredits( );
+
+ virtual void _InternalStep( );
+
+public:
+ ChaosRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ virtual ~ChaosRouter( );
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ virtual int GetUsedCredit(int out) const {return 0;}
+ virtual int GetBufferOccupancy(int i) const {return 0;}
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const {return 0;}
+ virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;}
+#endif
+
+ virtual vector<int> UsedCredits() const { return vector<int>(); }
+ virtual vector<int> FreeCredits() const { return vector<int>(); }
+ virtual vector<int> MaxCredits() const { return vector<int>(); }
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/routers/event_router.cpp b/src/intersim2/routers/event_router.cpp
new file mode 100644
index 0000000..e3f9712
--- /dev/null
+++ b/src/intersim2/routers/event_router.cpp
@@ -0,0 +1,890 @@
+// $Id: event_router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstdlib>
+#include <cassert>
+
+#include "event_router.hpp"
+#include "stats.hpp"
+#include "globals.hpp"
+
+EventRouter::EventRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+ : Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ ostringstream module_name;
+
+ _vcs = config.GetInt( "num_vcs" );
+
+ // Cut-through mode --- packets are not broken
+ // up and input buffers are assumed to be
+ // expressed in units of maximum size packets.
+
+ _vct = config.GetInt( "vct" );
+
+ // Routing
+
+ string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ // Alloc VC's
+
+ _buf.resize(_inputs);
+ _active.resize(_inputs);
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ module_name << "buf_" << i;
+ _buf[i] = new Buffer( config, _outputs, this, module_name.str( ) );
+ module_name.seekp( 0, ios::beg );
+ _active[i].resize(_vcs, false);
+ }
+
+ // Alloc next VCs' state
+
+ _output_state.resize(_outputs);
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ module_name << "output" << o << "_vc_state";
+ _output_state[o] = new EventNextVCState(config, this, module_name.str());
+ module_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc arbiters
+
+ _arrival_arbiter.resize(_outputs);
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ module_name << "arrival_arb_output" << o;
+ _arrival_arbiter[o] =
+ new PriorityArbiter( config, this, module_name.str( ), _inputs );
+ module_name.seekp( 0, ios::beg );
+ }
+
+ _transport_arbiter.resize(_inputs);
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ module_name << "transport_arb_input" << i;
+ _transport_arbiter[i] =
+ new PriorityArbiter( config, this, module_name.str( ), _outputs );
+ module_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc pipelines (to simulate processing/transmission delays)
+
+ _crossbar_pipe =
+ new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs,
+ _crossbar_delay );
+
+ _credit_pipe =
+ new PipelineFIFO<Credit>( this, "credit_pipeline", _inputs,
+ _credit_delay );
+
+ _arrival_pipe =
+ new PipelineFIFO<tArrivalEvent>( this, "arrival_pipeline", _inputs,
+ 0 /* FIX THIS EVENTUALLY */);
+
+ // Queues
+
+ _input_buffer.resize(_inputs);
+ _output_buffer.resize(_outputs);
+
+ _in_cred_buffer.resize(_inputs);
+ _out_cred_buffer.resize(_outputs);
+
+ _arrival_queue.resize(_inputs);
+ _transport_queue.resize(_outputs);
+
+ // Misc.
+
+ _transport_free.resize(_inputs, true);
+ _transport_match.resize(_inputs, -1);
+}
+
+EventRouter::~EventRouter( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete _buf[i];
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ delete _output_state[o];
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ delete _arrival_arbiter[o];
+ }
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete _transport_arbiter[i];
+ }
+
+ delete _crossbar_pipe;
+ delete _credit_pipe;
+ delete _arrival_pipe;
+}
+
+void EventRouter::ReadInputs( )
+{
+ _ReceiveFlits( );
+ _ReceiveCredits( );
+}
+
+void EventRouter::_InternalStep( )
+{
+ // Receive incoming flits
+ _IncomingFlits( );
+
+ // The input pipe simulates routing delay
+ _arrival_pipe->Advance( );
+
+ // Clear output requests
+ for ( int output = 0; output < _outputs; ++output ) {
+ _arrival_arbiter[output]->Clear( );
+ }
+
+ // Check input arrival queues and generate
+ // requests for the outputs
+ for ( int input = 0; input < _inputs; ++input ) {
+ _ArrivalRequests( input );
+ }
+
+ // Arbitrate between requests at outputs
+ for ( int output = 0; output < _outputs; ++output ) {
+ _ArrivalArb( output );
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ _transport_arbiter[input]->Clear( );
+ }
+
+ _crossbar_pipe->WriteAll( 0 );
+ _credit_pipe->WriteAll( 0 );
+
+ // Generate transport events and their
+ // requests for the inputs
+ for ( int output = 0; output < _outputs; ++output ) {
+ _TransportRequests( output );
+ }
+
+ // Arbitrate between requests at inputs
+ for ( int input = 0; input < _inputs; ++input ) {
+ _TransportArb( input );
+ }
+
+ _crossbar_pipe->Advance( );
+ _credit_pipe->Advance( );
+
+ _OutputQueuing( );
+}
+
+void EventRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+void EventRouter::_ReceiveFlits( )
+{
+ Flit *f;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ f = _input_channels[input]->Receive();
+
+ if ( f ) {
+ _input_buffer[input].push( f );
+ }
+ }
+}
+
+void EventRouter::_ReceiveCredits( )
+{
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = _output_credits[output]->Receive();
+
+ if ( c ) {
+ _out_cred_buffer[output].push( c );
+ }
+ }
+}
+
+void EventRouter::_ProcessWaiting( int output, int out_vc )
+{
+ // out_vc just sent the transport event for out_vc,
+ // check if any events are queued on that vc. if so,
+ // generate another transport event and set the
+ // owner of the vc, otherwise set the vc to idle.
+
+ int credits;
+
+ tTransportEvent *tevt;
+
+ EventNextVCState::tWaiting *w;
+
+ if ( _output_state[output]->IsWaiting( out_vc ) ) {
+
+ // State remains as busy, but the waiting VC takes over
+ w = _output_state[output]->PopWaiting( out_vc );
+
+ _output_state[output]->SetState( out_vc, EventNextVCState::busy );
+ _output_state[output]->SetInput( out_vc, w->input );
+ _output_state[output]->SetInputVC( out_vc, w->vc );
+
+ if ( w->watch ) {
+ cout << "Dequeuing waiting arrival event at " << FullName()
+ << " for flit " << w->id << endl;
+ }
+
+ credits = _output_state[output]->GetCredits( out_vc );
+
+ // Try to queue a transmit event for a waiting packet
+ if ( credits > 0 ) {
+ tevt = new tTransportEvent;
+ tevt->src_vc = w->vc;
+ tevt->dst_vc = out_vc;
+ tevt->input = w->input;
+ tevt->watch = w->watch; // just to have something here
+ tevt->id = w->id;
+
+ _transport_queue[output].push( tevt );
+
+ if ( tevt->watch ) {
+ cout << "Injecting transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+
+ credits--;
+ _output_state[output]->SetCredits( out_vc, credits );
+ _output_state[output]->SetPresence( out_vc, w->pres - 1 );
+
+ } else {
+ // No credits available, just store presence
+ _output_state[output]->SetPresence( out_vc, w->pres );
+ }
+
+ delete w;
+
+ } else {
+ // Tail sent, none waiting => VC is idle
+ _output_state[output]->SetState( out_vc, EventNextVCState::idle );
+ }
+}
+
+void EventRouter::_IncomingFlits( )
+{
+ Flit *f;
+ Buffer *cur_buf;
+
+ tArrivalEvent *aevt;
+
+ _arrival_pipe->WriteAll( 0 );
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_input_buffer[input].empty( ) ) {
+ f = _input_buffer[input].front( );
+ _input_buffer[input].pop( );
+
+ cur_buf = _buf[input];
+ int vc = f->vc;
+
+ cur_buf->AddFlit( vc, f );
+
+ // Head flit arriving at idle VC
+ if ( !_active[input][vc] ) {
+
+ if ( !f->head ) {
+ cout << "Non-head flit:" << endl;
+ cout << *f;
+ Error( "Received non-head flit at idle VC" );
+ }
+
+ const OutputSet *route_set;
+ int out_vc, out_port;
+
+ cur_buf->Route( vc, _rf, this, f, input );
+ route_set = cur_buf->GetRouteSet( vc );
+
+ if ( !route_set->GetPortVC( &out_port, &out_vc ) ) {
+ Error( "The event-driven router requires routing functions with a single (port,vc) output" );
+ }
+
+ cur_buf->SetOutput( vc, out_port, out_vc );
+ _active[input][vc] = true;
+ } else {
+ if ( f->head ) {
+ cout << *f;
+ Error( "Received head flit at non-idle VC." );
+ }
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Received flit at " << FullName() << ". Output port = "
+ << cur_buf->GetOutputPort( vc ) << ", output VC = "
+ << cur_buf->GetOutputVC( vc ) << endl
+ << *f;
+ }
+
+ // In cut-through mode, only head flits generate arrivals,
+ // otherwise all flits generate
+
+ if ( ( !_vct ) || ( _vct && f->head ) ) {
+ // Add the arrival event to a delay pipeline to
+ // account for routing/decoding time
+
+ aevt = new tArrivalEvent;
+
+ aevt->input = input;
+ aevt->output = cur_buf->GetOutputPort( vc );
+ aevt->src_vc = f->vc;
+ aevt->dst_vc = cur_buf->GetOutputVC( vc );
+ aevt->head = f->head;
+ aevt->tail = f->tail;
+
+ //if ( f->head && f->tail ) {
+ // Error( "Head/tail packets not supported." );
+ //}
+
+ aevt->watch = f->watch;
+ aevt->id = f->id;
+
+ _arrival_pipe->Write( aevt, input );
+
+ if ( aevt->watch ) {
+ cout << "Injected arrival event at " << FullName()
+ << " for flit " << aevt->id << endl;
+ }
+ }
+ }
+ }
+}
+
+void EventRouter::_ArrivalRequests( int input )
+{
+ tArrivalEvent *aevt;
+
+ aevt = _arrival_pipe->Read( input );
+ if ( aevt ) {
+ _arrival_queue[input].push( aevt );
+ }
+
+ if ( !_arrival_queue[input].empty( ) ) {
+ aevt = _arrival_queue[input].front( );
+ _arrival_arbiter[aevt->output]->AddRequest( input );
+ }
+}
+
+void EventRouter::_SendTransport( int input, int output, tArrivalEvent *aevt )
+{
+ // Try to send a transport event
+
+ tTransportEvent *tevt;
+
+ int credits;
+ int pres;
+
+ credits = _output_state[output]->GetCredits( aevt->dst_vc );
+
+ if ( credits > 0 ) {
+ // Take a credit and queue a transport event
+ credits--;
+ _output_state[output]->SetCredits( aevt->dst_vc, credits );
+
+ tevt = new tTransportEvent;
+ tevt->src_vc = aevt->src_vc;
+ tevt->dst_vc = aevt->dst_vc;
+ tevt->input = input;
+ tevt->watch = aevt->watch;
+ tevt->id = aevt->id;
+
+ _transport_queue[output].push( tevt );
+
+ if ( tevt->watch ) {
+ cout << "Injecting transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+ } else {
+ if ( aevt->watch ) {
+ cout << "No credits available at " << FullName()
+ << " for flit " << aevt->id << " storing presence." << endl;
+ }
+
+ // No credits available, just store presence
+ pres = _output_state[output]->GetPresence( aevt->dst_vc );
+ _output_state[output]->SetPresence( aevt->dst_vc, pres + 1 );
+ }
+}
+
+void EventRouter::_ArrivalArb( int output )
+{
+ tArrivalEvent *aevt;
+ tTransportEvent *tevt;
+ Credit *c;
+
+ EventNextVCState::tWaiting *w;
+
+ int input;
+ int credits;
+ int pres;
+
+ // Incoming credits can produce or enable
+ // transport events --- process them first
+
+ if ( !_out_cred_buffer[output].empty( ) ) {
+ c = _out_cred_buffer[output].front( );
+ _out_cred_buffer[output].pop( );
+
+ assert( c->vc.size() == 1 );
+ int vc = *c->vc.begin();
+
+ EventNextVCState::eNextVCState state =
+ _output_state[output]->GetState( vc );
+
+ credits = _output_state[output]->GetCredits( vc );
+ pres = _output_state[output]->GetPresence( vc );
+
+ if ( _vct ) {
+ // In cut-through mode, only head credits indicate a change in
+ // channel state.
+
+ if ( c->head ) {
+ credits++;
+ _output_state[output]->SetCredits( vc, credits );
+ _ProcessWaiting( output, vc );
+ }
+ } else {
+ credits++;
+ _output_state[output]->SetCredits( vc, credits );
+
+ if ( c->tail ) { // tail flit -- recycle VC
+ if ( state != EventNextVCState::busy ) {
+ Error( "Received tail credit at non-busy output VC" );
+ }
+
+ _ProcessWaiting( output, vc );
+ } else if ( ( state == EventNextVCState::busy ) && ( pres > 0 ) ) {
+ // Flit is present => generate transport event
+
+ tevt = new tTransportEvent;
+ tevt->input = _output_state[output]->GetInput( vc );
+ tevt->src_vc = _output_state[output]->GetInputVC( vc );
+ tevt->dst_vc = vc;
+ tevt->watch = false;
+ tevt->id = -1;
+
+ _transport_queue[output].push( tevt );
+
+ pres--;
+ credits--;
+ _output_state[output]->SetPresence( vc, pres );
+ _output_state[output]->SetCredits( vc, credits );
+ }
+ }
+
+ c->Free();
+ }
+
+ // Now process arrival events
+
+ _arrival_arbiter[output]->Arbitrate( );
+ input = _arrival_arbiter[output]->Match( );
+
+ if ( input != -1 ) {
+ // Winning arrival event gets access to output
+
+ aevt = _arrival_queue[input].front( );
+ _arrival_queue[input].pop( );
+
+ if ( aevt->watch ) {
+ cout << "Processing arrival event at " << FullName()
+ << " for flit " << aevt->id << endl;
+ }
+
+ EventNextVCState::eNextVCState state =
+ _output_state[output]->GetState( aevt->dst_vc );
+
+ if ( aevt->head ) { // Head flits
+ if ( state == EventNextVCState::idle ) {
+ // Allocate the output VC and queue a transport event
+ _output_state[output]->SetState( aevt->dst_vc, EventNextVCState::busy );
+ _output_state[output]->SetInput( aevt->dst_vc, input );
+ _output_state[output]->SetInputVC( aevt->dst_vc, aevt->src_vc );
+
+ _SendTransport( input, output, aevt );
+ } else {
+ // VC busy => queue a waiting event
+
+ w = new EventNextVCState::tWaiting;
+
+ w->input = input;
+ w->vc = aevt->src_vc;
+ w->id = aevt->id;
+ w->watch = aevt->watch;
+ w->pres = 1;
+
+ _output_state[output]->PushWaiting( aevt->dst_vc, w );
+ }
+ } else {
+ if ( _vct ) {
+ Error( "Received arrival event for non-head flit in cut-through mode" );
+ }
+
+ if ( state != EventNextVCState::busy ) {
+ cout << "flit id = " << aevt->id << endl;
+ Error( "Received a body flit at a non-busy output VC" );
+ }
+
+ if ( ( !_output_state[output]->IsInputWaiting( aevt->dst_vc, input, aevt->src_vc ) ) &&
+ ( input == _output_state[output]->GetInput( aevt->dst_vc ) ) &&
+ ( aevt->src_vc == _output_state[output]->GetInputVC( aevt->dst_vc ) ) ) {
+ // Body flit part of the current active VC => queue transport event
+ // (the weird IsInputWaiting call handles a body flit waiting in addition
+ // to a head flit)
+
+ _SendTransport( input, output, aevt );
+ } else {
+
+ // VC busy with a differnet transaction => update waiting event
+ _output_state[output]->IncrWaiting( aevt->dst_vc, input, aevt->src_vc );
+ }
+ }
+
+ delete aevt;
+ }
+}
+
+void EventRouter::_TransportRequests( int output )
+{
+ tTransportEvent *tevt;
+
+ if ( !_transport_queue[output].empty( ) ) {
+ tevt = _transport_queue[output].front( );
+ _transport_arbiter[tevt->input]->AddRequest( output );
+ }
+}
+
+void EventRouter::_TransportArb( int input )
+{
+ tTransportEvent *tevt;
+
+ int output;
+ Buffer *cur_buf;
+ Flit *f;
+ Credit *c;
+
+ if ( _transport_free[input] ) {
+ _transport_arbiter[input]->Arbitrate( );
+ output = _transport_arbiter[input]->Match( );
+ } else {
+ output = _transport_match[input];
+ }
+
+ if ( output != -1 ) {
+ // This completes the match from input to output =>
+ // one flit can be transferred
+
+ tevt = _transport_queue[output].front( );
+
+ if ( tevt->watch ) {
+ cout << "Processing transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+
+ cur_buf = _buf[input];
+ int vc = tevt->src_vc;
+
+ // Some sanity checking first
+
+ if ( !_active[input][vc] ) {
+ Error( "Non-active VC received grant." );
+ }
+
+ if ( cur_buf->Empty( vc ) ) {
+ return; //Error( "Empty VC received grant." );
+ }
+
+ if ( tevt->dst_vc != cur_buf->GetOutputVC( vc ) ) {
+ Error( "Transport event's VC does not match input's destination VC." );
+ }
+
+ f = cur_buf->RemoveFlit( vc );
+
+ if ( _vct ) {
+ if ( f->tail ) {
+ _transport_free[input] = true;
+ _transport_match[input] = -1;
+
+ _transport_queue[output].pop( );
+ delete tevt;
+
+ _active[input][vc] = false;
+ } else {
+ _transport_free[input] = false;
+ _transport_match[input] = output;
+ }
+ } else {
+ _transport_free[input] = true;
+ _transport_match[input] = -1;
+
+ _transport_queue[output].pop( );
+ delete tevt;
+
+ if ( f->tail ) {
+ _active[input][vc] = false;
+ }
+ }
+
+ c = Credit::New( );
+ c->vc.insert(f->vc);
+ c->head = f->head;
+ c->tail = f->tail;
+ c->id = f->id;
+ _credit_pipe->Write( c, input );
+
+ if ( f->watch && c->tail ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << FullName() << " sending tail credit back for flit " << f->id << endl;
+ }
+
+ // Update and forward the flit to the crossbar
+
+ f->hops++;
+ f->vc = cur_buf->GetOutputVC( vc );
+ _crossbar_pipe->Write( f, output );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Forwarding flit through crossbar at " << FullName() << ":" << endl
+ << *f;
+ }
+ }
+}
+
+void EventRouter::_OutputQueuing( )
+{
+ Flit *f;
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ f = _crossbar_pipe->Read( output );
+
+ if ( f ) {
+ _output_buffer[output].push( f );
+ }
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ c = _credit_pipe->Read( input );
+
+ if ( c ) {
+ _in_cred_buffer[input].push( c );
+ }
+ }
+}
+
+void EventRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_output_buffer[output].empty( ) ) {
+ Flit *f = _output_buffer[output].front( );
+ _output_buffer[output].pop( );
+ _output_channels[output]->Send( f );
+ }
+ }
+}
+
+void EventRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_in_cred_buffer[input].empty( ) ) {
+ Credit *c = _in_cred_buffer[input].front( );
+ _in_cred_buffer[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+void EventRouter::Display( ostream & os ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ _buf[input]->Display( os );
+ }
+}
+
+EventNextVCState::EventNextVCState( const Configuration& config,
+ Module *parent, const string& name ) :
+ Module( parent, name )
+{
+ _buf_size = config.GetInt( "vc_buf_size" );
+ _vcs = config.GetInt( "num_vcs" );
+
+ _credits.resize(_vcs, _buf_size);
+ _presence.resize(_vcs, 0);
+ _input.resize(_vcs);
+ _inputVC.resize(_vcs);
+ _waiting.resize(_vcs);
+ _state.resize(_vcs, idle);
+}
+
+EventNextVCState::eNextVCState EventNextVCState::GetState( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _state[vc];
+}
+
+int EventNextVCState::GetPresence( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _presence[vc];
+}
+
+int EventNextVCState::GetCredits( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _credits[vc];
+}
+
+int EventNextVCState::GetInput( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _input[vc];
+}
+
+int EventNextVCState::GetInputVC( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _inputVC[vc];
+}
+
+bool EventNextVCState::IsWaiting( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return !_waiting[vc].empty( );
+}
+
+void EventNextVCState::PushWaiting( int vc, tWaiting *w )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ if ( w->watch ) {
+ cout << FullName() << " pushing flit " << w->id
+ << " onto a waiting queue of length " << _waiting[vc].size( ) << endl;
+ }
+
+ _waiting[vc].push_back( w );
+}
+
+void EventNextVCState::IncrWaiting( int vc, int w_input, int w_vc )
+{
+ list<tWaiting *>::iterator match;
+
+ // search for match
+ for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) {
+ if ( ( (*match)->input == w_input ) &&
+ ( (*match)->vc == w_vc ) ) break;
+ }
+
+ if ( match != _waiting[vc].end( ) ) {
+ (*match)->pres++;
+ } else {
+ Error( "Did not find match in IncrWaiting" );
+ }
+}
+
+bool EventNextVCState::IsInputWaiting( int vc, int w_input, int w_vc ) const
+{
+ list<tWaiting *>::const_iterator match;
+ bool r;
+
+ // search for match
+ for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) {
+ if ( ( (*match)->input == w_input ) &&
+ ( (*match)->vc == w_vc ) ) break;
+ }
+
+ if ( match != _waiting[vc].end( ) ) {
+ r = true;
+ } else {
+ r = false;
+ }
+
+ return r;
+}
+
+EventNextVCState::tWaiting *EventNextVCState::PopWaiting( int vc )
+{
+ tWaiting *w;
+
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ w = _waiting[vc].front( );
+ _waiting[vc].pop_front( );
+
+ return w;
+}
+
+void EventNextVCState::SetState( int vc, eNextVCState state )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _state[vc] = state;
+}
+
+void EventNextVCState::SetCredits( int vc, int value )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _credits[vc] = value;
+}
+
+void EventNextVCState::SetPresence( int vc, int value )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _presence[vc] = value;
+}
+
+void EventNextVCState::SetInput( int vc, int input )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _input[vc] = input;
+}
+
+void EventNextVCState::SetInputVC( int vc, int in_vc )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _inputVC[vc] = in_vc;
+}
diff --git a/src/intersim2/routers/event_router.hpp b/src/intersim2/routers/event_router.hpp
new file mode 100644
index 0000000..2f2f170
--- /dev/null
+++ b/src/intersim2/routers/event_router.hpp
@@ -0,0 +1,187 @@
+// $Id: event_router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _EVENT_ROUTER_HPP_
+#define _EVENT_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "buffer.hpp"
+#include "vc.hpp"
+#include "prio_arb.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "pipefifo.hpp"
+
+class EventNextVCState : public Module {
+public:
+ enum eNextVCState { idle, busy, tail_pending };
+
+ struct tWaiting {
+ int input;
+ int vc;
+ int id;
+ int pres;
+ bool watch;
+ };
+
+private:
+ int _buf_size;
+ int _vcs;
+
+ vector<int> _credits;
+ vector<int> _presence;
+ vector<int> _input;
+ vector<int> _inputVC;
+
+ vector<list<tWaiting *> > _waiting;
+
+ vector<eNextVCState> _state;
+
+public:
+
+ EventNextVCState( const Configuration& config,
+ Module *parent, const string& name );
+
+ eNextVCState GetState( int vc ) const;
+ int GetPresence( int vc ) const;
+ int GetCredits( int vc ) const;
+ int GetInput( int vc ) const;
+ int GetInputVC( int vc ) const;
+
+ bool IsWaiting( int vc ) const;
+ bool IsInputWaiting( int vc, int w_input, int w_vc ) const;
+
+ void PushWaiting( int vc, tWaiting *w );
+ void IncrWaiting( int vc, int w_input, int w_vc );
+ tWaiting *PopWaiting( int vc );
+
+ void SetState( int vc, eNextVCState state );
+ void SetCredits( int vc, int value );
+ void SetPresence( int vc, int value );
+ void SetInput( int vc, int input );
+ void SetInputVC( int vc, int in_vc );
+};
+
+class EventRouter : public Router {
+ int _vcs;
+
+ int _vct;
+
+ vector<Buffer *> _buf;
+ vector<vector<bool> > _active;
+
+ tRoutingFunction _rf;
+
+ vector<EventNextVCState *> _output_state;
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+ PipelineFIFO<Credit> *_credit_pipe;
+
+ vector<queue<Flit *> > _input_buffer;
+ vector<queue<Flit *> > _output_buffer;
+
+ vector<queue<Credit *> > _in_cred_buffer;
+ vector<queue<Credit *> > _out_cred_buffer;
+
+ struct tArrivalEvent {
+ int input;
+ int output;
+ int src_vc;
+ int dst_vc;
+ bool head;
+ bool tail;
+
+ int id; // debug
+ bool watch; // debug
+ };
+
+ PipelineFIFO<tArrivalEvent> *_arrival_pipe;
+ vector<queue<tArrivalEvent *> > _arrival_queue;
+ vector<PriorityArbiter*> _arrival_arbiter;
+
+ struct tTransportEvent {
+ int input;
+ int src_vc;
+ int dst_vc;
+
+ int id; // debug
+ bool watch; // debug
+ };
+
+ vector<queue<tTransportEvent *> > _transport_queue;
+ vector<PriorityArbiter*> _transport_arbiter;
+
+ vector<bool> _transport_free;
+ vector<int> _transport_match;
+
+ void _ReceiveFlits( );
+ void _ReceiveCredits( );
+
+ void _IncomingFlits( );
+ void _ArrivalRequests( int input );
+ void _ArrivalArb( int output );
+ void _SendTransport( int input, int output, tArrivalEvent *aevt );
+ void _ProcessWaiting( int output, int out_vc );
+ void _TransportRequests( int output );
+ void _TransportArb( int input );
+ void _OutputQueuing( );
+
+ void _SendFlits( );
+ void _SendCredits( );
+
+ virtual void _InternalStep( );
+
+public:
+ EventRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+ virtual ~EventRouter( );
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ virtual int GetUsedCredit(int o) const {return 0;}
+ virtual int GetBufferOccupancy(int i) const {return 0;}
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const {return 0;}
+ virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;}
+#endif
+
+ virtual vector<int> UsedCredits() const { return vector<int>(); }
+ virtual vector<int> FreeCredits() const { return vector<int>(); }
+ virtual vector<int> MaxCredits() const { return vector<int>(); }
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/routers/iq_router.cpp b/src/intersim2/routers/iq_router.cpp
new file mode 100644
index 0000000..d97f485
--- /dev/null
+++ b/src/intersim2/routers/iq_router.cpp
@@ -0,0 +1,2385 @@
+// $Id: iq_router.cpp 5263 2012-09-20 23:40:33Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "iq_router.hpp"
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+#include <cassert>
+#include <limits>
+
+#include "globals.hpp"
+#include "random_utils.hpp"
+#include "vc.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "buffer.hpp"
+#include "buffer_state.hpp"
+#include "roundrobin_arb.hpp"
+#include "allocator.hpp"
+#include "switch_monitor.hpp"
+#include "buffer_monitor.hpp"
+
+IQRouter::IQRouter( Configuration const & config, Module *parent,
+ string const & name, int id, int inputs, int outputs )
+: Router( config, parent, name, id, inputs, outputs ), _active(false)
+{
+ _vcs = config.GetInt( "num_vcs" );
+
+ _vc_busy_when_full = (config.GetInt("vc_busy_when_full") > 0);
+ _vc_prioritize_empty = (config.GetInt("vc_prioritize_empty") > 0);
+ _vc_shuffle_requests = (config.GetInt("vc_shuffle_requests") > 0);
+
+ _speculative = (config.GetInt("speculative") > 0);
+ _spec_check_elig = (config.GetInt("spec_check_elig") > 0);
+ _spec_check_cred = (config.GetInt("spec_check_cred") > 0);
+ _spec_mask_by_reqs = (config.GetInt("spec_mask_by_reqs") > 0);
+
+ _routing_delay = config.GetInt( "routing_delay" );
+ _vc_alloc_delay = config.GetInt( "vc_alloc_delay" );
+ if(!_vc_alloc_delay) {
+ Error("VC allocator cannot have zero delay.");
+ }
+ _sw_alloc_delay = config.GetInt( "sw_alloc_delay" );
+ if(!_sw_alloc_delay) {
+ Error("Switch allocator cannot have zero delay.");
+ }
+
+ // Routing
+ string const rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::const_iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ // Alloc VC's
+ _buf.resize(_inputs);
+ for ( int i = 0; i < _inputs; ++i ) {
+ ostringstream module_name;
+ module_name << "buf_" << i;
+ _buf[i] = new Buffer(config, _outputs, this, module_name.str( ) );
+ module_name.str("");
+ }
+
+ // Alloc next VCs' buffer state
+ _next_buf.resize(_outputs);
+ for (int j = 0; j < _outputs; ++j) {
+ ostringstream module_name;
+ module_name << "next_vc_o" << j;
+ _next_buf[j] = new BufferState( config, this, module_name.str( ) );
+ module_name.str("");
+ }
+
+ // Alloc allocators
+ string vc_alloc_type = config.GetStr( "vc_allocator" );
+ if(vc_alloc_type == "piggyback") {
+ if(!_speculative) {
+ Error("Piggyback VC allocation requires speculative switch allocation to be enabled.");
+ }
+ _vc_allocator = NULL;
+ _vc_rr_offset.resize(_outputs*_classes, -1);
+ } else {
+ _vc_allocator = Allocator::NewAllocator( this, "vc_allocator",
+ vc_alloc_type,
+ _vcs*_inputs,
+ _vcs*_outputs );
+
+ if ( !_vc_allocator ) {
+ Error("Unknown vc_allocator type: " + vc_alloc_type);
+ }
+ }
+
+ string sw_alloc_type = config.GetStr( "sw_allocator" );
+ _sw_allocator = Allocator::NewAllocator( this, "sw_allocator",
+ sw_alloc_type,
+ _inputs*_input_speedup,
+ _outputs*_output_speedup );
+
+ if ( !_sw_allocator ) {
+ Error("Unknown sw_allocator type: " + sw_alloc_type);
+ }
+
+ string spec_sw_alloc_type = config.GetStr( "spec_sw_allocator" );
+ if ( _speculative && ( spec_sw_alloc_type != "prio" ) ) {
+ _spec_sw_allocator = Allocator::NewAllocator( this, "spec_sw_allocator",
+ spec_sw_alloc_type,
+ _inputs*_input_speedup,
+ _outputs*_output_speedup );
+ if ( !_spec_sw_allocator ) {
+ Error("Unknown spec_sw_allocator type: " + spec_sw_alloc_type);
+ }
+ } else {
+ _spec_sw_allocator = NULL;
+ }
+
+ _sw_rr_offset.resize(_inputs*_input_speedup);
+ for(int i = 0; i < _inputs*_input_speedup; ++i)
+ _sw_rr_offset[i] = i % _input_speedup;
+
+ _noq = config.GetInt("noq") > 0;
+ if(_noq) {
+ if(_routing_delay) {
+ Error("NOQ requires lookahead routing to be enabled.");
+ }
+ if(_vcs < _outputs) {
+ Error("NOQ requires at least as many VCs as router outputs.");
+ }
+ }
+ _noq_next_output_port.resize(_inputs, vector<int>(_vcs, -1));
+ _noq_next_vc_start.resize(_inputs, vector<int>(_vcs, -1));
+ _noq_next_vc_end.resize(_inputs, vector<int>(_vcs, -1));
+
+ // Output queues
+ _output_buffer_size = config.GetInt("output_buffer_size");
+ _output_buffer.resize(_outputs);
+ _credit_buffer.resize(_inputs);
+
+ // Switch configuration (when held for multiple cycles)
+ _hold_switch_for_packet = (config.GetInt("hold_switch_for_packet") > 0);
+ _switch_hold_in.resize(_inputs*_input_speedup, -1);
+ _switch_hold_out.resize(_outputs*_output_speedup, -1);
+ _switch_hold_vc.resize(_inputs*_input_speedup, -1);
+
+ _bufferMonitor = new BufferMonitor(inputs, _classes);
+ _switchMonitor = new SwitchMonitor(inputs, outputs, _classes);
+
+#ifdef TRACK_FLOWS
+ for(int c = 0; c < _classes; ++c) {
+ _stored_flits[c].resize(_inputs, 0);
+ _active_packets[c].resize(_inputs, 0);
+ }
+ _outstanding_classes.resize(_outputs, vector<queue<int> >(_vcs));
+#endif
+}
+
+IQRouter::~IQRouter( )
+{
+
+ if(gPrintActivity) {
+ cout << Name() << ".bufferMonitor:" << endl ;
+ cout << *_bufferMonitor << endl ;
+
+ cout << Name() << ".switchMonitor:" << endl ;
+ cout << "Inputs=" << _inputs ;
+ cout << "Outputs=" << _outputs ;
+ cout << *_switchMonitor << endl ;
+ }
+
+ for(int i = 0; i < _inputs; ++i)
+ delete _buf[i];
+
+ for(int j = 0; j < _outputs; ++j)
+ delete _next_buf[j];
+
+ delete _vc_allocator;
+ delete _sw_allocator;
+ if(_spec_sw_allocator)
+ delete _spec_sw_allocator;
+
+ delete _bufferMonitor;
+ delete _switchMonitor;
+}
+
+void IQRouter::AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel)
+{
+ int alloc_delay = _speculative ? max(_vc_alloc_delay, _sw_alloc_delay) : (_vc_alloc_delay + _sw_alloc_delay);
+ int min_latency = 1 + _crossbar_delay + channel->GetLatency() + _routing_delay + alloc_delay + backchannel->GetLatency() + _credit_delay;
+ _next_buf[_output_channels.size()]->SetMinLatency(min_latency);
+ Router::AddOutputChannel(channel, backchannel);
+}
+
+void IQRouter::ReadInputs( )
+{
+ bool have_flits = _ReceiveFlits( );
+ bool have_credits = _ReceiveCredits( );
+ _active = _active || have_flits || have_credits;
+}
+
+void IQRouter::_InternalStep( )
+{
+ if(!_active) {
+ return;
+ }
+
+ _InputQueuing( );
+ bool activity = !_proc_credits.empty();
+
+ if(!_route_vcs.empty())
+ _RouteEvaluate( );
+ if(_vc_allocator) {
+ _vc_allocator->Clear();
+ if(!_vc_alloc_vcs.empty())
+ _VCAllocEvaluate( );
+ }
+ if(_hold_switch_for_packet) {
+ if(!_sw_hold_vcs.empty())
+ _SWHoldEvaluate( );
+ }
+ _sw_allocator->Clear();
+ if(_spec_sw_allocator)
+ _spec_sw_allocator->Clear();
+ if(!_sw_alloc_vcs.empty())
+ _SWAllocEvaluate( );
+ if(!_crossbar_flits.empty())
+ _SwitchEvaluate( );
+
+ if(!_route_vcs.empty()) {
+ _RouteUpdate( );
+ activity = activity || !_route_vcs.empty();
+ }
+ if(!_vc_alloc_vcs.empty()) {
+ _VCAllocUpdate( );
+ activity = activity || !_vc_alloc_vcs.empty();
+ }
+ if(_hold_switch_for_packet) {
+ if(!_sw_hold_vcs.empty()) {
+ _SWHoldUpdate( );
+ activity = activity || !_sw_hold_vcs.empty();
+ }
+ }
+ if(!_sw_alloc_vcs.empty()) {
+ _SWAllocUpdate( );
+ activity = activity || !_sw_alloc_vcs.empty();
+ }
+ if(!_crossbar_flits.empty()) {
+ _SwitchUpdate( );
+ activity = activity || !_crossbar_flits.empty();
+ }
+
+ _active = activity;
+
+ _OutputQueuing( );
+
+ _bufferMonitor->cycle( );
+ _switchMonitor->cycle( );
+}
+
+void IQRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+
+//------------------------------------------------------------------------------
+// read inputs
+//------------------------------------------------------------------------------
+
+bool IQRouter::_ReceiveFlits( )
+{
+ bool activity = false;
+ for(int input = 0; input < _inputs; ++input) {
+ Flit * const f = _input_channels[input]->Receive();
+ if(f) {
+
+#ifdef TRACK_FLOWS
+ ++_received_flits[f->cl][input];
+#endif
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Received flit " << f->id
+ << " from channel at input " << input
+ << "." << endl;
+ }
+ _in_queue_flits.insert(make_pair(input, f));
+ activity = true;
+ }
+ }
+ return activity;
+}
+
+bool IQRouter::_ReceiveCredits( )
+{
+ bool activity = false;
+ for(int output = 0; output < _outputs; ++output) {
+ Credit * const c = _output_credits[output]->Receive();
+ if(c) {
+ _proc_credits.push_back(make_pair(GetSimTime() + _credit_delay,
+ make_pair(c, output)));
+ activity = true;
+ }
+ }
+ return activity;
+}
+
+
+//------------------------------------------------------------------------------
+// input queuing
+//------------------------------------------------------------------------------
+
+void IQRouter::_InputQueuing( )
+{
+ for(map<int, Flit *>::const_iterator iter = _in_queue_flits.begin();
+ iter != _in_queue_flits.end();
+ ++iter) {
+
+ int const input = iter->first;
+ assert((input >= 0) && (input < _inputs));
+
+ Flit * const f = iter->second;
+ assert(f);
+
+ int const vc = f->vc;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Adding flit " << f->id
+ << " to VC " << vc
+ << " at input " << input
+ << " (state: " << VC::VCSTATE[cur_buf->GetState(vc)];
+ if(cur_buf->Empty(vc)) {
+ *gWatchOut << ", empty";
+ } else {
+ assert(cur_buf->FrontFlit(vc));
+ *gWatchOut << ", front: " << cur_buf->FrontFlit(vc)->id;
+ }
+ *gWatchOut << ")." << endl;
+ }
+ cur_buf->AddFlit(vc, f);
+
+#ifdef TRACK_FLOWS
+ ++_stored_flits[f->cl][input];
+ if(f->head) ++_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->write(input, f) ;
+
+ if(cur_buf->GetState(vc) == VC::idle) {
+ assert(cur_buf->FrontFlit(vc) == f);
+ assert(cur_buf->GetOccupancy(vc) == 1);
+ assert(f->head);
+ assert(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] != vc);
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, make_pair(input, vc)));
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &f->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, f);
+ }
+ }
+ } else if((cur_buf->GetState(vc) == VC::active) &&
+ (cur_buf->FrontFlit(vc) == f)) {
+ if(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] == vc) {
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ } else {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ }
+ }
+ _in_queue_flits.clear();
+
+ while(!_proc_credits.empty()) {
+
+ pair<int, pair<Credit *, int> > const & item = _proc_credits.front();
+
+ int const time = item.first;
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ Credit * const c = item.second.first;
+ assert(c);
+
+ int const output = item.second.second;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+#ifdef TRACK_FLOWS
+ for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) {
+ int const vc = *iter;
+ assert(!_outstanding_classes[output][vc].empty());
+ int cl = _outstanding_classes[output][vc].front();
+ _outstanding_classes[output][vc].pop();
+ assert(_outstanding_credits[cl][output] > 0);
+ --_outstanding_credits[cl][output];
+ }
+#endif
+
+ dest_buf->ProcessCredit(c);
+ c->Free();
+ _proc_credits.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// routing
+//------------------------------------------------------------------------------
+
+void IQRouter::_RouteEvaluate( )
+{
+ assert(_routing_delay);
+
+ for(deque<pair<int, pair<int, int> > >::iterator iter = _route_vcs.begin();
+ iter != _route_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _routing_delay - 1;
+
+ int const input = iter->second.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::routing);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning routing for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+ }
+}
+
+void IQRouter::_RouteUpdate( )
+{
+ assert(_routing_delay);
+
+ while(!_route_vcs.empty()) {
+
+ pair<int, pair<int, int> > const & item = _route_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::routing);
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed routing for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ cur_buf->Route(vc, _rf, this, f, input);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1)));
+ }
+ // NOTE: No need to handle NOQ here, as it requires lookahead routing!
+ _route_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// VC allocation
+//------------------------------------------------------------------------------
+
+void IQRouter::_VCAllocEvaluate( )
+{
+ assert(_vc_allocator);
+
+ bool watched = false;
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning VC allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ int const out_priority = cur_buf->GetPriority(vc);
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ bool elig = false;
+ bool cred = false;
+ bool reserved = false;
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+
+ int const out_port = iset->output_port;
+ assert((out_port >= 0) && (out_port < _outputs));
+
+ BufferState const * const dest_buf = _next_buf[out_port];
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+
+ int in_priority = iset->pri;
+ if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) {
+ assert(in_priority >= 0);
+ in_priority += numeric_limits<int>::min();
+ }
+
+ // On the input input side, a VC might request several output VCs.
+ // These VCs can be prioritized by the routing function, and this is
+ // reflected in "in_priority". On the output side, if multiple VCs are
+ // requesting the same output VC, the priority of VCs is based on the
+ // actual packet priorities, which is reflected in "out_priority".
+
+ if(!dest_buf->IsAvailableFor(out_vc)) {
+ if(f->watch) {
+ int const use_input_and_vc = dest_buf->UsedBy(out_vc);
+ int const use_input = use_input_and_vc / _vcs;
+ int const use_vc = use_input_and_vc % _vcs;
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << out_vc
+ << " at output " << out_port
+ << " is in use by VC " << use_vc
+ << " at input " << use_input;
+ Flit * cf = _buf[use_input]->FrontFlit(use_vc);
+ if(cf) {
+ *gWatchOut << " (front flit: " << cf->id << ")";
+ } else {
+ *gWatchOut << " (empty)";
+ }
+ *gWatchOut << "." << endl;
+ }
+ } else {
+ elig = true;
+ if(_vc_busy_when_full && dest_buf->IsFullFor(out_vc)) {
+ if(f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << out_vc
+ << " at output " << out_port
+ << " is full." << endl;
+ reserved |= !dest_buf->IsFull();
+ } else {
+ cred = true;
+ if(f->watch){
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Requesting VC " << out_vc
+ << " at output " << out_port
+ << " (in_pri: " << in_priority
+ << ", out_pri: " << out_priority
+ << ")." << endl;
+ watched = true;
+ }
+ int const input_and_vc
+ = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ _vc_allocator->AddRequest(input_and_vc, out_port*_vcs + out_vc,
+ 0, in_priority, out_priority);
+ }
+ }
+ }
+ }
+ if(!elig) {
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_vc_busy_when_full && !cred) {
+ iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL;
+ }
+ }
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | ";
+ _vc_allocator->PrintRequests( gWatchOut );
+ }
+
+ _vc_allocator->Allocate();
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | ";
+ _vc_allocator->PrintGrants( gWatchOut );
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _vc_alloc_delay - 1;
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ if(iter->second.second < -1) {
+ continue;
+ }
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ int const input_and_vc
+ = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc);
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning VC " << match_vc
+ << " at output " << match_output
+ << " to VC " << vc
+ << " at input " << input
+ << "." << endl;
+ }
+
+ iter->second.second = output_and_vc;
+
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "VC allocation failed for VC " << vc
+ << " at input " << input
+ << "." << endl;
+ }
+
+ iter->second.second = STALL_BUFFER_CONFLICT;
+
+ }
+ }
+
+ if(_vc_alloc_delay <= 1) {
+ return;
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ assert(time >= 0);
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ assert(iter->second.second != -1);
+
+ int const output_and_vc = iter->second.second;
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ BufferState const * const dest_buf = _next_buf[match_output];
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(!dest_buf->IsAvailableFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding previously generated grant for VC " << vc
+ << " at input " << input
+ << ": VC " << match_vc
+ << " at output " << match_output
+ << " is no longer available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_vc_busy_when_full && dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding previously generated grant for VC " << vc
+ << " at input " << input
+ << ": VC " << match_vc
+ << " at output " << match_output
+ << " has become full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+ }
+ }
+}
+
+void IQRouter::_VCAllocUpdate( )
+{
+ assert(_vc_allocator);
+
+ while(!_vc_alloc_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _vc_alloc_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(item.second.second != -1);
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed VC allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const output_and_vc = item.second.second;
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Acquiring assigned VC " << match_vc
+ << " at output " << match_output
+ << "." << endl;
+ }
+
+ BufferState * const dest_buf = _next_buf[match_output];
+ assert(dest_buf->IsAvailableFor(match_vc));
+
+ dest_buf->TakeBuffer(match_vc, input*_vcs + vc);
+
+ cur_buf->SetOutput(vc, match_output, match_vc);
+ cur_buf->SetState(vc, VC::active);
+ if(!_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " No output VC allocated." << endl;
+ }
+
+#ifdef TRACK_STALLS
+ assert((output_and_vc == STALL_BUFFER_BUSY) ||
+ (output_and_vc == STALL_BUFFER_CONFLICT));
+ if(output_and_vc == STALL_BUFFER_BUSY) {
+ ++_buffer_busy_stalls[f->cl];
+ } else if(output_and_vc == STALL_BUFFER_CONFLICT) {
+ ++_buffer_conflict_stalls[f->cl];
+ }
+#endif
+
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ _vc_alloc_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch holding
+//------------------------------------------------------------------------------
+
+void IQRouter::_SWHoldEvaluate( )
+{
+ assert(_hold_switch_for_packet);
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_hold_vcs.begin();
+ iter != _sw_hold_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime();
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::active);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning held switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] == vc);
+
+ int const match_port = cur_buf->GetOutputPort(vc);
+ assert((match_port >= 0) && (match_port < _outputs));
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ int const expanded_output = match_port*_output_speedup + input%_output_speedup;
+ assert(_switch_hold_in[expanded_input] == expanded_output);
+
+ BufferState const * const dest_buf = _next_buf[match_port];
+
+ if(dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Unable to reuse held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << match_port
+ << "." << (expanded_output % _output_speedup)
+ << ": No credit available." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Reusing held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << match_port
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ iter->second.second = expanded_output;
+ }
+ }
+}
+
+void IQRouter::_SWHoldUpdate( )
+{
+ assert(_hold_switch_for_packet);
+
+ while(!_sw_hold_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _sw_hold_vcs.front();
+
+ int const time = item.first;
+ if(time < 0) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(item.second.second != -1);
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::active);
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed held switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] == vc);
+
+ int const expanded_output = item.second.second;
+
+ if(expanded_output >= 0 && ( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size))) {
+
+ assert(_switch_hold_in[expanded_input] == expanded_output);
+ assert(_switch_hold_out[expanded_output] == expanded_input);
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Scheduling switch connection from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+
+ cur_buf->RemoveFlit(vc);
+
+#ifdef TRACK_FLOWS
+ --_stored_flits[f->cl][input];
+ if(f->tail) --_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->read(input, f) ;
+
+ f->hops++;
+ f->vc = match_vc;
+
+ if(!_routing_delay && f->head) {
+ const FlitChannel * channel = _output_channels[output];
+ const Router * router = channel->GetSink();
+ if(router) {
+ if(_noq) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ int next_output_port = _noq_next_output_port[input][vc];
+ assert(next_output_port >= 0);
+ _noq_next_output_port[input][vc] = -1;
+ int next_vc_start = _noq_next_vc_start[input][vc];
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ _noq_next_vc_start[input][vc] = -1;
+ int next_vc_end = _noq_next_vc_end[input][vc];
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ _noq_next_vc_end[input][vc] = -1;
+ f->la_route_set.Clear();
+ f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end);
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << "." << endl;
+ }
+ int in_channel = channel->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[f->cl][output];
+ _outstanding_classes[output][f->vc].push(f->cl);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output))));
+
+ if(_out_queue_credits.count(input) == 0) {
+ _out_queue_credits.insert(make_pair(input, Credit::New()));
+ }
+ _out_queue_credits.find(input)->second->vc.insert(vc);
+
+ if(cur_buf->Empty(vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << output
+ << "." << (expanded_output % _output_speedup)
+ << ": No more flits." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[expanded_output] = -1;
+ if(f->tail) {
+ cur_buf->SetState(vc, VC::idle);
+ }
+ } else {
+ Flit * const nf = cur_buf->FrontFlit(vc);
+ assert(nf);
+ assert(nf->vc == vc);
+ if(f->tail) {
+ assert(nf->head);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << output
+ << "." << (expanded_output % _output_speedup)
+ << ": End of packet." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[expanded_output] = -1;
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, item.second.first));
+ } else {
+ if(nf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << nf->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &nf->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, nf);
+ }
+ }
+ } else {
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ }
+ } else {
+ //when internal speedup >1.0, the buffer stall stats may not be accruate
+ assert((expanded_output == STALL_BUFFER_FULL) ||
+ (expanded_output == STALL_BUFFER_RESERVED) || !( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size)));
+
+ int const held_expanded_output = _switch_hold_in[expanded_input];
+ assert(held_expanded_output >= 0);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << (held_expanded_output / _output_speedup)
+ << "." << (held_expanded_output % _output_speedup)
+ << ": Flit not sent." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[held_expanded_output] = -1;
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ _sw_hold_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch allocation
+//------------------------------------------------------------------------------
+
+bool IQRouter::_SWAllocAddReq(int input, int vc, int output)
+{
+ assert(input >= 0 && input < _inputs);
+ assert(vc >= 0 && vc < _vcs);
+ assert(output >= 0 && output < _outputs);
+
+ // When input_speedup > 1, the virtual channel buffers are interleaved to
+ // create multiple input ports to the switch. Similarily, the output ports
+ // are interleaved based on their originating input when output_speedup > 1.
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ int const expanded_output = output * _output_speedup + input % _output_speedup;
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if((_switch_hold_in[expanded_input] < 0) &&
+ (_switch_hold_out[expanded_output] < 0)) {
+
+ Allocator * allocator = _sw_allocator;
+ int prio = cur_buf->GetPriority(vc);
+
+ if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+ if(_spec_sw_allocator) {
+ allocator = _spec_sw_allocator;
+ } else {
+ assert(prio >= 0);
+ prio += numeric_limits<int>::min();
+ }
+ }
+
+ Allocator::sRequest req;
+
+ if(allocator->ReadRequest(req, expanded_input, expanded_output)) {
+ if(RoundRobinArbiter::Supersedes(vc, prio, req.label, req.in_pri,
+ _sw_rr_offset[expanded_input], _vcs)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Replacing earlier request from VC " << req.label
+ << " for output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " with priority " << req.in_pri
+ << " (" << ((cur_buf->GetState(vc) == VC::active) ?
+ "non-spec" :
+ "spec")
+ << ", pri: " << prio
+ << ")." << endl;
+ }
+ allocator->RemoveRequest(expanded_input, expanded_output, req.label);
+ allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio);
+ return true;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " was already requested by VC " << req.label
+ << " with priority " << req.in_pri
+ << " (pri: " << prio
+ << ")." << endl;
+ }
+ return false;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Requesting output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " (" << ((cur_buf->GetState(vc) == VC::active) ?
+ "non-spec" :
+ "spec")
+ << ", pri: " << prio
+ << ")." << endl;
+ }
+ allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio);
+ return true;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Ignoring output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to switch hold (";
+ if(_switch_hold_in[expanded_input] >= 0) {
+ *gWatchOut << "input: " << input
+ << "." << (expanded_input % _input_speedup);
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << ", ";
+ }
+ }
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << "output: " << output
+ << "." << (expanded_output % _output_speedup);
+ }
+ *gWatchOut << ")." << endl;
+ }
+ return false;
+}
+
+void IQRouter::_SWAllocEvaluate( )
+{
+ bool watched = false;
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ assert(_switch_hold_vc[input * _input_speedup + vc % _input_speedup] != vc);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ if(cur_buf->GetState(vc) == VC::active) {
+
+ int const dest_output = cur_buf->GetOutputPort(vc);
+ assert((dest_output >= 0) && (dest_output < _outputs));
+ int const dest_vc = cur_buf->GetOutputVC(vc);
+ assert((dest_vc >= 0) && (dest_vc < _vcs));
+
+ BufferState const * const dest_buf = _next_buf[dest_output];
+
+ if(dest_buf->IsFullFor(dest_vc) || ( _output_buffer_size!=-1 && _output_buffer[dest_output].size()>=(size_t)(_output_buffer_size))) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << dest_vc
+ << " at output " << dest_output
+ << " is full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ continue;
+ }
+ bool const requested = _SWAllocAddReq(input, vc, dest_output);
+ watched |= requested && f->watch;
+ continue;
+ }
+ assert(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc));
+ assert(f->head);
+
+ // The following models the speculative VC allocation aspects of the
+ // pipeline. An input VC with a request in for an egress virtual channel
+ // will also speculatively bid for the switch regardless of whether the VC
+ // allocation succeeds.
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+
+ int const dest_output = iset->output_port;
+ assert((dest_output >= 0) && (dest_output < _outputs));
+
+ // for lower levels of speculation, ignore credit availability and always
+ // issue requests for all output ports in route set
+
+ BufferState const * const dest_buf = _next_buf[dest_output];
+
+ bool elig = false;
+ bool cred = false;
+
+ if(_spec_check_elig) {
+
+ // for higher levels of speculation, check if at least one suitable VC
+ // is available at the current output
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int dest_vc = vc_start; dest_vc <= vc_end; ++dest_vc) {
+ assert((dest_vc >= 0) && (dest_vc < _vcs));
+
+ if(dest_buf->IsAvailableFor(dest_vc) && ( _output_buffer_size==-1 || _output_buffer[dest_output].size()<(size_t)(_output_buffer_size))) {
+ elig = true;
+ if(!_spec_check_cred || !dest_buf->IsFullFor(dest_vc)) {
+ cred = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(_spec_check_elig && !elig) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output " << dest_output
+ << " has no suitable VCs available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_spec_check_cred && !cred) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " All suitable VCs at output " << dest_output
+ << " are full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ } else {
+ bool const requested = _SWAllocAddReq(input, vc, dest_output);
+ watched |= requested && f->watch;
+ }
+ }
+ }
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | ";
+ _sw_allocator->PrintRequests(gWatchOut);
+ if(_spec_sw_allocator) {
+ *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | ";
+ _spec_sw_allocator->PrintRequests(gWatchOut);
+ }
+ }
+
+ _sw_allocator->Allocate();
+ if(_spec_sw_allocator)
+ _spec_sw_allocator->Allocate();
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | ";
+ _sw_allocator->PrintGrants(gWatchOut);
+ if(_spec_sw_allocator) {
+ *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | ";
+ _spec_sw_allocator->PrintGrants(gWatchOut);
+ }
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _sw_alloc_delay - 1;
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ if(iter->second.second < -1) {
+ continue;
+ }
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+
+ int expanded_output = _sw_allocator->OutputAssigned(expanded_input);
+
+ if(expanded_output >= 0) {
+ assert((expanded_output % _output_speedup) == (input % _output_speedup));
+ int const granted_vc = _sw_allocator->ReadRequest(expanded_input, expanded_output);
+ if(granted_vc == vc) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " to VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << "." << endl;
+ }
+ _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs;
+ iter->second.second = expanded_output;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": Granted to VC " << granted_vc << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ }
+ } else if(_spec_sw_allocator) {
+ expanded_output = _spec_sw_allocator->OutputAssigned(expanded_input);
+ if(expanded_output >= 0) {
+ assert((expanded_output % _output_speedup) == (input % _output_speedup));
+ if(_spec_mask_by_reqs &&
+ _sw_allocator->OutputHasRequests(expanded_output)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding speculative grant for VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << " because output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " has non-speculative requests." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else if(!_spec_mask_by_reqs &&
+ (_sw_allocator->InputAssigned(expanded_output) >= 0)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding speculative grant for VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << " because output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " has a non-speculative grant." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else {
+ int const granted_vc = _spec_sw_allocator->ReadRequest(expanded_input,
+ expanded_output);
+ if(granted_vc == vc) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " to VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << "." << endl;
+ }
+ _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs;
+ iter->second.second = expanded_output;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": Granted to VC " << granted_vc << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ }
+ }
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": No output granted." << endl;
+ }
+
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+
+ }
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": No output granted." << endl;
+ }
+
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+
+ }
+ }
+
+ if(!_speculative && (_sw_alloc_delay <= 1)) {
+ return;
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ assert(time >= 0);
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ assert(iter->second.second != -1);
+
+ int const expanded_output = iter->second.second;
+
+ if(expanded_output >= 0) {
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState const * const dest_buf = _next_buf[output];
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ assert((input % _output_speedup) == (expanded_output % _output_speedup));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] != vc);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if((_switch_hold_in[expanded_input] >= 0) ||
+ (_switch_hold_out[expanded_output] >= 0)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to conflict with held connection at ";
+ if(_switch_hold_in[expanded_input] >= 0) {
+ *gWatchOut << "input";
+ }
+ if((_switch_hold_in[expanded_input] >= 0) &&
+ (_switch_hold_out[expanded_output] >= 0)) {
+ *gWatchOut << " and ";
+ }
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << "output";
+ }
+ *gWatchOut << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+
+ assert(f->head);
+
+ if(_vc_allocator) { // separate VC and switch allocators
+
+ int const input_and_vc =
+ _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc);
+
+ if(output_and_vc < 0) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to misspeculation." << endl;
+ }
+ iter->second.second = -1; // stall is counted in VC allocation path!
+ } else if((output_and_vc / _vcs) != output) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to port mismatch between VC and switch allocator." << endl;
+ }
+ iter->second.second = STALL_BUFFER_CONFLICT; // count this case as if we had failed allocation
+ } else if(dest_buf->IsFullFor((output_and_vc % _vcs))) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to lack of credit." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+
+ } else { // VC allocation is piggybacked onto switch allocation
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ bool busy = true;
+ bool full = true;
+ bool reserved = false;
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+ if(iset->output_port == output) {
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+ if(dest_buf->IsAvailableFor(out_vc)) {
+ busy = false;
+ if(!dest_buf->IsFullFor(out_vc)) {
+ full = false;
+ break;
+ } else if(!dest_buf->IsFull()) {
+ reserved = true;
+ }
+ }
+ }
+ if(!full) {
+ break;
+ }
+ }
+ }
+
+ if(busy) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " because no suitable output VC for piggyback allocation is available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(full) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " because all suitable output VCs for piggyback allocation are full." << endl;
+ }
+ iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL;
+ }
+
+ }
+
+ } else {
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to lack of credit." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+ }
+ }
+ }
+}
+
+void IQRouter::_SWAllocUpdate( )
+{
+ while(!_sw_alloc_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _sw_alloc_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_output = item.second.second;
+
+ if(expanded_output >= 0) {
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] < 0);
+ assert(_switch_hold_in[expanded_input] < 0);
+ assert(_switch_hold_out[expanded_output] < 0);
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+ int match_vc;
+
+ if(!_vc_allocator && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+
+ assert(f->head);
+
+ int const cl = f->cl;
+ assert((cl >= 0) && (cl < _classes));
+
+ int const vc_offset = _vc_rr_offset[output*_classes+cl];
+
+ match_vc = -1;
+ int match_prio = numeric_limits<int>::min();
+
+ const OutputSet * route_set = cur_buf->GetRouteSet(vc);
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+ if(iset->output_port == output) {
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+
+ int vc_prio = iset->pri;
+ if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) {
+ assert(vc_prio >= 0);
+ vc_prio += numeric_limits<int>::min();
+ }
+
+ // FIXME: This check should probably be performed in Evaluate(),
+ // not Update(), as the latter can cause the outcome to depend on
+ // the order of evaluation!
+ if(dest_buf->IsAvailableFor(out_vc) &&
+ !dest_buf->IsFullFor(out_vc) &&
+ ((match_vc < 0) ||
+ RoundRobinArbiter::Supersedes(out_vc, vc_prio,
+ match_vc, match_prio,
+ vc_offset, _vcs))) {
+ match_vc = out_vc;
+ match_prio = vc_prio;
+ }
+ }
+ }
+ }
+ assert(match_vc >= 0);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Allocating VC " << match_vc
+ << " at output " << output
+ << " via piggyback VC allocation." << endl;
+ }
+
+ cur_buf->SetState(vc, VC::active);
+ cur_buf->SetOutput(vc, output, match_vc);
+ dest_buf->TakeBuffer(match_vc, input*_vcs + vc);
+
+ _vc_rr_offset[output*_classes+cl] = (match_vc + 1) % _vcs;
+
+ } else {
+
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ match_vc = cur_buf->GetOutputVC(vc);
+
+ }
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Scheduling switch connection from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+
+ cur_buf->RemoveFlit(vc);
+
+#ifdef TRACK_FLOWS
+ --_stored_flits[f->cl][input];
+ if(f->tail) --_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->read(input, f) ;
+
+ f->hops++;
+ f->vc = match_vc;
+
+ if(!_routing_delay && f->head) {
+ const FlitChannel * channel = _output_channels[output];
+ const Router * router = channel->GetSink();
+ if(router) {
+ if(_noq) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ int next_output_port = _noq_next_output_port[input][vc];
+ assert(next_output_port >= 0);
+ _noq_next_output_port[input][vc] = -1;
+ int next_vc_start = _noq_next_vc_start[input][vc];
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ _noq_next_vc_start[input][vc] = -1;
+ int next_vc_end = _noq_next_vc_end[input][vc];
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ _noq_next_vc_end[input][vc] = -1;
+ f->la_route_set.Clear();
+ f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end);
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << "." << endl;
+ }
+ int in_channel = channel->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[f->cl][output];
+ _outstanding_classes[output][f->vc].push(f->cl);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output))));
+
+ if(_out_queue_credits.count(input) == 0) {
+ _out_queue_credits.insert(make_pair(input, Credit::New()));
+ }
+ _out_queue_credits.find(input)->second->vc.insert(vc);
+
+ if(cur_buf->Empty(vc)) {
+ if(f->tail) {
+ cur_buf->SetState(vc, VC::idle);
+ }
+ } else {
+ Flit * const nf = cur_buf->FrontFlit(vc);
+ assert(nf);
+ assert(nf->vc == vc);
+ if(f->tail) {
+ assert(nf->head);
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, item.second.first));
+ } else {
+ if(nf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << nf->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &nf->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, nf);
+ }
+ }
+ } else {
+ if(_hold_switch_for_packet) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Setting up switch hold for VC " << vc
+ << " at input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ _switch_hold_vc[expanded_input] = vc;
+ _switch_hold_in[expanded_input] = expanded_output;
+ _switch_hold_out[expanded_output] = expanded_input;
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ } else {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ }
+ }
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " No output port allocated." << endl;
+ }
+
+#ifdef TRACK_STALLS
+ assert((expanded_output == -1) || // for stalls that are accounted for in VC allocation path
+ (expanded_output == STALL_BUFFER_BUSY) ||
+ (expanded_output == STALL_BUFFER_CONFLICT) ||
+ (expanded_output == STALL_BUFFER_FULL) ||
+ (expanded_output == STALL_BUFFER_RESERVED) ||
+ (expanded_output == STALL_CROSSBAR_CONFLICT));
+ if(expanded_output == STALL_BUFFER_BUSY) {
+ ++_buffer_busy_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_CONFLICT) {
+ ++_buffer_conflict_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_FULL) {
+ ++_buffer_full_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_RESERVED) {
+ ++_buffer_reserved_stalls[f->cl];
+ } else if(expanded_output == STALL_CROSSBAR_CONFLICT) {
+ ++_crossbar_conflict_stalls[f->cl];
+ }
+#endif
+
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ _sw_alloc_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch traversal
+//------------------------------------------------------------------------------
+
+void IQRouter::_SwitchEvaluate( )
+{
+ for(deque<pair<int, pair<Flit *, pair<int, int> > > >::iterator iter = _crossbar_flits.begin();
+ iter != _crossbar_flits.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _crossbar_delay - 1;
+
+ Flit const * const f = iter->second.first;
+ assert(f);
+
+ int const expanded_input = iter->second.second.first;
+ int const expanded_output = iter->second.second.second;
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning crossbar traversal for flit " << f->id
+ << " from input " << (expanded_input / _input_speedup)
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ }
+}
+
+void IQRouter::_SwitchUpdate( )
+{
+ while(!_crossbar_flits.empty()) {
+
+ pair<int, pair<Flit *, pair<int, int> > > const & item = _crossbar_flits.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ Flit * const f = item.second.first;
+ assert(f);
+
+ int const expanded_input = item.second.second.first;
+ int const input = expanded_input / _input_speedup;
+ assert((input >= 0) && (input < _inputs));
+ int const expanded_output = item.second.second.second;
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed crossbar traversal for flit " << f->id
+ << " from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ _switchMonitor->traversal(input, output, f) ;
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Buffering flit " << f->id
+ << " at output " << output
+ << "." << endl;
+ }
+ _output_buffer[output].push(f);
+ //the output buffer size isn't precise due to flits in flight
+ //but there is a maximum bound based on output speed up and ST traversal
+ assert(_output_buffer[output].size()<=(size_t)_output_buffer_size+ _crossbar_delay* _output_speedup+( _output_speedup-1) ||_output_buffer_size==-1);
+ _crossbar_flits.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// output queuing
+//------------------------------------------------------------------------------
+
+void IQRouter::_OutputQueuing( )
+{
+ for(map<int, Credit *>::const_iterator iter = _out_queue_credits.begin();
+ iter != _out_queue_credits.end();
+ ++iter) {
+
+ int const input = iter->first;
+ assert((input >= 0) && (input < _inputs));
+
+ Credit * const c = iter->second;
+ assert(c);
+ assert(!c->vc.empty());
+
+ _credit_buffer[input].push(c);
+ }
+ _out_queue_credits.clear();
+}
+
+//------------------------------------------------------------------------------
+// write outputs
+//------------------------------------------------------------------------------
+
+void IQRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_output_buffer[output].empty( ) ) {
+ Flit * const f = _output_buffer[output].front( );
+ assert(f);
+ _output_buffer[output].pop( );
+
+#ifdef TRACK_FLOWS
+ ++_sent_flits[f->cl][output];
+#endif
+
+ if(f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Sending flit " << f->id
+ << " to channel at output " << output
+ << "." << endl;
+ if(gTrace) {
+ cout << "Outport " << output << endl << "Stop Mark" << endl;
+ }
+ _output_channels[output]->Send( f );
+ }
+ }
+}
+
+void IQRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_credit_buffer[input].empty( ) ) {
+ Credit * const c = _credit_buffer[input].front( );
+ assert(c);
+ _credit_buffer[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// misc.
+//------------------------------------------------------------------------------
+
+void IQRouter::Display( ostream & os ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ _buf[input]->Display( os );
+ }
+}
+
+int IQRouter::GetUsedCredit(int o) const
+{
+ assert((o >= 0) && (o < _outputs));
+ BufferState const * const dest_buf = _next_buf[o];
+ return dest_buf->Occupancy();
+}
+
+int IQRouter::GetBufferOccupancy(int i) const {
+ assert(i >= 0 && i < _inputs);
+ return _buf[i]->GetOccupancy();
+}
+
+#ifdef TRACK_BUFFERS
+int IQRouter::GetUsedCreditForClass(int output, int cl) const
+{
+ assert((output >= 0) && (output < _outputs));
+ BufferState const * const dest_buf = _next_buf[output];
+ return dest_buf->OccupancyForClass(cl);
+}
+
+int IQRouter::GetBufferOccupancyForClass(int input, int cl) const
+{
+ assert((input >= 0) && (input < _inputs));
+ return _buf[input]->GetOccupancyForClass(cl);
+}
+#endif
+
+vector<int> IQRouter::UsedCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->OccupancyFor(v);
+ }
+ }
+ return result;
+}
+
+vector<int> IQRouter::FreeCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->AvailableFor(v);
+ }
+ }
+ return result;
+}
+
+vector<int> IQRouter::MaxCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->LimitFor(v);
+ }
+ }
+ return result;
+}
+
+void IQRouter::_UpdateNOQ(int input, int vc, Flit const * f) {
+ assert(!_routing_delay);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+ set<OutputSet::sSetElement> sl = f->la_route_set.GetSet();
+ assert(sl.size() == 1);
+ int out_port = sl.begin()->output_port;
+ const FlitChannel * channel = _output_channels[out_port];
+ const Router * router = channel->GetSink();
+ if(router) {
+ int in_channel = channel->GetSinkPort();
+ OutputSet nos;
+ _rf(router, f, in_channel, &nos, false);
+ sl = nos.GetSet();
+ assert(sl.size() == 1);
+ OutputSet::sSetElement const & se = *sl.begin();
+ int next_output_port = se.output_port;
+ assert(next_output_port >= 0);
+ assert(_noq_next_output_port[input][vc] < 0);
+ _noq_next_output_port[input][vc] = next_output_port;
+ int next_vc_count = (se.vc_end - se.vc_start + 1) / router->NumOutputs();
+ int next_vc_start = se.vc_start + next_output_port * next_vc_count;
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ assert(_noq_next_vc_start[input][vc] < 0);
+ _noq_next_vc_start[input][vc] = next_vc_start;
+ int next_vc_end = se.vc_start + (next_output_port + 1) * next_vc_count - 1;
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ assert(_noq_next_vc_end[input][vc] < 0);
+ _noq_next_vc_end[input][vc] = next_vc_end;
+ assert(next_vc_start <= next_vc_end);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Computing lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ }
+}
diff --git a/src/intersim2/routers/iq_router.hpp b/src/intersim2/routers/iq_router.hpp
new file mode 100644
index 0000000..b64502d
--- /dev/null
+++ b/src/intersim2/routers/iq_router.hpp
@@ -0,0 +1,183 @@
+// $Id: iq_router.hpp 5263 2012-09-20 23:40:33Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _IQ_ROUTER_HPP_
+#define _IQ_ROUTER_HPP_
+
+#include <string>
+#include <deque>
+#include <queue>
+#include <set>
+#include <map>
+
+#include "router.hpp"
+#include "routefunc.hpp"
+
+using namespace std;
+
+class VC;
+class Flit;
+class Credit;
+class Buffer;
+class BufferState;
+class Allocator;
+class SwitchMonitor;
+class BufferMonitor;
+
+class IQRouter : public Router {
+
+ int _vcs;
+
+ bool _vc_busy_when_full;
+ bool _vc_prioritize_empty;
+ bool _vc_shuffle_requests;
+
+ bool _speculative;
+ bool _spec_check_elig;
+ bool _spec_check_cred;
+ bool _spec_mask_by_reqs;
+
+ bool _active;
+
+ int _routing_delay;
+ int _vc_alloc_delay;
+ int _sw_alloc_delay;
+
+ map<int, Flit *> _in_queue_flits;
+
+ deque<pair<int, pair<Credit *, int> > > _proc_credits;
+
+ deque<pair<int, pair<int, int> > > _route_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _vc_alloc_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _sw_hold_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _sw_alloc_vcs;
+
+ deque<pair<int, pair<Flit *, pair<int, int> > > > _crossbar_flits;
+
+ map<int, Credit *> _out_queue_credits;
+
+ vector<Buffer *> _buf;
+ vector<BufferState *> _next_buf;
+
+ Allocator *_vc_allocator;
+ Allocator *_sw_allocator;
+ Allocator *_spec_sw_allocator;
+
+ vector<int> _vc_rr_offset;
+ vector<int> _sw_rr_offset;
+
+ tRoutingFunction _rf;
+
+ int _output_buffer_size;
+ vector<queue<Flit *> > _output_buffer;
+
+ vector<queue<Credit *> > _credit_buffer;
+
+ bool _hold_switch_for_packet;
+ vector<int> _switch_hold_in;
+ vector<int> _switch_hold_out;
+ vector<int> _switch_hold_vc;
+
+ bool _noq;
+ vector<vector<int> > _noq_next_output_port;
+ vector<vector<int> > _noq_next_vc_start;
+ vector<vector<int> > _noq_next_vc_end;
+
+#ifdef TRACK_FLOWS
+ vector<vector<queue<int> > > _outstanding_classes;
+#endif
+
+ bool _ReceiveFlits( );
+ bool _ReceiveCredits( );
+
+ virtual void _InternalStep( );
+
+ bool _SWAllocAddReq(int input, int vc, int output);
+
+ void _InputQueuing( );
+
+ void _RouteEvaluate( );
+ void _VCAllocEvaluate( );
+ void _SWHoldEvaluate( );
+ void _SWAllocEvaluate( );
+ void _SwitchEvaluate( );
+
+ void _RouteUpdate( );
+ void _VCAllocUpdate( );
+ void _SWHoldUpdate( );
+ void _SWAllocUpdate( );
+ void _SwitchUpdate( );
+
+ void _OutputQueuing( );
+
+ void _SendFlits( );
+ void _SendCredits( );
+
+ void _UpdateNOQ(int input, int vc, Flit const * f);
+
+ // ----------------------------------------
+ //
+ // Router Power Modellingyes
+ //
+ // ----------------------------------------
+
+ SwitchMonitor * _switchMonitor ;
+ BufferMonitor * _bufferMonitor ;
+
+public:
+
+ IQRouter( Configuration const & config,
+ Module *parent, string const & name, int id,
+ int inputs, int outputs );
+
+ virtual ~IQRouter( );
+
+ virtual void AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel);
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ void Display( ostream & os = cout ) const;
+
+ virtual int GetUsedCredit(int o) const;
+ virtual int GetBufferOccupancy(int i) const;
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const;
+ virtual int GetBufferOccupancyForClass(int input, int cl) const;
+#endif
+
+ virtual vector<int> UsedCredits() const;
+ virtual vector<int> FreeCredits() const;
+ virtual vector<int> MaxCredits() const;
+
+ SwitchMonitor const * const GetSwitchMonitor() const {return _switchMonitor;}
+ BufferMonitor const * const GetBufferMonitor() const {return _bufferMonitor;}
+
+};
+
+#endif
diff --git a/src/intersim2/routers/router.cpp b/src/intersim2/routers/router.cpp
new file mode 100644
index 0000000..cb6f078
--- /dev/null
+++ b/src/intersim2/routers/router.cpp
@@ -0,0 +1,155 @@
+// $Id: router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*router.cpp
+ *
+ *The base class of either iq router or event router
+ *contains a list of channels and other router configuration variables
+ *
+ *The older version of the simulator uses an array of flits and credit to
+ *simulate the channels. Newer version ueses flitchannel and credit channel
+ *which can better model channel delay
+ *
+ *The older version of the simulator also uses vc_router and chaos router
+ *which are replaced by iq rotuer and event router in the present form
+ */
+
+#include "booksim.hpp"
+#include <iostream>
+#include <cassert>
+#include "router.hpp"
+
+//////////////////Sub router types//////////////////////
+#include "iq_router.hpp"
+#include "event_router.hpp"
+#include "chaos_router.hpp"
+///////////////////////////////////////////////////////
+
+int const Router::STALL_BUFFER_BUSY = -2;
+int const Router::STALL_BUFFER_CONFLICT = -3;
+int const Router::STALL_BUFFER_FULL = -4;
+int const Router::STALL_BUFFER_RESERVED = -5;
+int const Router::STALL_CROSSBAR_CONFLICT = -6;
+
+Router::Router( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs ) :
+TimedModule( parent, name ), _id( id ), _inputs( inputs ), _outputs( outputs ),
+ _partial_internal_cycles(0.0)
+{
+ _crossbar_delay = ( config.GetInt( "st_prepare_delay" ) +
+ config.GetInt( "st_final_delay" ) );
+ _credit_delay = config.GetInt( "credit_delay" );
+ _input_speedup = config.GetInt( "input_speedup" );
+ _output_speedup = config.GetInt( "output_speedup" );
+ _internal_speedup = config.GetFloat( "internal_speedup" );
+ _classes = config.GetInt( "classes" );
+
+#ifdef TRACK_FLOWS
+ _received_flits.resize(_classes, vector<int>(_inputs, 0));
+ _stored_flits.resize(_classes);
+ _sent_flits.resize(_classes, vector<int>(_outputs, 0));
+ _active_packets.resize(_classes);
+ _outstanding_credits.resize(_classes, vector<int>(_outputs, 0));
+#endif
+
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls.resize(_classes, 0);
+ _buffer_conflict_stalls.resize(_classes, 0);
+ _buffer_full_stalls.resize(_classes, 0);
+ _buffer_reserved_stalls.resize(_classes, 0);
+ _crossbar_conflict_stalls.resize(_classes, 0);
+#endif
+
+}
+
+void Router::AddInputChannel( FlitChannel *channel, CreditChannel *backchannel )
+{
+ _input_channels.push_back( channel );
+ _input_credits.push_back( backchannel );
+ channel->SetSink( this, _input_channels.size() - 1 ) ;
+}
+
+void Router::AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel )
+{
+ _output_channels.push_back( channel );
+ _output_credits.push_back( backchannel );
+ _channel_faults.push_back( false );
+ channel->SetSource( this, _output_channels.size() - 1 ) ;
+}
+
+void Router::Evaluate( )
+{
+ _partial_internal_cycles += _internal_speedup;
+ while( _partial_internal_cycles >= 1.0 ) {
+ _InternalStep( );
+ _partial_internal_cycles -= 1.0;
+ }
+}
+
+void Router::OutChannelFault( int c, bool fault )
+{
+ assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) );
+
+ _channel_faults[c] = fault;
+}
+
+bool Router::IsFaultyOutput( int c ) const
+{
+ assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) );
+
+ return _channel_faults[c];
+}
+
+/*Router constructor*/
+Router *Router::NewRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+{
+ const string type = config.GetStr( "router" );
+ Router *r = NULL;
+ if ( type == "iq" ) {
+ r = new IQRouter( config, parent, name, id, inputs, outputs );
+ } else if ( type == "event" ) {
+ r = new EventRouter( config, parent, name, id, inputs, outputs );
+ } else if ( type == "chaos" ) {
+ r = new ChaosRouter( config, parent, name, id, inputs, outputs );
+ } else {
+ cerr << "Unknown router type: " << type << endl;
+ }
+ /*For additional router, add another else if statement*/
+ /*Original booksim specifies the router using "flow_control"
+ *we now simply call these types.
+ */
+
+ return r;
+}
+
+
+
+
+
diff --git a/src/intersim2/routers/router.hpp b/src/intersim2/routers/router.hpp
new file mode 100644
index 0000000..1dff57f
--- /dev/null
+++ b/src/intersim2/routers/router.hpp
@@ -0,0 +1,202 @@
+// $Id: router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ROUTER_HPP_
+#define _ROUTER_HPP_
+
+#include <string>
+#include <vector>
+
+#include "timed_module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "flitchannel.hpp"
+#include "channel.hpp"
+#include "config_utils.hpp"
+
+typedef Channel<Credit> CreditChannel;
+
+class Router : public TimedModule {
+
+protected:
+
+ static int const STALL_BUFFER_BUSY;
+ static int const STALL_BUFFER_CONFLICT;
+ static int const STALL_BUFFER_FULL;
+ static int const STALL_BUFFER_RESERVED;
+ static int const STALL_CROSSBAR_CONFLICT;
+
+ int _id;
+
+ int _inputs;
+ int _outputs;
+
+ int _classes;
+
+ int _input_speedup;
+ int _output_speedup;
+
+ double _internal_speedup;
+ double _partial_internal_cycles;
+
+ int _crossbar_delay;
+ int _credit_delay;
+
+ vector<FlitChannel *> _input_channels;
+ vector<CreditChannel *> _input_credits;
+ vector<FlitChannel *> _output_channels;
+ vector<CreditChannel *> _output_credits;
+ vector<bool> _channel_faults;
+
+#ifdef TRACK_FLOWS
+ vector<vector<int> > _received_flits;
+ vector<vector<int> > _stored_flits;
+ vector<vector<int> > _sent_flits;
+ vector<vector<int> > _outstanding_credits;
+ vector<vector<int> > _active_packets;
+#endif
+
+#ifdef TRACK_STALLS
+ vector<int> _buffer_busy_stalls;
+ vector<int> _buffer_conflict_stalls;
+ vector<int> _buffer_full_stalls;
+ vector<int> _buffer_reserved_stalls;
+ vector<int> _crossbar_conflict_stalls;
+#endif
+
+ virtual void _InternalStep() = 0;
+
+public:
+ Router( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ static Router *NewRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ virtual void AddInputChannel( FlitChannel *channel, CreditChannel *backchannel );
+ virtual void AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel );
+
+ inline FlitChannel * GetInputChannel( int input ) const {
+ assert((input >= 0) && (input < _inputs));
+ return _input_channels[input];
+ }
+ inline FlitChannel * GetOutputChannel( int output ) const {
+ assert((output >= 0) && (output < _outputs));
+ return _output_channels[output];
+ }
+
+ virtual void ReadInputs( ) = 0;
+ virtual void Evaluate( );
+ virtual void WriteOutputs( ) = 0;
+
+ void OutChannelFault( int c, bool fault = true );
+ bool IsFaultyOutput( int c ) const;
+
+ inline int GetID( ) const {return _id;}
+
+
+ virtual int GetUsedCredit(int o) const = 0;
+ virtual int GetBufferOccupancy(int i) const = 0;
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const = 0;
+ virtual int GetBufferOccupancyForClass(int input, int cl) const = 0;
+#endif
+
+#ifdef TRACK_FLOWS
+ inline vector<int> const & GetReceivedFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _received_flits[c];
+ }
+ inline vector<int> const & GetStoredFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _stored_flits[c];
+ }
+ inline vector<int> const & GetSentFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _sent_flits[c];
+ }
+ inline vector<int> const & GetOutstandingCredits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _outstanding_credits[c];
+ }
+
+ inline vector<int> const & GetActivePackets(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _active_packets[c];
+ }
+
+ inline void ResetFlowStats(int c) {
+ assert((c >= 0) && (c < _classes));
+ _received_flits[c].assign(_received_flits[c].size(), 0);
+ _sent_flits[c].assign(_sent_flits[c].size(), 0);
+ }
+#endif
+
+ virtual vector<int> UsedCredits() const = 0;
+ virtual vector<int> FreeCredits() const = 0;
+ virtual vector<int> MaxCredits() const = 0;
+
+#ifdef TRACK_STALLS
+ inline int GetBufferBusyStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_busy_stalls[c];
+ }
+ inline int GetBufferConflictStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_conflict_stalls[c];
+ }
+ inline int GetBufferFullStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_full_stalls[c];
+ }
+ inline int GetBufferReservedStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_reserved_stalls[c];
+ }
+ inline int GetCrossbarConflictStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _crossbar_conflict_stalls[c];
+ }
+
+ inline void ResetStallStats(int c) {
+ assert((c >= 0) && (c < _classes));
+ _buffer_busy_stalls[c] = 0;
+ _buffer_conflict_stalls[c] = 0;
+ _buffer_full_stalls[c] = 0;
+ _buffer_reserved_stalls[c] = 0;
+ _crossbar_conflict_stalls[c] = 0;
+ }
+#endif
+
+ inline int NumInputs() const {return _inputs;}
+ inline int NumOutputs() const {return _outputs;}
+};
+
+#endif
diff --git a/src/intersim2/stats.cpp b/src/intersim2/stats.cpp
new file mode 100644
index 0000000..b585b35
--- /dev/null
+++ b/src/intersim2/stats.cpp
@@ -0,0 +1,130 @@
+// $Id: stats.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*stats.cpp
+ *
+ *class stores statistics gnerated by the trafficmanager such as the latency
+ *hope count of the the flits
+ *
+ *reset option resets the min and max alues of this statistiscs
+ */
+
+#include "booksim.hpp"
+#include <iostream>
+#include <sstream>
+#include <limits>
+#include <cmath>
+#include <cstdio>
+
+#include "stats.hpp"
+
+Stats::Stats( Module *parent, const string &name,
+ double bin_size, int num_bins ) :
+ Module( parent, name ), _num_bins( num_bins ), _bin_size( bin_size )
+{
+ Clear();
+}
+
+void Stats::Clear( )
+{
+ _num_samples = 0;
+ _sample_sum = 0.0;
+ _sample_squared_sum = 0.0;
+
+ _hist.assign(_num_bins, 0);
+
+ _min = numeric_limits<double>::quiet_NaN();
+ _max = -numeric_limits<double>::quiet_NaN();
+
+ // _reset = true;
+}
+
+double Stats::Average( ) const
+{
+ return _sample_sum / (double)_num_samples;
+}
+
+double Stats::Variance( ) const
+{
+ return (_sample_squared_sum * (double)_num_samples - _sample_sum * _sample_sum) / ((double)_num_samples * (double)_num_samples);
+}
+
+double Stats::Min( ) const
+{
+ return _min;
+}
+
+double Stats::Max( ) const
+{
+ return _max;
+}
+
+double Stats::Sum( ) const
+{
+ return _sample_sum;
+}
+
+double Stats::SquaredSum( ) const
+{
+ return _sample_squared_sum;
+}
+
+int Stats::NumSamples( ) const
+{
+ return _num_samples;
+}
+
+void Stats::AddSample( double val )
+{
+ ++_num_samples;
+ _sample_sum += val;
+
+ // NOTE: the negation ensures that NaN values are handled correctly!
+ _max = !(val <= _max) ? val : _max;
+ _min = !(val >= _min) ? val : _min;
+
+ //double clamp between 0 and num_bins-1
+ int b = (int)fmax(floor( val / _bin_size ), 0.0);
+ b = (b >= _num_bins) ? (_num_bins - 1) : b;
+
+ _hist[b]++;
+}
+
+void Stats::Display( ostream & os ) const
+{
+ os << *this << endl;
+}
+
+ostream & operator<<(ostream & os, const Stats & s) {
+ vector<int> const & v = s._hist;
+ os << "[ ";
+ for(size_t i = 0; i < v.size(); ++i) {
+ os << v[i] << " ";
+ }
+ os << "]";
+ return os;
+}
diff --git a/src/intersim2/stats.hpp b/src/intersim2/stats.hpp
new file mode 100644
index 0000000..1aaf013
--- /dev/null
+++ b/src/intersim2/stats.hpp
@@ -0,0 +1,76 @@
+// $Id: stats.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _STATS_HPP_
+#define _STATS_HPP_
+
+#include "module.hpp"
+
+class Stats : public Module {
+ int _num_samples;
+ double _sample_sum;
+ double _sample_squared_sum;
+
+ //bool _reset;
+ double _min;
+ double _max;
+
+ int _num_bins;
+ double _bin_size;
+
+ vector<int> _hist;
+
+public:
+ Stats( Module *parent, const string &name,
+ double bin_size = 1.0, int num_bins = 10 );
+
+ void Clear( );
+
+ double Average( ) const;
+ double Variance( ) const;
+ double Max( ) const;
+ double Min( ) const;
+ double Sum( ) const;
+ double SquaredSum( ) const;
+ int NumSamples( ) const;
+
+ void AddSample( double val );
+ inline void AddSample( int val ) {
+ AddSample( (double)val );
+ }
+
+ int GetBin(int b){ return _hist[b];}
+
+ void Display( ostream & os = cout ) const;
+
+ friend ostream & operator<<(ostream & os, const Stats & s);
+
+};
+
+ostream & operator<<(ostream & os, const Stats & s);
+
+#endif
diff --git a/src/intersim2/timed_module.hpp b/src/intersim2/timed_module.hpp
new file mode 100644
index 0000000..be0edc1
--- /dev/null
+++ b/src/intersim2/timed_module.hpp
@@ -0,0 +1,44 @@
+// $Id: timed_module.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _TIMED_MODULE_HPP_
+#define _TIMED_MODULE_HPP_
+
+#include "module.hpp"
+
+class TimedModule : public Module {
+
+public:
+ TimedModule(Module * parent, string const & name) : Module(parent, name) {}
+ virtual ~TimedModule() {}
+
+ virtual void ReadInputs() = 0;
+ virtual void Evaluate() = 0;
+ virtual void WriteOutputs() = 0;
+};
+
+#endif
diff --git a/src/intersim2/traffic.cpp b/src/intersim2/traffic.cpp
new file mode 100644
index 0000000..7ee74a5
--- /dev/null
+++ b/src/intersim2/traffic.cpp
@@ -0,0 +1,518 @@
+// $Id: traffic.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <iostream>
+#include <sstream>
+#include "random_utils.hpp"
+#include "traffic.hpp"
+
+TrafficPattern::TrafficPattern(int nodes)
+: _nodes(nodes)
+{
+ if(nodes <= 0) {
+ cout << "Error: Traffic patterns require at least one node." << endl;
+ exit(-1);
+ }
+}
+
+void TrafficPattern::reset()
+{
+
+}
+
+TrafficPattern * TrafficPattern::New(string const & pattern, int nodes,
+ Configuration const * const config)
+{
+ string pattern_name;
+ string param_str;
+ size_t left = pattern.find_first_of('(');
+ if(left == string::npos) {
+ pattern_name = pattern;
+ } else {
+ pattern_name = pattern.substr(0, left);
+ size_t right = pattern.find_last_of(')');
+ if(right == string::npos) {
+ param_str = pattern.substr(left+1);
+ } else {
+ param_str = pattern.substr(left+1, right-left-1);
+ }
+ }
+ vector<string> params = tokenize_str(param_str);
+
+ TrafficPattern * result = NULL;
+ if(pattern_name == "bitcomp") {
+ result = new BitCompTrafficPattern(nodes);
+ } else if(pattern_name == "transpose") {
+ result = new TransposeTrafficPattern(nodes);
+ } else if(pattern_name == "bitrev") {
+ result = new BitRevTrafficPattern(nodes);
+ } else if(pattern_name == "shuffle") {
+ result = new ShuffleTrafficPattern(nodes);
+ } else if(pattern_name == "randperm") {
+ int perm_seed = -1;
+ if(params.empty()) {
+ if(config) {
+ perm_seed = config->GetInt("perm_seed");
+ } else {
+ cout << "Error: Missing parameter for random permutation traffic pattern: " << pattern << endl;
+ exit(-1);
+ }
+ } else {
+ perm_seed = atoi(params[0].c_str());
+ }
+ result = new RandomPermutationTrafficPattern(nodes, perm_seed);
+ } else if(pattern_name == "uniform") {
+ result = new UniformRandomTrafficPattern(nodes);
+ } else if(pattern_name == "background") {
+ vector<int> excludes = tokenize_int(params[0]);
+ result = new UniformBackgroundTrafficPattern(nodes, excludes);
+ } else if(pattern_name == "diagonal") {
+ result = new DiagonalTrafficPattern(nodes);
+ } else if(pattern_name == "asymmetric") {
+ result = new AsymmetricTrafficPattern(nodes);
+ } else if(pattern_name == "taper64") {
+ result = new Taper64TrafficPattern(nodes);
+ } else if(pattern_name == "bad_dragon") {
+ bool missing_params = false;
+ int k = -1;
+ if(params.size() < 1) {
+ if(config) {
+ k = config->GetInt("k");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ k = atoi(params[0].c_str());
+ }
+ int n = -1;
+ if(params.size() < 2) {
+ if(config) {
+ n = config->GetInt("n");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ n = atoi(params[1].c_str());
+ }
+ if(missing_params) {
+ cout << "Error: Missing parameters for dragonfly bad permutation traffic pattern: " << pattern << endl;
+ exit(-1);
+ }
+ result = new BadPermDFlyTrafficPattern(nodes, k, n);
+ } else if((pattern_name == "tornado") || (pattern_name == "neighbor") ||
+ (pattern_name == "badperm_yarc")) {
+ bool missing_params = false;
+ int k = -1;
+ if(params.size() < 1) {
+ if(config) {
+ k = config->GetInt("k");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ k = atoi(params[0].c_str());
+ }
+ int n = -1;
+ if(params.size() < 2) {
+ if(config) {
+ n = config->GetInt("n");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ n = atoi(params[1].c_str());
+ }
+ int xr = -1;
+ if(params.size() < 3) {
+ if(config) {
+ xr = config->GetInt("xr");
+ } else {
+ missing_params = true;
+ }
+ } else {
+ xr = atoi(params[2].c_str());
+ }
+ if(missing_params) {
+ cout << "Error: Missing parameters for digit permutation traffic pattern: " << pattern << endl;
+ exit(-1);
+ }
+ if(pattern_name == "tornado") {
+ result = new TornadoTrafficPattern(nodes, k, n, xr);
+ } else if(pattern_name == "neighbor") {
+ result = new NeighborTrafficPattern(nodes, k, n, xr);
+ } else if(pattern_name == "badperm_yarc") {
+ result = new BadPermYarcTrafficPattern(nodes, k, n, xr);
+ }
+ } else if(pattern_name == "hotspot") {
+ if(params.empty()) {
+ params.push_back("-1");
+ }
+ vector<int> hotspots = tokenize_int(params[0]);
+ for(size_t i = 0; i < hotspots.size(); ++i) {
+ if(hotspots[i] < 0) {
+ hotspots[i] = RandomInt(nodes - 1);
+ }
+ }
+ vector<int> rates;
+ if(params.size() >= 2) {
+ rates = tokenize_int(params[1]);
+ rates.resize(hotspots.size(), rates.back());
+ } else {
+ rates.resize(hotspots.size(), 1);
+ }
+ result = new HotSpotTrafficPattern(nodes, hotspots, rates);
+ } else {
+ cout << "Error: Unknown traffic pattern: " << pattern << endl;
+ exit(-1);
+ }
+ return result;
+}
+
+PermutationTrafficPattern::PermutationTrafficPattern(int nodes)
+ : TrafficPattern(nodes)
+{
+
+}
+
+BitPermutationTrafficPattern::BitPermutationTrafficPattern(int nodes)
+ : PermutationTrafficPattern(nodes)
+{
+ if((nodes & -nodes) != nodes) {
+ cout << "Error: Bit permutation traffic patterns require the number of "
+ << "nodes to be a power of two." << endl;
+ exit(-1);
+ }
+}
+
+BitCompTrafficPattern::BitCompTrafficPattern(int nodes)
+ : BitPermutationTrafficPattern(nodes)
+{
+
+}
+
+int BitCompTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int const mask = _nodes - 1;
+ return ~source & mask;
+}
+
+TransposeTrafficPattern::TransposeTrafficPattern(int nodes)
+ : BitPermutationTrafficPattern(nodes), _shift(0)
+{
+ while(nodes >>= 1) {
+ ++_shift;
+ }
+ if(_shift % 2) {
+ cout << "Error: Transpose traffic pattern requires the number of nodes to "
+ << "be an even power of two." << endl;
+ exit(-1);
+ }
+ _shift >>= 1;
+}
+
+int TransposeTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int const mask_lo = (1 << _shift) - 1;
+ int const mask_hi = mask_lo << _shift;
+ return (((source >> _shift) & mask_lo) | ((source << _shift) & mask_hi));
+}
+
+BitRevTrafficPattern::BitRevTrafficPattern(int nodes)
+ : BitPermutationTrafficPattern(nodes)
+{
+
+}
+
+int BitRevTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int result = 0;
+ for(int n = _nodes; n > 1; n >>= 1) {
+ result = (result << 1) | (source % 2);
+ source >>= 1;
+ }
+ return result;
+}
+
+ShuffleTrafficPattern::ShuffleTrafficPattern(int nodes)
+ : BitPermutationTrafficPattern(nodes)
+{
+
+}
+
+int ShuffleTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int const shifted = source << 1;
+ return ((shifted & (_nodes - 1)) | bool(shifted & _nodes));
+}
+
+DigitPermutationTrafficPattern::DigitPermutationTrafficPattern(int nodes, int k,
+ int n, int xr)
+ : PermutationTrafficPattern(nodes), _k(k), _n(n), _xr(xr)
+{
+
+}
+
+TornadoTrafficPattern::TornadoTrafficPattern(int nodes, int k, int n, int xr)
+ : DigitPermutationTrafficPattern(nodes, k, n, xr)
+{
+
+}
+
+int TornadoTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ int offset = 1;
+ int result = 0;
+
+ for(int n = 0; n < _n; ++n) {
+ result += offset *
+ (((source / offset) % (_xr * _k) + ((_xr * _k + 1) / 2 - 1)) % (_xr * _k));
+ offset *= (_xr * _k);
+ }
+ return result;
+}
+
+NeighborTrafficPattern::NeighborTrafficPattern(int nodes, int k, int n, int xr)
+ : DigitPermutationTrafficPattern(nodes, k, n, xr)
+{
+
+}
+
+int NeighborTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ int offset = 1;
+ int result = 0;
+
+ for(int n = 0; n < _n; ++n) {
+ result += offset *
+ (((source / offset) % (_xr * _k) + 1) % (_xr * _k));
+ offset *= (_xr * _k);
+ }
+ return result;
+}
+
+RandomPermutationTrafficPattern::RandomPermutationTrafficPattern(int nodes,
+ int seed)
+ : TrafficPattern(nodes)
+{
+ _dest.resize(nodes);
+ randomize(seed);
+}
+
+void RandomPermutationTrafficPattern::randomize(int seed)
+{
+ unsigned long prev_seed = RandomIntLong( );
+ RandomSeed(seed);
+
+ _dest.assign(_nodes, -1);
+
+ for(int i = 0; i < _nodes; ++i) {
+ int ind = RandomInt(_nodes - 1 - i);
+
+ int j = 0;
+ int cnt = 0;
+ while((cnt < ind) || (_dest[j] != -1)) {
+ if(_dest[j] == -1) {
+ ++cnt;
+ }
+ ++j;
+ assert(j < _nodes);
+ }
+
+ _dest[j] = i;
+ }
+
+ RandomSeed(prev_seed);
+}
+
+int RandomPermutationTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ assert((_dest[source] >= 0) && (_dest[source] < _nodes));
+ return _dest[source];
+}
+
+RandomTrafficPattern::RandomTrafficPattern(int nodes)
+ : TrafficPattern(nodes)
+{
+
+}
+
+UniformRandomTrafficPattern::UniformRandomTrafficPattern(int nodes)
+ : RandomTrafficPattern(nodes)
+{
+
+}
+
+int UniformRandomTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ return RandomInt(_nodes - 1);
+}
+
+UniformBackgroundTrafficPattern::UniformBackgroundTrafficPattern(int nodes, vector<int> excluded_nodes)
+ : RandomTrafficPattern(nodes)
+{
+ for(size_t i = 0; i < excluded_nodes.size(); ++i) {
+ int const node = excluded_nodes[i];
+ assert((node >= 0) && (node < _nodes));
+ _excluded.insert(node);
+ }
+}
+
+int UniformBackgroundTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ int result;
+
+ do {
+ result = RandomInt(_nodes - 1);
+ } while(_excluded.count(result) > 0);
+
+ return result;
+}
+
+DiagonalTrafficPattern::DiagonalTrafficPattern(int nodes)
+ : RandomTrafficPattern(nodes)
+{
+
+}
+
+int DiagonalTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ return ((RandomInt(2) == 0) ? ((source + 1) % _nodes) : source);
+}
+
+AsymmetricTrafficPattern::AsymmetricTrafficPattern(int nodes)
+ : RandomTrafficPattern(nodes)
+{
+
+}
+
+int AsymmetricTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int const half = _nodes / 2;
+ return (source % half) + (RandomInt(1) ? half : 0);
+}
+
+Taper64TrafficPattern::Taper64TrafficPattern(int nodes)
+ : RandomTrafficPattern(nodes)
+{
+ if(nodes != 64) {
+ cout << "Error: Tthe Taper64 traffic pattern requires the number of nodes "
+ << "to be exactly 64." << endl;
+ exit(-1);
+ }
+}
+
+int Taper64TrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ if(RandomInt(1)) {
+ return ((64 + source + 8 * (RandomInt(2) - 1) + (RandomInt(2) - 1)) % 64);
+ } else {
+ return RandomInt(_nodes - 1);
+ }
+}
+
+BadPermDFlyTrafficPattern::BadPermDFlyTrafficPattern(int nodes, int k, int n)
+ : DigitPermutationTrafficPattern(nodes, k, n, 1)
+{
+
+}
+
+int BadPermDFlyTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ int const grp_size_routers = 2 * _k;
+ int const grp_size_nodes = grp_size_routers * _k;
+
+ return ((RandomInt(grp_size_nodes - 1) + ((source / grp_size_nodes) + 1) * grp_size_nodes) % _nodes);
+}
+
+BadPermYarcTrafficPattern::BadPermYarcTrafficPattern(int nodes, int k, int n,
+ int xr)
+ : DigitPermutationTrafficPattern(nodes, k, n, xr)
+{
+
+}
+
+int BadPermYarcTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+ int const row = source / (_xr * _k);
+ return RandomInt((_xr * _k) - 1) * (_xr * _k) + row;
+}
+
+HotSpotTrafficPattern::HotSpotTrafficPattern(int nodes, vector<int> hotspots,
+ vector<int> rates)
+ : TrafficPattern(nodes), _hotspots(hotspots), _rates(rates), _max_val(-1)
+{
+ assert(!_hotspots.empty());
+ size_t const size = _hotspots.size();
+ _rates.resize(size, _rates.empty() ? 1 : _rates.back());
+ for(size_t i = 0; i < size; ++i) {
+ int const hotspot = _hotspots[i];
+ assert((hotspot >= 0) && (hotspot < _nodes));
+ int const rate = _rates[i];
+ assert(rate >= 0);
+ _max_val += rate;
+ }
+}
+
+int HotSpotTrafficPattern::dest(int source)
+{
+ assert((source >= 0) && (source < _nodes));
+
+ if(_hotspots.size() == 1) {
+ return _hotspots[0];
+ }
+
+ int pct = RandomInt(_max_val);
+
+ for(size_t i = 0; i < (_hotspots.size() - 1); ++i) {
+ int const limit = _rates[i];
+ if(limit > pct) {
+ return _hotspots[i];
+ } else {
+ pct -= limit;
+ }
+ }
+ assert(_rates.back() > pct);
+ return _hotspots.back();
+}
diff --git a/src/intersim2/traffic.hpp b/src/intersim2/traffic.hpp
new file mode 100644
index 0000000..798b790
--- /dev/null
+++ b/src/intersim2/traffic.hpp
@@ -0,0 +1,174 @@
+// $Id: traffic.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _TRAFFIC_HPP_
+#define _TRAFFIC_HPP_
+
+#include <vector>
+#include <set>
+#include "config_utils.hpp"
+
+using namespace std;
+
+class TrafficPattern {
+protected:
+ int _nodes;
+ TrafficPattern(int nodes);
+public:
+ virtual ~TrafficPattern() {}
+ virtual void reset();
+ virtual int dest(int source) = 0;
+ static TrafficPattern * New(string const & pattern, int nodes,
+ Configuration const * const config = NULL);
+};
+
+class PermutationTrafficPattern : public TrafficPattern {
+protected:
+ PermutationTrafficPattern(int nodes);
+};
+
+class BitPermutationTrafficPattern : public PermutationTrafficPattern {
+protected:
+ BitPermutationTrafficPattern(int nodes);
+};
+
+class BitCompTrafficPattern : public BitPermutationTrafficPattern {
+public:
+ BitCompTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class TransposeTrafficPattern : public BitPermutationTrafficPattern {
+protected:
+ int _shift;
+public:
+ TransposeTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class BitRevTrafficPattern : public BitPermutationTrafficPattern {
+public:
+ BitRevTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class ShuffleTrafficPattern : public BitPermutationTrafficPattern {
+public:
+ ShuffleTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class DigitPermutationTrafficPattern : public PermutationTrafficPattern {
+protected:
+ int _k;
+ int _n;
+ int _xr;
+ DigitPermutationTrafficPattern(int nodes, int k, int n, int xr = 1);
+};
+
+class TornadoTrafficPattern : public DigitPermutationTrafficPattern {
+public:
+ TornadoTrafficPattern(int nodes, int k, int n, int xr = 1);
+ virtual int dest(int source);
+};
+
+class NeighborTrafficPattern : public DigitPermutationTrafficPattern {
+public:
+ NeighborTrafficPattern(int nodes, int k, int n, int xr = 1);
+ virtual int dest(int source);
+};
+
+class RandomPermutationTrafficPattern : public TrafficPattern {
+private:
+ vector<int> _dest;
+ inline void randomize(int seed);
+public:
+ RandomPermutationTrafficPattern(int nodes, int seed);
+ virtual int dest(int source);
+};
+
+class RandomTrafficPattern : public TrafficPattern {
+protected:
+ RandomTrafficPattern(int nodes);
+};
+
+class UniformRandomTrafficPattern : public RandomTrafficPattern {
+public:
+ UniformRandomTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class UniformBackgroundTrafficPattern : public RandomTrafficPattern {
+private:
+ set<int> _excluded;
+public:
+ UniformBackgroundTrafficPattern(int nodes, vector<int> excluded_nodes);
+ virtual int dest(int source);
+};
+
+class DiagonalTrafficPattern : public RandomTrafficPattern {
+public:
+ DiagonalTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class AsymmetricTrafficPattern : public RandomTrafficPattern {
+public:
+ AsymmetricTrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class Taper64TrafficPattern : public RandomTrafficPattern {
+public:
+ Taper64TrafficPattern(int nodes);
+ virtual int dest(int source);
+};
+
+class BadPermDFlyTrafficPattern : public DigitPermutationTrafficPattern {
+public:
+ BadPermDFlyTrafficPattern(int nodes, int k, int n);
+ virtual int dest(int source);
+};
+
+class BadPermYarcTrafficPattern : public DigitPermutationTrafficPattern {
+public:
+ BadPermYarcTrafficPattern(int nodes, int k, int n, int xr = 1);
+ virtual int dest(int source);
+};
+
+class HotSpotTrafficPattern : public TrafficPattern {
+private:
+ vector<int> _hotspots;
+ vector<int> _rates;
+ int _max_val;
+public:
+ HotSpotTrafficPattern(int nodes, vector<int> hotspots,
+ vector<int> rates = vector<int>());
+ virtual int dest(int source);
+};
+
+#endif
diff --git a/src/intersim2/trafficmanager.cpp b/src/intersim2/trafficmanager.cpp
new file mode 100644
index 0000000..7b2289c
--- /dev/null
+++ b/src/intersim2/trafficmanager.cpp
@@ -0,0 +1,2287 @@
+// $Id: trafficmanager.cpp 5506 2013-05-07 21:22:23Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sstream>
+#include <cmath>
+#include <fstream>
+#include <limits>
+#include <cstdlib>
+
+#include "booksim.hpp"
+#include "booksim_config.hpp"
+#include "trafficmanager.hpp"
+#include "batchtrafficmanager.hpp"
+#include "gputrafficmanager.hpp"
+#include "random_utils.hpp"
+#include "vc.hpp"
+#include "packet_reply_info.hpp"
+
+TrafficManager * TrafficManager::New(Configuration const & config,
+ vector<Network *> const & net)
+{
+ TrafficManager * result = NULL;
+ string sim_type = config.GetStr("sim_type");
+ if((sim_type == "latency") || (sim_type == "throughput")) {
+ result = new TrafficManager(config, net);
+ } else if(sim_type == "batch") {
+ result = new BatchTrafficManager(config, net);
+ } else if(sim_type == "gpgpusim") {
+ result = new GPUTrafficManager(config, net);
+ }
+ else {
+ cerr << "Unknown simulation type: " << sim_type << endl;
+ }
+ return result;
+}
+
+TrafficManager::TrafficManager( const Configuration &config, const vector<Network *> & net )
+: Module( 0, "traffic_manager" ), _net(net), _empty_network(false), _deadlock_timer(0), _reset_time(0), _drain_time(-1), _cur_id(0), _cur_pid(0), _time(0)
+{
+
+ _nodes = _net[0]->NumNodes( );
+ _routers = _net[0]->NumRouters( );
+
+ _vcs = config.GetInt("num_vcs");
+ _subnets = config.GetInt("subnets");
+
+ _subnet.resize(Flit::NUM_FLIT_TYPES);
+ _subnet[Flit::READ_REQUEST] = config.GetInt("read_request_subnet");
+ _subnet[Flit::READ_REPLY] = config.GetInt("read_reply_subnet");
+ _subnet[Flit::WRITE_REQUEST] = config.GetInt("write_request_subnet");
+ _subnet[Flit::WRITE_REPLY] = config.GetInt("write_reply_subnet");
+
+ // ============ Message priorities ============
+
+ string priority = config.GetStr( "priority" );
+
+ if ( priority == "class" ) {
+ _pri_type = class_based;
+ } else if ( priority == "age" ) {
+ _pri_type = age_based;
+ } else if ( priority == "network_age" ) {
+ _pri_type = network_age_based;
+ } else if ( priority == "local_age" ) {
+ _pri_type = local_age_based;
+ } else if ( priority == "queue_length" ) {
+ _pri_type = queue_length_based;
+ } else if ( priority == "hop_count" ) {
+ _pri_type = hop_count_based;
+ } else if ( priority == "sequence" ) {
+ _pri_type = sequence_based;
+ } else if ( priority == "none" ) {
+ _pri_type = none;
+ } else {
+ Error( "Unkown priority value: " + priority );
+ }
+
+ // ============ Routing ============
+
+ string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::const_iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ _lookahead_routing = !config.GetInt("routing_delay");
+ _noq = config.GetInt("noq");
+ if(_noq) {
+ if(!_lookahead_routing) {
+ Error("NOQ requires lookahead routing to be enabled.");
+ }
+ }
+
+ // ============ Traffic ============
+
+ _classes = config.GetInt("classes");
+
+ _use_read_write = config.GetIntArray("use_read_write");
+ if(_use_read_write.empty()) {
+ _use_read_write.push_back(config.GetInt("use_read_write"));
+ }
+ _use_read_write.resize(_classes, _use_read_write.back());
+
+ _write_fraction = config.GetFloatArray("write_fraction");
+ if(_write_fraction.empty()) {
+ _write_fraction.push_back(config.GetFloat("write_fraction"));
+ }
+ _write_fraction.resize(_classes, _write_fraction.back());
+
+ _read_request_size = config.GetIntArray("read_request_size");
+ if(_read_request_size.empty()) {
+ _read_request_size.push_back(config.GetInt("read_request_size"));
+ }
+ _read_request_size.resize(_classes, _read_request_size.back());
+
+ _read_reply_size = config.GetIntArray("read_reply_size");
+ if(_read_reply_size.empty()) {
+ _read_reply_size.push_back(config.GetInt("read_reply_size"));
+ }
+ _read_reply_size.resize(_classes, _read_reply_size.back());
+
+ _write_request_size = config.GetIntArray("write_request_size");
+ if(_write_request_size.empty()) {
+ _write_request_size.push_back(config.GetInt("write_request_size"));
+ }
+ _write_request_size.resize(_classes, _write_request_size.back());
+
+ _write_reply_size = config.GetIntArray("write_reply_size");
+ if(_write_reply_size.empty()) {
+ _write_reply_size.push_back(config.GetInt("write_reply_size"));
+ }
+ _write_reply_size.resize(_classes, _write_reply_size.back());
+
+ string packet_size_str = config.GetStr("packet_size");
+ if(packet_size_str.empty()) {
+ _packet_size.push_back(vector<int>(1, config.GetInt("packet_size")));
+ } else {
+ vector<string> packet_size_strings = tokenize_str(packet_size_str);
+ for(size_t i = 0; i < packet_size_strings.size(); ++i) {
+ _packet_size.push_back(tokenize_int(packet_size_strings[i]));
+ }
+ }
+ _packet_size.resize(_classes, _packet_size.back());
+
+ string packet_size_rate_str = config.GetStr("packet_size_rate");
+ if(packet_size_rate_str.empty()) {
+ int rate = config.GetInt("packet_size_rate");
+ assert(rate >= 0);
+ for(int c = 0; c < _classes; ++c) {
+ int size = _packet_size[c].size();
+ _packet_size_rate.push_back(vector<int>(size, rate));
+ _packet_size_max_val.push_back(size * rate - 1);
+ }
+ } else {
+ vector<string> packet_size_rate_strings = tokenize_str(packet_size_rate_str);
+ packet_size_rate_strings.resize(_classes, packet_size_rate_strings.back());
+ for(int c = 0; c < _classes; ++c) {
+ vector<int> rates = tokenize_int(packet_size_rate_strings[c]);
+ rates.resize(_packet_size[c].size(), rates.back());
+ _packet_size_rate.push_back(rates);
+ int size = rates.size();
+ int max_val = -1;
+ for(int i = 0; i < size; ++i) {
+ int rate = rates[i];
+ assert(rate >= 0);
+ max_val += rate;
+ }
+ _packet_size_max_val.push_back(max_val);
+ }
+ }
+
+ for(int c = 0; c < _classes; ++c) {
+ if(_use_read_write[c]) {
+ _packet_size[c] =
+ vector<int>(1, (_read_request_size[c] + _read_reply_size[c] +
+ _write_request_size[c] + _write_reply_size[c]) / 2);
+ _packet_size_rate[c] = vector<int>(1, 1);
+ _packet_size_max_val[c] = 0;
+ }
+ }
+
+ _load = config.GetFloatArray("injection_rate");
+ if(_load.empty()) {
+ _load.push_back(config.GetFloat("injection_rate"));
+ }
+ _load.resize(_classes, _load.back());
+
+ if(config.GetInt("injection_rate_uses_flits")) {
+ for(int c = 0; c < _classes; ++c)
+ _load[c] /= _GetAveragePacketSize(c);
+ }
+
+ _traffic = config.GetStrArray("traffic");
+ _traffic.resize(_classes, _traffic.back());
+
+ _traffic_pattern.resize(_classes);
+
+ _class_priority = config.GetIntArray("class_priority");
+ if(_class_priority.empty()) {
+ _class_priority.push_back(config.GetInt("class_priority"));
+ }
+ _class_priority.resize(_classes, _class_priority.back());
+
+ vector<string> injection_process = config.GetStrArray("injection_process");
+ injection_process.resize(_classes, injection_process.back());
+
+ _injection_process.resize(_classes);
+
+ for(int c = 0; c < _classes; ++c) {
+ _traffic_pattern[c] = TrafficPattern::New(_traffic[c], _nodes, &config);
+ _injection_process[c] = InjectionProcess::New(injection_process[c], _nodes, _load[c], &config);
+ }
+
+ // ============ Injection VC states ============
+
+ _buf_states.resize(_nodes);
+ _last_vc.resize(_nodes);
+ _last_class.resize(_nodes);
+
+ for ( int source = 0; source < _nodes; ++source ) {
+ _buf_states[source].resize(_subnets);
+ _last_class[source].resize(_subnets, 0);
+ _last_vc[source].resize(_subnets);
+ for ( int subnet = 0; subnet < _subnets; ++subnet ) {
+ ostringstream tmp_name;
+ tmp_name << "terminal_buf_state_" << source << "_" << subnet;
+ BufferState * bs = new BufferState( config, this, tmp_name.str( ) );
+ int vc_alloc_delay = config.GetInt("vc_alloc_delay");
+ int sw_alloc_delay = config.GetInt("sw_alloc_delay");
+ int router_latency = config.GetInt("routing_delay") + (config.GetInt("speculative") ? max(vc_alloc_delay, sw_alloc_delay) : (vc_alloc_delay + sw_alloc_delay));
+ int min_latency = 1 + _net[subnet]->GetInject(source)->GetLatency() + router_latency + _net[subnet]->GetInjectCred(source)->GetLatency();
+ bs->SetMinLatency(min_latency);
+ _buf_states[source][subnet] = bs;
+ _last_vc[source][subnet].resize(_classes, -1);
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ _outstanding_credits.resize(_classes);
+ for(int c = 0; c < _classes; ++c) {
+ _outstanding_credits[c].resize(_subnets, vector<int>(_nodes, 0));
+ }
+ _outstanding_classes.resize(_nodes);
+ for(int n = 0; n < _nodes; ++n) {
+ _outstanding_classes[n].resize(_subnets, vector<queue<int> >(_vcs));
+ }
+#endif
+
+ // ============ Injection queues ============
+
+ _qtime.resize(_nodes);
+ _qdrained.resize(_nodes);
+ _partial_packets.resize(_nodes);
+
+ for ( int s = 0; s < _nodes; ++s ) {
+ _qtime[s].resize(_classes);
+ _qdrained[s].resize(_classes);
+ _partial_packets[s].resize(_classes);
+ }
+
+ _total_in_flight_flits.resize(_classes);
+ _measured_in_flight_flits.resize(_classes);
+ _retired_packets.resize(_classes);
+
+ _packet_seq_no.resize(_nodes);
+ _repliesPending.resize(_nodes);
+ _requestsOutstanding.resize(_nodes);
+
+ _hold_switch_for_packet = config.GetInt("hold_switch_for_packet");
+
+ // ============ Simulation parameters ============
+
+ _total_sims = config.GetInt( "sim_count" );
+
+ _router.resize(_subnets);
+ for (int i=0; i < _subnets; ++i) {
+ _router[i] = _net[i]->GetRouters();
+ }
+
+ //seed the network
+ RandomSeed(config.GetInt("seed"));
+
+ _measure_latency = (config.GetStr("sim_type") == "latency");
+
+ _sample_period = config.GetInt( "sample_period" );
+ _max_samples = config.GetInt( "max_samples" );
+ _warmup_periods = config.GetInt( "warmup_periods" );
+
+ _measure_stats = config.GetIntArray( "measure_stats" );
+ if(_measure_stats.empty()) {
+ _measure_stats.push_back(config.GetInt("measure_stats"));
+ }
+ _measure_stats.resize(_classes, _measure_stats.back());
+ _pair_stats = (config.GetInt("pair_stats")==1);
+
+ _latency_thres = config.GetFloatArray( "latency_thres" );
+ if(_latency_thres.empty()) {
+ _latency_thres.push_back(config.GetFloat("latency_thres"));
+ }
+ _latency_thres.resize(_classes, _latency_thres.back());
+
+ _warmup_threshold = config.GetFloatArray( "warmup_thres" );
+ if(_warmup_threshold.empty()) {
+ _warmup_threshold.push_back(config.GetFloat("warmup_thres"));
+ }
+ _warmup_threshold.resize(_classes, _warmup_threshold.back());
+
+ _acc_warmup_threshold = config.GetFloatArray( "acc_warmup_thres" );
+ if(_acc_warmup_threshold.empty()) {
+ _acc_warmup_threshold.push_back(config.GetFloat("acc_warmup_thres"));
+ }
+ _acc_warmup_threshold.resize(_classes, _acc_warmup_threshold.back());
+
+ _stopping_threshold = config.GetFloatArray( "stopping_thres" );
+ if(_stopping_threshold.empty()) {
+ _stopping_threshold.push_back(config.GetFloat("stopping_thres"));
+ }
+ _stopping_threshold.resize(_classes, _stopping_threshold.back());
+
+ _acc_stopping_threshold = config.GetFloatArray( "acc_stopping_thres" );
+ if(_acc_stopping_threshold.empty()) {
+ _acc_stopping_threshold.push_back(config.GetFloat("acc_stopping_thres"));
+ }
+ _acc_stopping_threshold.resize(_classes, _acc_stopping_threshold.back());
+
+ _include_queuing = config.GetInt( "include_queuing" );
+
+ _print_csv_results = config.GetInt( "print_csv_results" );
+ _deadlock_warn_timeout = config.GetInt( "deadlock_warn_timeout" );
+
+ string watch_file = config.GetStr( "watch_file" );
+ if((watch_file != "") && (watch_file != "-")) {
+ _LoadWatchList(watch_file);
+ }
+
+ vector<int> watch_flits = config.GetIntArray("watch_flits");
+ for(size_t i = 0; i < watch_flits.size(); ++i) {
+ _flits_to_watch.insert(watch_flits[i]);
+ }
+
+ vector<int> watch_packets = config.GetIntArray("watch_packets");
+ for(size_t i = 0; i < watch_packets.size(); ++i) {
+ _packets_to_watch.insert(watch_packets[i]);
+ }
+
+ string stats_out_file = config.GetStr( "stats_out" );
+ if(stats_out_file == "") {
+ _stats_out = NULL;
+ } else if(stats_out_file == "-") {
+ _stats_out = &cout;
+ } else {
+ _stats_out = new ofstream(stats_out_file.c_str());
+ config.WriteMatlabFile(_stats_out);
+ }
+
+#ifdef TRACK_FLOWS
+ _injected_flits.resize(_classes, vector<int>(_nodes, 0));
+ _ejected_flits.resize(_classes, vector<int>(_nodes, 0));
+ string injected_flits_out_file = config.GetStr( "injected_flits_out" );
+ if(injected_flits_out_file == "") {
+ _injected_flits_out = NULL;
+ } else {
+ _injected_flits_out = new ofstream(injected_flits_out_file.c_str());
+ }
+ string received_flits_out_file = config.GetStr( "received_flits_out" );
+ if(received_flits_out_file == "") {
+ _received_flits_out = NULL;
+ } else {
+ _received_flits_out = new ofstream(received_flits_out_file.c_str());
+ }
+ string stored_flits_out_file = config.GetStr( "stored_flits_out" );
+ if(stored_flits_out_file == "") {
+ _stored_flits_out = NULL;
+ } else {
+ _stored_flits_out = new ofstream(stored_flits_out_file.c_str());
+ }
+ string sent_flits_out_file = config.GetStr( "sent_flits_out" );
+ if(sent_flits_out_file == "") {
+ _sent_flits_out = NULL;
+ } else {
+ _sent_flits_out = new ofstream(sent_flits_out_file.c_str());
+ }
+ string outstanding_credits_out_file = config.GetStr( "outstanding_credits_out" );
+ if(outstanding_credits_out_file == "") {
+ _outstanding_credits_out = NULL;
+ } else {
+ _outstanding_credits_out = new ofstream(outstanding_credits_out_file.c_str());
+ }
+ string ejected_flits_out_file = config.GetStr( "ejected_flits_out" );
+ if(ejected_flits_out_file == "") {
+ _ejected_flits_out = NULL;
+ } else {
+ _ejected_flits_out = new ofstream(ejected_flits_out_file.c_str());
+ }
+ string active_packets_out_file = config.GetStr( "active_packets_out" );
+ if(active_packets_out_file == "") {
+ _active_packets_out = NULL;
+ } else {
+ _active_packets_out = new ofstream(active_packets_out_file.c_str());
+ }
+#endif
+
+#ifdef TRACK_CREDITS
+ string used_credits_out_file = config.GetStr( "used_credits_out" );
+ if(used_credits_out_file == "") {
+ _used_credits_out = NULL;
+ } else {
+ _used_credits_out = new ofstream(used_credits_out_file.c_str());
+ }
+ string free_credits_out_file = config.GetStr( "free_credits_out" );
+ if(free_credits_out_file == "") {
+ _free_credits_out = NULL;
+ } else {
+ _free_credits_out = new ofstream(free_credits_out_file.c_str());
+ }
+ string max_credits_out_file = config.GetStr( "max_credits_out" );
+ if(max_credits_out_file == "") {
+ _max_credits_out = NULL;
+ } else {
+ _max_credits_out = new ofstream(max_credits_out_file.c_str());
+ }
+#endif
+
+ // ============ Statistics ============
+
+ _plat_stats.resize(_classes);
+ _overall_min_plat.resize(_classes, 0.0);
+ _overall_avg_plat.resize(_classes, 0.0);
+ _overall_max_plat.resize(_classes, 0.0);
+
+ _nlat_stats.resize(_classes);
+ _overall_min_nlat.resize(_classes, 0.0);
+ _overall_avg_nlat.resize(_classes, 0.0);
+ _overall_max_nlat.resize(_classes, 0.0);
+
+ _flat_stats.resize(_classes);
+ _overall_min_flat.resize(_classes, 0.0);
+ _overall_avg_flat.resize(_classes, 0.0);
+ _overall_max_flat.resize(_classes, 0.0);
+
+ _frag_stats.resize(_classes);
+ _overall_min_frag.resize(_classes, 0.0);
+ _overall_avg_frag.resize(_classes, 0.0);
+ _overall_max_frag.resize(_classes, 0.0);
+
+ if(_pair_stats){
+ _pair_plat.resize(_classes);
+ _pair_nlat.resize(_classes);
+ _pair_flat.resize(_classes);
+ }
+
+ _hop_stats.resize(_classes);
+ _overall_hop_stats.resize(_classes, 0.0);
+
+ _sent_packets.resize(_classes);
+ _overall_min_sent_packets.resize(_classes, 0.0);
+ _overall_avg_sent_packets.resize(_classes, 0.0);
+ _overall_max_sent_packets.resize(_classes, 0.0);
+ _accepted_packets.resize(_classes);
+ _overall_min_accepted_packets.resize(_classes, 0.0);
+ _overall_avg_accepted_packets.resize(_classes, 0.0);
+ _overall_max_accepted_packets.resize(_classes, 0.0);
+
+ _sent_flits.resize(_classes);
+ _overall_min_sent.resize(_classes, 0.0);
+ _overall_avg_sent.resize(_classes, 0.0);
+ _overall_max_sent.resize(_classes, 0.0);
+ _accepted_flits.resize(_classes);
+ _overall_min_accepted.resize(_classes, 0.0);
+ _overall_avg_accepted.resize(_classes, 0.0);
+ _overall_max_accepted.resize(_classes, 0.0);
+
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls.resize(_classes);
+ _buffer_conflict_stalls.resize(_classes);
+ _buffer_full_stalls.resize(_classes);
+ _buffer_reserved_stalls.resize(_classes);
+ _crossbar_conflict_stalls.resize(_classes);
+ _overall_buffer_busy_stalls.resize(_classes, 0);
+ _overall_buffer_conflict_stalls.resize(_classes, 0);
+ _overall_buffer_full_stalls.resize(_classes, 0);
+ _overall_buffer_reserved_stalls.resize(_classes, 0);
+ _overall_crossbar_conflict_stalls.resize(_classes, 0);
+#endif
+
+ for ( int c = 0; c < _classes; ++c ) {
+ ostringstream tmp_name;
+
+ tmp_name << "plat_stat_" << c;
+ _plat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 );
+ _stats[tmp_name.str()] = _plat_stats[c];
+ tmp_name.str("");
+
+ tmp_name << "nlat_stat_" << c;
+ _nlat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 );
+ _stats[tmp_name.str()] = _nlat_stats[c];
+ tmp_name.str("");
+
+ tmp_name << "flat_stat_" << c;
+ _flat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 );
+ _stats[tmp_name.str()] = _flat_stats[c];
+ tmp_name.str("");
+
+ tmp_name << "frag_stat_" << c;
+ _frag_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 100 );
+ _stats[tmp_name.str()] = _frag_stats[c];
+ tmp_name.str("");
+
+ tmp_name << "hop_stat_" << c;
+ _hop_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 20 );
+ _stats[tmp_name.str()] = _hop_stats[c];
+ tmp_name.str("");
+
+ if(_pair_stats){
+ _pair_plat[c].resize(_nodes*_nodes);
+ _pair_nlat[c].resize(_nodes*_nodes);
+ _pair_flat[c].resize(_nodes*_nodes);
+ }
+
+ _sent_packets[c].resize(_nodes, 0);
+ _accepted_packets[c].resize(_nodes, 0);
+ _sent_flits[c].resize(_nodes, 0);
+ _accepted_flits[c].resize(_nodes, 0);
+
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls[c].resize(_subnets*_routers, 0);
+ _buffer_conflict_stalls[c].resize(_subnets*_routers, 0);
+ _buffer_full_stalls[c].resize(_subnets*_routers, 0);
+ _buffer_reserved_stalls[c].resize(_subnets*_routers, 0);
+ _crossbar_conflict_stalls[c].resize(_subnets*_routers, 0);
+#endif
+ if(_pair_stats){
+ for ( int i = 0; i < _nodes; ++i ) {
+ for ( int j = 0; j < _nodes; ++j ) {
+ tmp_name << "pair_plat_stat_" << c << "_" << i << "_" << j;
+ _pair_plat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 );
+ _stats[tmp_name.str()] = _pair_plat[c][i*_nodes+j];
+ tmp_name.str("");
+
+ tmp_name << "pair_nlat_stat_" << c << "_" << i << "_" << j;
+ _pair_nlat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 );
+ _stats[tmp_name.str()] = _pair_nlat[c][i*_nodes+j];
+ tmp_name.str("");
+
+ tmp_name << "pair_flat_stat_" << c << "_" << i << "_" << j;
+ _pair_flat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 );
+ _stats[tmp_name.str()] = _pair_flat[c][i*_nodes+j];
+ tmp_name.str("");
+ }
+ }
+ }
+ }
+
+ _slowest_flit.resize(_classes, -1);
+ _slowest_packet.resize(_classes, -1);
+
+
+
+}
+
+TrafficManager::~TrafficManager( )
+{
+
+ for ( int source = 0; source < _nodes; ++source ) {
+ for ( int subnet = 0; subnet < _subnets; ++subnet ) {
+ delete _buf_states[source][subnet];
+ }
+ }
+
+ for ( int c = 0; c < _classes; ++c ) {
+ delete _plat_stats[c];
+ delete _nlat_stats[c];
+ delete _flat_stats[c];
+ delete _frag_stats[c];
+ delete _hop_stats[c];
+
+ delete _traffic_pattern[c];
+ delete _injection_process[c];
+ if(_pair_stats){
+ for ( int i = 0; i < _nodes; ++i ) {
+ for ( int j = 0; j < _nodes; ++j ) {
+ delete _pair_plat[c][i*_nodes+j];
+ delete _pair_nlat[c][i*_nodes+j];
+ delete _pair_flat[c][i*_nodes+j];
+ }
+ }
+ }
+ }
+
+ if(gWatchOut && (gWatchOut != &cout)) delete gWatchOut;
+ if(_stats_out && (_stats_out != &cout)) delete _stats_out;
+
+#ifdef TRACK_FLOWS
+ if(_injected_flits_out) delete _injected_flits_out;
+ if(_received_flits_out) delete _received_flits_out;
+ if(_stored_flits_out) delete _stored_flits_out;
+ if(_sent_flits_out) delete _sent_flits_out;
+ if(_outstanding_credits_out) delete _outstanding_credits_out;
+ if(_ejected_flits_out) delete _ejected_flits_out;
+ if(_active_packets_out) delete _active_packets_out;
+#endif
+
+#ifdef TRACK_CREDITS
+ if(_used_credits_out) delete _used_credits_out;
+ if(_free_credits_out) delete _free_credits_out;
+ if(_max_credits_out) delete _max_credits_out;
+#endif
+
+ PacketReplyInfo::FreeAll();
+ Flit::FreeAll();
+ Credit::FreeAll();
+}
+
+
+void TrafficManager::_RetireFlit( Flit *f, int dest )
+{
+ _deadlock_timer = 0;
+
+ assert(_total_in_flight_flits[f->cl].count(f->id) > 0);
+ _total_in_flight_flits[f->cl].erase(f->id);
+
+ if(f->record) {
+ assert(_measured_in_flight_flits[f->cl].count(f->id) > 0);
+ _measured_in_flight_flits[f->cl].erase(f->id);
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << dest << " | "
+ << "Retiring flit " << f->id
+ << " (packet " << f->pid
+ << ", src = " << f->src
+ << ", dest = " << f->dest
+ << ", hops = " << f->hops
+ << ", flat = " << f->atime - f->itime
+ << ")." << endl;
+ }
+
+ if ( f->head && ( f->dest != dest ) ) {
+ ostringstream err;
+ err << "Flit " << f->id << " arrived at incorrect output " << dest;
+ Error( err.str( ) );
+ }
+
+ if((_slowest_flit[f->cl] < 0) ||
+ (_flat_stats[f->cl]->Max() < (f->atime - f->itime)))
+ _slowest_flit[f->cl] = f->id;
+ _flat_stats[f->cl]->AddSample( f->atime - f->itime);
+ if(_pair_stats){
+ _pair_flat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - f->itime );
+ }
+
+ if ( f->tail ) {
+ Flit * head;
+ if(f->head) {
+ head = f;
+ } else {
+ map<int, Flit *>::iterator iter = _retired_packets[f->cl].find(f->pid);
+ assert(iter != _retired_packets[f->cl].end());
+ head = iter->second;
+ _retired_packets[f->cl].erase(iter);
+ assert(head->head);
+ assert(f->pid == head->pid);
+ }
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << dest << " | "
+ << "Retiring packet " << f->pid
+ << " (plat = " << f->atime - head->ctime
+ << ", nlat = " << f->atime - head->itime
+ << ", frag = " << (f->atime - head->atime) - (f->id - head->id) // NB: In the spirit of solving problems using ugly hacks, we compute the packet length by taking advantage of the fact that the IDs of flits within a packet are contiguous.
+ << ", src = " << head->src
+ << ", dest = " << head->dest
+ << ")." << endl;
+ }
+
+ //code the source of request, look carefully, its tricky ;)
+ if (f->type == Flit::READ_REQUEST || f->type == Flit::WRITE_REQUEST) {
+ PacketReplyInfo* rinfo = PacketReplyInfo::New();
+ rinfo->source = f->src;
+ rinfo->time = f->atime;
+ rinfo->record = f->record;
+ rinfo->type = f->type;
+ _repliesPending[dest].push_back(rinfo);
+ } else {
+ if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){
+ _requestsOutstanding[dest]--;
+ } else if(f->type == Flit::ANY_TYPE) {
+ _requestsOutstanding[f->src]--;
+ }
+
+ }
+
+ // Only record statistics once per packet (at tail)
+ // and based on the simulation state
+ if ( ( _sim_state == warming_up ) || f->record ) {
+
+ _hop_stats[f->cl]->AddSample( f->hops );
+
+ if((_slowest_packet[f->cl] < 0) ||
+ (_plat_stats[f->cl]->Max() < (f->atime - head->itime)))
+ _slowest_packet[f->cl] = f->pid;
+ _plat_stats[f->cl]->AddSample( f->atime - head->ctime);
+ _nlat_stats[f->cl]->AddSample( f->atime - head->itime);
+ _frag_stats[f->cl]->AddSample( (f->atime - head->atime) - (f->id - head->id) );
+
+ if(_pair_stats){
+ _pair_plat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->ctime );
+ _pair_nlat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->itime );
+ }
+ }
+
+ if(f != head) {
+ head->Free();
+ }
+
+ }
+
+ if(f->head && !f->tail) {
+ _retired_packets[f->cl].insert(make_pair(f->pid, f));
+ } else {
+ f->Free();
+ }
+}
+
+int TrafficManager::_IssuePacket( int source, int cl )
+{
+ int result = 0;
+ if(_use_read_write[cl]){ //use read and write
+ //check queue for waiting replies.
+ //check to make sure it is on time yet
+ if (!_repliesPending[source].empty()) {
+ if(_repliesPending[source].front()->time <= _time) {
+ result = -1;
+ }
+ } else {
+
+ //produce a packet
+ if(_injection_process[cl]->test(source)) {
+
+ //coin toss to determine request type.
+ result = (RandomFloat() < _write_fraction[cl]) ? 2 : 1;
+
+ _requestsOutstanding[source]++;
+ }
+ }
+ } else { //normal mode
+ result = _injection_process[cl]->test(source) ? 1 : 0;
+ _requestsOutstanding[source]++;
+ }
+ if(result != 0) {
+ _packet_seq_no[source]++;
+ }
+ return result;
+}
+
+void TrafficManager::_GeneratePacket( int source, int stype,
+ int cl, int time )
+{
+ assert(stype!=0);
+
+ Flit::FlitType packet_type = Flit::ANY_TYPE;
+ int size = _GetNextPacketSize(cl); //input size
+ int pid = _cur_pid++;
+ assert(_cur_pid);
+ int packet_destination = _traffic_pattern[cl]->dest(source);
+ bool record = false;
+ bool watch = gWatchOut && (_packets_to_watch.count(pid) > 0);
+ if(_use_read_write[cl]){
+ if(stype > 0) {
+ if (stype == 1) {
+ packet_type = Flit::READ_REQUEST;
+ size = _read_request_size[cl];
+ } else if (stype == 2) {
+ packet_type = Flit::WRITE_REQUEST;
+ size = _write_request_size[cl];
+ } else {
+ ostringstream err;
+ err << "Invalid packet type: " << packet_type;
+ Error( err.str( ) );
+ }
+ } else {
+ PacketReplyInfo* rinfo = _repliesPending[source].front();
+ if (rinfo->type == Flit::READ_REQUEST) {//read reply
+ size = _read_reply_size[cl];
+ packet_type = Flit::READ_REPLY;
+ } else if(rinfo->type == Flit::WRITE_REQUEST) { //write reply
+ size = _write_reply_size[cl];
+ packet_type = Flit::WRITE_REPLY;
+ } else {
+ ostringstream err;
+ err << "Invalid packet type: " << rinfo->type;
+ Error( err.str( ) );
+ }
+ packet_destination = rinfo->source;
+ time = rinfo->time;
+ record = rinfo->record;
+ _repliesPending[source].pop_front();
+ rinfo->Free();
+ }
+ }
+
+ if ((packet_destination <0) || (packet_destination >= _nodes)) {
+ ostringstream err;
+ err << "Incorrect packet destination " << packet_destination
+ << " for stype " << packet_type;
+ Error( err.str( ) );
+ }
+
+ if ( ( _sim_state == running ) ||
+ ( ( _sim_state == draining ) && ( time < _drain_time ) ) ) {
+ record = _measure_stats[cl];
+ }
+
+ int subnetwork = ((packet_type == Flit::ANY_TYPE) ?
+ RandomInt(_subnets-1) :
+ _subnet[packet_type]);
+
+ if ( watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << source << " | "
+ << "Enqueuing packet " << pid
+ << " at time " << time
+ << "." << endl;
+ }
+
+ for ( int i = 0; i < size; ++i ) {
+ Flit * f = Flit::New();
+ f->id = _cur_id++;
+ assert(_cur_id);
+ f->pid = pid;
+ f->watch = watch | (gWatchOut && (_flits_to_watch.count(f->id) > 0));
+ f->subnetwork = subnetwork;
+ f->src = source;
+ f->ctime = time;
+ f->record = record;
+ f->cl = cl;
+
+ _total_in_flight_flits[f->cl].insert(make_pair(f->id, f));
+ if(record) {
+ _measured_in_flight_flits[f->cl].insert(make_pair(f->id, f));
+ }
+
+ if(gTrace){
+ cout<<"New Flit "<<f->src<<endl;
+ }
+ f->type = packet_type;
+
+ if ( i == 0 ) { // Head flit
+ f->head = true;
+ //packets are only generated to nodes smaller or equal to limit
+ f->dest = packet_destination;
+ } else {
+ f->head = false;
+ f->dest = -1;
+ }
+ switch( _pri_type ) {
+ case class_based:
+ f->pri = _class_priority[cl];
+ assert(f->pri >= 0);
+ break;
+ case age_based:
+ f->pri = numeric_limits<int>::max() - time;
+ assert(f->pri >= 0);
+ break;
+ case sequence_based:
+ f->pri = numeric_limits<int>::max() - _packet_seq_no[source];
+ assert(f->pri >= 0);
+ break;
+ default:
+ f->pri = 0;
+ }
+ if ( i == ( size - 1 ) ) { // Tail flit
+ f->tail = true;
+ } else {
+ f->tail = false;
+ }
+
+ f->vc = -1;
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << source << " | "
+ << "Enqueuing flit " << f->id
+ << " (packet " << f->pid
+ << ") at time " << time
+ << "." << endl;
+ }
+
+ _partial_packets[source][cl].push_back( f );
+ }
+}
+
+void TrafficManager::_Inject(){
+
+ for ( int input = 0; input < _nodes; ++input ) {
+ for ( int c = 0; c < _classes; ++c ) {
+ // Potentially generate packets for any (input,class)
+ // that is currently empty
+ if ( _partial_packets[input][c].empty() ) {
+ bool generated = false;
+ while( !generated && ( _qtime[input][c] <= _time ) ) {
+ int stype = _IssuePacket( input, c );
+
+ if ( stype != 0 ) { //generate a packet
+ _GeneratePacket( input, stype, c,
+ _include_queuing==1 ?
+ _qtime[input][c] : _time );
+ generated = true;
+ }
+ // only advance time if this is not a reply packet
+ if(!_use_read_write[c] || (stype >= 0)){
+ ++_qtime[input][c];
+ }
+ }
+
+ if ( ( _sim_state == draining ) &&
+ ( _qtime[input][c] > _drain_time ) ) {
+ _qdrained[input][c] = true;
+ }
+ }
+ }
+ }
+}
+
+void TrafficManager::_Step( )
+{
+ bool flits_in_flight = false;
+ for(int c = 0; c < _classes; ++c) {
+ flits_in_flight |= !_total_in_flight_flits[c].empty();
+ }
+ if(flits_in_flight && (_deadlock_timer++ >= _deadlock_warn_timeout)){
+ _deadlock_timer = 0;
+ cout << "WARNING: Possible network deadlock.\n";
+ }
+
+ vector<map<int, Flit *> > flits(_subnets);
+
+ for ( int subnet = 0; subnet < _subnets; ++subnet ) {
+ for ( int n = 0; n < _nodes; ++n ) {
+ Flit * const f = _net[subnet]->ReadFlit( n );
+ if ( f ) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Ejecting flit " << f->id
+ << " (packet " << f->pid << ")"
+ << " from VC " << f->vc
+ << "." << endl;
+ }
+ flits[subnet].insert(make_pair(n, f));
+ if((_sim_state == warming_up) || (_sim_state == running)) {
+ ++_accepted_flits[f->cl][n];
+ if(f->tail) {
+ ++_accepted_packets[f->cl][n];
+ }
+ }
+ }
+
+ Credit * const c = _net[subnet]->ReadCredit( n );
+ if ( c ) {
+#ifdef TRACK_FLOWS
+ for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) {
+ int const vc = *iter;
+ assert(!_outstanding_classes[n][subnet][vc].empty());
+ int cl = _outstanding_classes[n][subnet][vc].front();
+ _outstanding_classes[n][subnet][vc].pop();
+ assert(_outstanding_credits[cl][subnet][n] > 0);
+ --_outstanding_credits[cl][subnet][n];
+ }
+#endif
+ _buf_states[n][subnet]->ProcessCredit(c);
+ c->Free();
+ }
+ }
+ _net[subnet]->ReadInputs( );
+ }
+
+ if ( !_empty_network ) {
+ _Inject();
+ }
+
+ for(int subnet = 0; subnet < _subnets; ++subnet) {
+
+ for(int n = 0; n < _nodes; ++n) {
+
+ Flit * f = NULL;
+
+ BufferState * const dest_buf = _buf_states[n][subnet];
+
+ int const last_class = _last_class[n][subnet];
+
+ int class_limit = _classes;
+
+ if(_hold_switch_for_packet) {
+ list<Flit *> const & pp = _partial_packets[n][last_class];
+ if(!pp.empty() && !pp.front()->head &&
+ !dest_buf->IsFullFor(pp.front()->vc)) {
+ f = pp.front();
+ assert(f->vc == _last_vc[n][subnet][last_class]);
+
+ // if we're holding the connection, we don't need to check that class
+ // again in the for loop
+ --class_limit;
+ }
+ }
+
+ for(int i = 1; i <= class_limit; ++i) {
+
+ int const c = (last_class + i) % _classes;
+
+ list<Flit *> const & pp = _partial_packets[n][c];
+
+ if(pp.empty()) {
+ continue;
+ }
+
+ Flit * const cf = pp.front();
+ assert(cf);
+ assert(cf->cl == c);
+
+ if(cf->subnetwork != subnet) {
+ continue;
+ }
+
+ if(f && (f->pri >= cf->pri)) {
+ continue;
+ }
+
+ if(cf->head && cf->vc == -1) { // Find first available VC
+
+ OutputSet route_set;
+ _rf(NULL, cf, -1, &route_set, true);
+ set<OutputSet::sSetElement> const & os = route_set.GetSet();
+ assert(os.size() == 1);
+ OutputSet::sSetElement const & se = *os.begin();
+ assert(se.output_port == -1);
+ int vc_start = se.vc_start;
+ int vc_end = se.vc_end;
+ int vc_count = vc_end - vc_start + 1;
+ if(_noq) {
+ assert(_lookahead_routing);
+ const FlitChannel * inject = _net[subnet]->GetInject(n);
+ const Router * router = inject->GetSink();
+ assert(router);
+ int in_channel = inject->GetSinkPort();
+
+ // NOTE: Because the lookahead is not for injection, but for the
+ // first hop, we have to temporarily set cf's VC to be non-negative
+ // in order to avoid seting of an assertion in the routing function.
+ cf->vc = vc_start;
+ _rf(router, cf, in_channel, &cf->la_route_set, false);
+ cf->vc = -1;
+
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Generating lookahead routing info for flit " << cf->id
+ << " (NOQ)." << endl;
+ }
+ set<OutputSet::sSetElement> const sl = cf->la_route_set.GetSet();
+ assert(sl.size() == 1);
+ int next_output = sl.begin()->output_port;
+ vc_count /= router->NumOutputs();
+ vc_start += next_output * vc_count;
+ vc_end = vc_start + vc_count - 1;
+ assert(vc_start >= se.vc_start && vc_start <= se.vc_end);
+ assert(vc_end >= se.vc_start && vc_end <= se.vc_end);
+ assert(vc_start <= vc_end);
+ }
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Finding output VC for flit " << cf->id
+ << ":" << endl;
+ }
+ for(int i = 1; i <= vc_count; ++i) {
+ int const lvc = _last_vc[n][subnet][c];
+ int const vc =
+ (lvc < vc_start || lvc > vc_end) ?
+ vc_start :
+ (vc_start + (lvc - vc_start + i) % vc_count);
+ assert((vc >= vc_start) && (vc <= vc_end));
+ if(!dest_buf->IsAvailableFor(vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output VC " << vc << " is busy." << endl;
+ }
+ } else {
+ if(dest_buf->IsFullFor(vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output VC " << vc << " is full." << endl;
+ }
+ } else {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Selected output VC " << vc << "." << endl;
+ }
+ cf->vc = vc;
+ break;
+ }
+ }
+ }
+ }
+
+ if(cf->vc == -1) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "No output VC found for flit " << cf->id
+ << "." << endl;
+ }
+ } else {
+ if(dest_buf->IsFullFor(cf->vc)) {
+ if(cf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Selected output VC " << cf->vc
+ << " is full for flit " << cf->id
+ << "." << endl;
+ }
+ } else {
+ f = cf;
+ }
+ }
+ }
+
+ if(f) {
+
+ assert(f->subnetwork == subnet);
+
+ int const c = f->cl;
+
+ if(f->head) {
+
+ if (_lookahead_routing) {
+ if(!_noq) {
+ const FlitChannel * inject = _net[subnet]->GetInject(n);
+ const Router * router = inject->GetSink();
+ assert(router);
+ int in_channel = inject->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Generating lookahead routing info for flit " << f->id
+ << "." << endl;
+ }
+ } else if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Already generated lookahead routing info for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+
+ dest_buf->TakeBuffer(f->vc);
+ _last_vc[n][subnet][c] = f->vc;
+ }
+
+ _last_class[n][subnet] = c;
+
+ _partial_packets[n][c].pop_front();
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[c][subnet][n];
+ _outstanding_classes[n][subnet][f->vc].push(c);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ if(_pri_type == network_age_based) {
+ f->pri = numeric_limits<int>::max() - _time;
+ assert(f->pri >= 0);
+ }
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Injecting flit " << f->id
+ << " into subnet " << subnet
+ << " at time " << _time
+ << " with priority " << f->pri
+ << "." << endl;
+ }
+ f->itime = _time;
+
+ // Pass VC "back"
+ if(!_partial_packets[n][c].empty() && !f->tail) {
+ Flit * const nf = _partial_packets[n][c].front();
+ nf->vc = f->vc;
+ }
+
+ if((_sim_state == warming_up) || (_sim_state == running)) {
+ ++_sent_flits[c][n];
+ if(f->head) {
+ ++_sent_packets[c][n];
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_injected_flits[c][n];
+#endif
+
+ _net[subnet]->WriteFlit(f, n);
+
+ }
+ }
+ }
+
+ for(int subnet = 0; subnet < _subnets; ++subnet) {
+ for(int n = 0; n < _nodes; ++n) {
+ map<int, Flit *>::const_iterator iter = flits[subnet].find(n);
+ if(iter != flits[subnet].end()) {
+ Flit * const f = iter->second;
+
+ f->atime = _time;
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | "
+ << "node" << n << " | "
+ << "Injecting credit for VC " << f->vc
+ << " into subnet " << subnet
+ << "." << endl;
+ }
+ Credit * const c = Credit::New();
+ c->vc.insert(f->vc);
+ _net[subnet]->WriteCredit(c, n);
+
+#ifdef TRACK_FLOWS
+ ++_ejected_flits[f->cl][n];
+#endif
+
+ _RetireFlit(f, n);
+ }
+ }
+ flits[subnet].clear();
+ _net[subnet]->Evaluate( );
+ _net[subnet]->WriteOutputs( );
+ }
+
+ ++_time;
+ assert(_time);
+ if(gTrace){
+ cout<<"TIME "<<_time<<endl;
+ }
+
+}
+
+bool TrafficManager::_PacketsOutstanding( ) const
+{
+ for ( int c = 0; c < _classes; ++c ) {
+ if ( _measure_stats[c] ) {
+ if ( _measured_in_flight_flits[c].empty() ) {
+
+ for ( int s = 0; s < _nodes; ++s ) {
+ if ( !_qdrained[s][c] ) {
+#ifdef DEBUG_DRAIN
+ cout << "waiting on queue " << s << " class " << c;
+ cout << ", time = " << _time << " qtime = " << _qtime[s][c] << endl;
+#endif
+ return true;
+ }
+ }
+ } else {
+#ifdef DEBUG_DRAIN
+ cout << "in flight = " << _measured_in_flight_flits[c].size() << endl;
+#endif
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void TrafficManager::_ClearStats( )
+{
+ _slowest_flit.assign(_classes, -1);
+ _slowest_packet.assign(_classes, -1);
+
+ for ( int c = 0; c < _classes; ++c ) {
+
+ _plat_stats[c]->Clear( );
+ _nlat_stats[c]->Clear( );
+ _flat_stats[c]->Clear( );
+
+ _frag_stats[c]->Clear( );
+
+ _sent_packets[c].assign(_nodes, 0);
+ _accepted_packets[c].assign(_nodes, 0);
+ _sent_flits[c].assign(_nodes, 0);
+ _accepted_flits[c].assign(_nodes, 0);
+
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls[c].assign(_subnets*_routers, 0);
+ _buffer_conflict_stalls[c].assign(_subnets*_routers, 0);
+ _buffer_full_stalls[c].assign(_subnets*_routers, 0);
+ _buffer_reserved_stalls[c].assign(_subnets*_routers, 0);
+ _crossbar_conflict_stalls[c].assign(_subnets*_routers, 0);
+#endif
+ if(_pair_stats){
+ for ( int i = 0; i < _nodes; ++i ) {
+ for ( int j = 0; j < _nodes; ++j ) {
+ _pair_plat[c][i*_nodes+j]->Clear( );
+ _pair_nlat[c][i*_nodes+j]->Clear( );
+ _pair_flat[c][i*_nodes+j]->Clear( );
+ }
+ }
+ }
+ _hop_stats[c]->Clear();
+
+ }
+
+ _reset_time = _time;
+}
+
+void TrafficManager::_ComputeStats( const vector<int> & stats, int *sum, int *min, int *max, int *min_pos, int *max_pos ) const
+{
+ int const count = stats.size();
+ assert(count > 0);
+
+ if(min_pos) {
+ *min_pos = 0;
+ }
+ if(max_pos) {
+ *max_pos = 0;
+ }
+
+ if(min) {
+ *min = stats[0];
+ }
+ if(max) {
+ *max = stats[0];
+ }
+
+ *sum = stats[0];
+
+ for ( int i = 1; i < count; ++i ) {
+ int curr = stats[i];
+ if ( min && ( curr < *min ) ) {
+ *min = curr;
+ if ( min_pos ) {
+ *min_pos = i;
+ }
+ }
+ if ( max && ( curr > *max ) ) {
+ *max = curr;
+ if ( max_pos ) {
+ *max_pos = i;
+ }
+ }
+ *sum += curr;
+ }
+}
+
+void TrafficManager::_DisplayRemaining( ostream & os ) const
+{
+ for(int c = 0; c < _classes; ++c) {
+
+ map<int, Flit *>::const_iterator iter;
+ int i;
+
+ os << "Class " << c << ":" << endl;
+
+ os << "Remaining flits: ";
+ for ( iter = _total_in_flight_flits[c].begin( ), i = 0;
+ ( iter != _total_in_flight_flits[c].end( ) ) && ( i < 10 );
+ iter++, i++ ) {
+ os << iter->first << " ";
+ }
+ if(_total_in_flight_flits[c].size() > 10)
+ os << "[...] ";
+
+ os << "(" << _total_in_flight_flits[c].size() << " flits)" << endl;
+
+ os << "Measured flits: ";
+ for ( iter = _measured_in_flight_flits[c].begin( ), i = 0;
+ ( iter != _measured_in_flight_flits[c].end( ) ) && ( i < 10 );
+ iter++, i++ ) {
+ os << iter->first << " ";
+ }
+ if(_measured_in_flight_flits[c].size() > 10)
+ os << "[...] ";
+
+ os << "(" << _measured_in_flight_flits[c].size() << " flits)" << endl;
+
+ }
+}
+
+bool TrafficManager::_SingleSim( )
+{
+ int converged = 0;
+
+ //once warmed up, we require 3 converging runs to end the simulation
+ vector<double> prev_latency(_classes, 0.0);
+ vector<double> prev_accepted(_classes, 0.0);
+ bool clear_last = false;
+ int total_phases = 0;
+ while( ( total_phases < _max_samples ) &&
+ ( ( _sim_state != running ) ||
+ ( converged < 3 ) ) ) {
+
+ if ( clear_last || (( ( _sim_state == warming_up ) && ( ( total_phases % 2 ) == 0 ) )) ) {
+ clear_last = false;
+ _ClearStats( );
+ }
+
+
+ for ( int iter = 0; iter < _sample_period; ++iter )
+ _Step( );
+
+ //cout << _sim_state << endl;
+
+ UpdateStats();
+ DisplayStats();
+
+ int lat_exc_class = -1;
+ int lat_chg_exc_class = -1;
+ int acc_chg_exc_class = -1;
+
+ for(int c = 0; c < _classes; ++c) {
+
+ if(_measure_stats[c] == 0) {
+ continue;
+ }
+
+ double cur_latency = _plat_stats[c]->Average( );
+
+ int total_accepted_count;
+ _ComputeStats( _accepted_flits[c], &total_accepted_count );
+ double total_accepted_rate = (double)total_accepted_count / (double)(_time - _reset_time);
+ double cur_accepted = total_accepted_rate / (double)_nodes;
+
+ double latency_change = fabs((cur_latency - prev_latency[c]) / cur_latency);
+ prev_latency[c] = cur_latency;
+
+ double accepted_change = fabs((cur_accepted - prev_accepted[c]) / cur_accepted);
+ prev_accepted[c] = cur_accepted;
+
+ double latency = (double)_plat_stats[c]->Sum();
+ double count = (double)_plat_stats[c]->NumSamples();
+
+ map<int, Flit *>::const_iterator iter;
+ for(iter = _total_in_flight_flits[c].begin();
+ iter != _total_in_flight_flits[c].end();
+ iter++) {
+ latency += (double)(_time - iter->second->ctime);
+ count++;
+ }
+
+ if((lat_exc_class < 0) &&
+ (_latency_thres[c] >= 0.0) &&
+ ((latency / count) > _latency_thres[c])) {
+ lat_exc_class = c;
+ }
+
+ cout << "latency change = " << latency_change << endl;
+ if(lat_chg_exc_class < 0) {
+ if((_sim_state == warming_up) &&
+ (_warmup_threshold[c] >= 0.0) &&
+ (latency_change > _warmup_threshold[c])) {
+ lat_chg_exc_class = c;
+ } else if((_sim_state == running) &&
+ (_stopping_threshold[c] >= 0.0) &&
+ (latency_change > _stopping_threshold[c])) {
+ lat_chg_exc_class = c;
+ }
+ }
+
+ cout << "throughput change = " << accepted_change << endl;
+ if(acc_chg_exc_class < 0) {
+ if((_sim_state == warming_up) &&
+ (_acc_warmup_threshold[c] >= 0.0) &&
+ (accepted_change > _acc_warmup_threshold[c])) {
+ acc_chg_exc_class = c;
+ } else if((_sim_state == running) &&
+ (_acc_stopping_threshold[c] >= 0.0) &&
+ (accepted_change > _acc_stopping_threshold[c])) {
+ acc_chg_exc_class = c;
+ }
+ }
+
+ }
+
+ // Fail safe for latency mode, throughput will ust continue
+ if ( _measure_latency && ( lat_exc_class >= 0 ) ) {
+
+ cout << "Average latency for class " << lat_exc_class << " exceeded " << _latency_thres[lat_exc_class] << " cycles. Aborting simulation." << endl;
+ converged = 0;
+ _sim_state = draining;
+ _drain_time = _time;
+ if(_stats_out) {
+ WriteStats(*_stats_out);
+ }
+ break;
+
+ }
+
+ if ( _sim_state == warming_up ) {
+ if ( ( _warmup_periods > 0 ) ?
+ ( total_phases + 1 >= _warmup_periods ) :
+ ( ( !_measure_latency || ( lat_chg_exc_class < 0 ) ) &&
+ ( acc_chg_exc_class < 0 ) ) ) {
+ cout << "Warmed up ..." << "Time used is " << _time << " cycles" <<endl;
+ clear_last = true;
+ _sim_state = running;
+ }
+ } else if(_sim_state == running) {
+ if ( ( !_measure_latency || ( lat_chg_exc_class < 0 ) ) &&
+ ( acc_chg_exc_class < 0 ) ) {
+ ++converged;
+ } else {
+ converged = 0;
+ }
+ }
+ ++total_phases;
+ }
+
+ if ( _sim_state == running ) {
+ ++converged;
+
+ _sim_state = draining;
+ _drain_time = _time;
+
+ if ( _measure_latency ) {
+ cout << "Draining all recorded packets ..." << endl;
+ int empty_steps = 0;
+ while( _PacketsOutstanding( ) ) {
+ _Step( );
+
+ ++empty_steps;
+
+ if ( empty_steps % 1000 == 0 ) {
+
+ int lat_exc_class = -1;
+
+ for(int c = 0; c < _classes; c++) {
+
+ double threshold = _latency_thres[c];
+
+ if(threshold < 0.0) {
+ continue;
+ }
+
+ double acc_latency = _plat_stats[c]->Sum();
+ double acc_count = (double)_plat_stats[c]->NumSamples();
+
+ map<int, Flit *>::const_iterator iter;
+ for(iter = _total_in_flight_flits[c].begin();
+ iter != _total_in_flight_flits[c].end();
+ iter++) {
+ acc_latency += (double)(_time - iter->second->ctime);
+ acc_count++;
+ }
+
+ if((acc_latency / acc_count) > threshold) {
+ lat_exc_class = c;
+ break;
+ }
+ }
+
+ if(lat_exc_class >= 0) {
+ cout << "Average latency for class " << lat_exc_class << " exceeded " << _latency_thres[lat_exc_class] << " cycles. Aborting simulation." << endl;
+ converged = 0;
+ _sim_state = warming_up;
+ if(_stats_out) {
+ WriteStats(*_stats_out);
+ }
+ break;
+ }
+
+ _DisplayRemaining( );
+
+ }
+ }
+ }
+ } else {
+ cout << "Too many sample periods needed to converge" << endl;
+ }
+
+ return ( converged > 0 );
+}
+
+bool TrafficManager::Run( )
+{
+ for ( int sim = 0; sim < _total_sims; ++sim ) {
+
+ _time = 0;
+
+ //remove any pending request from the previous simulations
+ _requestsOutstanding.assign(_nodes, 0);
+ for (int i=0;i<_nodes;i++) {
+ while(!_repliesPending[i].empty()) {
+ _repliesPending[i].front()->Free();
+ _repliesPending[i].pop_front();
+ }
+ }
+
+ //reset queuetime for all sources
+ for ( int s = 0; s < _nodes; ++s ) {
+ _qtime[s].assign(_classes, 0);
+ _qdrained[s].assign(_classes, false);
+ }
+
+ // warm-up ...
+ // reset stats, all packets after warmup_time marked
+ // converge
+ // draing, wait until all packets finish
+ _sim_state = warming_up;
+
+ _ClearStats( );
+
+ for(int c = 0; c < _classes; ++c) {
+ _traffic_pattern[c]->reset();
+ _injection_process[c]->reset();
+ }
+
+ if ( !_SingleSim( ) ) {
+ cout << "Simulation unstable, ending ..." << endl;
+ return false;
+ }
+
+ // Empty any remaining packets
+ cout << "Draining remaining packets ..." << endl;
+ _empty_network = true;
+ int empty_steps = 0;
+
+ bool packets_left = false;
+ for(int c = 0; c < _classes; ++c) {
+ packets_left |= !_total_in_flight_flits[c].empty();
+ }
+
+ while( packets_left ) {
+ _Step( );
+
+ ++empty_steps;
+
+ if ( empty_steps % 1000 == 0 ) {
+ _DisplayRemaining( );
+ }
+
+ packets_left = false;
+ for(int c = 0; c < _classes; ++c) {
+ packets_left |= !_total_in_flight_flits[c].empty();
+ }
+ }
+ //wait until all the credits are drained as well
+ while(Credit::OutStanding()!=0){
+ _Step();
+ }
+ _empty_network = false;
+
+ //for the love of god don't ever say "Time taken" anywhere else
+ //the power script depend on it
+ cout << "Time taken is " << _time << " cycles" <<endl;
+
+ if(_stats_out) {
+ WriteStats(*_stats_out);
+ }
+ _UpdateOverallStats();
+ }
+
+ DisplayOverallStats();
+ if(_print_csv_results) {
+ DisplayOverallStatsCSV();
+ }
+
+ return true;
+}
+
+void TrafficManager::_UpdateOverallStats() {
+ for ( int c = 0; c < _classes; ++c ) {
+
+ if(_measure_stats[c] == 0) {
+ continue;
+ }
+
+ _overall_min_plat[c] += _plat_stats[c]->Min();
+ _overall_avg_plat[c] += _plat_stats[c]->Average();
+ _overall_max_plat[c] += _plat_stats[c]->Max();
+ _overall_min_nlat[c] += _nlat_stats[c]->Min();
+ _overall_avg_nlat[c] += _nlat_stats[c]->Average();
+ _overall_max_nlat[c] += _nlat_stats[c]->Max();
+ _overall_min_flat[c] += _flat_stats[c]->Min();
+ _overall_avg_flat[c] += _flat_stats[c]->Average();
+ _overall_max_flat[c] += _flat_stats[c]->Max();
+
+ _overall_min_frag[c] += _frag_stats[c]->Min();
+ _overall_avg_frag[c] += _frag_stats[c]->Average();
+ _overall_max_frag[c] += _frag_stats[c]->Max();
+
+ _overall_hop_stats[c] += _hop_stats[c]->Average();
+
+ int count_min, count_sum, count_max;
+ double rate_min, rate_sum, rate_max;
+ double rate_avg;
+ double time_delta = (double)(_drain_time - _reset_time);
+ _ComputeStats( _sent_flits[c], &count_sum, &count_min, &count_max );
+ rate_min = (double)count_min / time_delta;
+ rate_sum = (double)count_sum / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ _overall_min_sent[c] += rate_min;
+ _overall_avg_sent[c] += rate_avg;
+ _overall_max_sent[c] += rate_max;
+ _ComputeStats( _sent_packets[c], &count_sum, &count_min, &count_max );
+ rate_min = (double)count_min / time_delta;
+ rate_sum = (double)count_sum / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ _overall_min_sent_packets[c] += rate_min;
+ _overall_avg_sent_packets[c] += rate_avg;
+ _overall_max_sent_packets[c] += rate_max;
+ _ComputeStats( _accepted_flits[c], &count_sum, &count_min, &count_max );
+ rate_min = (double)count_min / time_delta;
+ rate_sum = (double)count_sum / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ _overall_min_accepted[c] += rate_min;
+ _overall_avg_accepted[c] += rate_avg;
+ _overall_max_accepted[c] += rate_max;
+ _ComputeStats( _accepted_packets[c], &count_sum, &count_min, &count_max );
+ rate_min = (double)count_min / time_delta;
+ rate_sum = (double)count_sum / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ _overall_min_accepted_packets[c] += rate_min;
+ _overall_avg_accepted_packets[c] += rate_avg;
+ _overall_max_accepted_packets[c] += rate_max;
+
+#ifdef TRACK_STALLS
+ _ComputeStats(_buffer_busy_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ _overall_buffer_busy_stalls[c] += rate_avg;
+ _ComputeStats(_buffer_conflict_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ _overall_buffer_conflict_stalls[c] += rate_avg;
+ _ComputeStats(_buffer_full_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ _overall_buffer_full_stalls[c] += rate_avg;
+ _ComputeStats(_buffer_reserved_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ _overall_buffer_reserved_stalls[c] += rate_avg;
+ _ComputeStats(_crossbar_conflict_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ _overall_crossbar_conflict_stalls[c] += rate_avg;
+#endif
+
+ }
+}
+
+void TrafficManager::WriteStats(ostream & os) const {
+
+ os << "%=================================" << endl;
+
+ for(int c = 0; c < _classes; ++c) {
+
+ if(_measure_stats[c] == 0) {
+ continue;
+ }
+
+ //c+1 due to matlab array starting at 1
+ os << "plat(" << c+1 << ") = " << _plat_stats[c]->Average() << ";" << endl
+ << "plat_hist(" << c+1 << ",:) = " << *_plat_stats[c] << ";" << endl
+ << "nlat(" << c+1 << ") = " << _nlat_stats[c]->Average() << ";" << endl
+ << "nlat_hist(" << c+1 << ",:) = " << *_nlat_stats[c] << ";" << endl
+ << "flat(" << c+1 << ") = " << _flat_stats[c]->Average() << ";" << endl
+ << "flat_hist(" << c+1 << ",:) = " << *_flat_stats[c] << ";" << endl
+ << "frag_hist(" << c+1 << ",:) = " << *_frag_stats[c] << ";" << endl
+ << "hops(" << c+1 << ",:) = " << *_hop_stats[c] << ";" << endl;
+ if(_pair_stats){
+ os<< "pair_sent(" << c+1 << ",:) = [ ";
+ for(int i = 0; i < _nodes; ++i) {
+ for(int j = 0; j < _nodes; ++j) {
+ os << _pair_plat[c][i*_nodes+j]->NumSamples() << " ";
+ }
+ }
+ os << "];" << endl
+ << "pair_plat(" << c+1 << ",:) = [ ";
+ for(int i = 0; i < _nodes; ++i) {
+ for(int j = 0; j < _nodes; ++j) {
+ os << _pair_plat[c][i*_nodes+j]->Average( ) << " ";
+ }
+ }
+ os << "];" << endl
+ << "pair_nlat(" << c+1 << ",:) = [ ";
+ for(int i = 0; i < _nodes; ++i) {
+ for(int j = 0; j < _nodes; ++j) {
+ os << _pair_nlat[c][i*_nodes+j]->Average( ) << " ";
+ }
+ }
+ os << "];" << endl
+ << "pair_flat(" << c+1 << ",:) = [ ";
+ for(int i = 0; i < _nodes; ++i) {
+ for(int j = 0; j < _nodes; ++j) {
+ os << _pair_flat[c][i*_nodes+j]->Average( ) << " ";
+ }
+ }
+ }
+
+ double time_delta = (double)(_drain_time - _reset_time);
+
+ os << "];" << endl
+ << "sent_packets(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_sent_packets[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "accepted_packets(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_accepted_packets[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "sent_flits(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_sent_flits[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "accepted_flits(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_accepted_flits[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "sent_packet_size(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_sent_flits[c][d] / (double)_sent_packets[c][d] << " ";
+ }
+ os << "];" << endl
+ << "accepted_packet_size(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _nodes; ++d ) {
+ os << (double)_accepted_flits[c][d] / (double)_accepted_packets[c][d] << " ";
+ }
+ os << "];" << endl;
+#ifdef TRACK_STALLS
+ os << "buffer_busy_stalls(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _subnets*_routers; ++d ) {
+ os << (double)_buffer_busy_stalls[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "buffer_conflict_stalls(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _subnets*_routers; ++d ) {
+ os << (double)_buffer_conflict_stalls[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "buffer_full_stalls(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _subnets*_routers; ++d ) {
+ os << (double)_buffer_full_stalls[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "buffer_reserved_stalls(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _subnets*_routers; ++d ) {
+ os << (double)_buffer_reserved_stalls[c][d] / time_delta << " ";
+ }
+ os << "];" << endl
+ << "crossbar_conflict_stalls(" << c+1 << ",:) = [ ";
+ for ( int d = 0; d < _subnets*_routers; ++d ) {
+ os << (double)_crossbar_conflict_stalls[c][d] / time_delta << " ";
+ }
+ os << "];" << endl;
+#endif
+ }
+}
+
+void TrafficManager::UpdateStats() {
+#if defined(TRACK_FLOWS) || defined(TRACK_STALLS)
+ for(int c = 0; c < _classes; ++c) {
+#ifdef TRACK_FLOWS
+ {
+ char trail_char = (c == _classes - 1) ? '\n' : ',';
+ if(_injected_flits_out) *_injected_flits_out << _injected_flits[c] << trail_char;
+ _injected_flits[c].assign(_nodes, 0);
+ if(_ejected_flits_out) *_ejected_flits_out << _ejected_flits[c] << trail_char;
+ _ejected_flits[c].assign(_nodes, 0);
+ }
+#endif
+ for(int subnet = 0; subnet < _subnets; ++subnet) {
+#ifdef TRACK_FLOWS
+ if(_outstanding_credits_out) *_outstanding_credits_out << _outstanding_credits[c][subnet] << ',';
+ if(_stored_flits_out) *_stored_flits_out << vector<int>(_nodes, 0) << ',';
+#endif
+ for(int router = 0; router < _routers; ++router) {
+ Router * const r = _router[subnet][router];
+#ifdef TRACK_FLOWS
+ char trail_char =
+ ((router == _routers - 1) && (subnet == _subnets - 1) && (c == _classes - 1)) ? '\n' : ',';
+ if(_received_flits_out) *_received_flits_out << r->GetReceivedFlits(c) << trail_char;
+ if(_stored_flits_out) *_stored_flits_out << r->GetStoredFlits(c) << trail_char;
+ if(_sent_flits_out) *_sent_flits_out << r->GetSentFlits(c) << trail_char;
+ if(_outstanding_credits_out) *_outstanding_credits_out << r->GetOutstandingCredits(c) << trail_char;
+ if(_active_packets_out) *_active_packets_out << r->GetActivePackets(c) << trail_char;
+ r->ResetFlowStats(c);
+#endif
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls[c][subnet*_routers+router] += r->GetBufferBusyStalls(c);
+ _buffer_conflict_stalls[c][subnet*_routers+router] += r->GetBufferConflictStalls(c);
+ _buffer_full_stalls[c][subnet*_routers+router] += r->GetBufferFullStalls(c);
+ _buffer_reserved_stalls[c][subnet*_routers+router] += r->GetBufferReservedStalls(c);
+ _crossbar_conflict_stalls[c][subnet*_routers+router] += r->GetCrossbarConflictStalls(c);
+ r->ResetStallStats(c);
+#endif
+ }
+ }
+ }
+#ifdef TRACK_FLOWS
+ if(_injected_flits_out) *_injected_flits_out << flush;
+ if(_received_flits_out) *_received_flits_out << flush;
+ if(_stored_flits_out) *_stored_flits_out << flush;
+ if(_sent_flits_out) *_sent_flits_out << flush;
+ if(_outstanding_credits_out) *_outstanding_credits_out << flush;
+ if(_ejected_flits_out) *_ejected_flits_out << flush;
+ if(_active_packets_out) *_active_packets_out << flush;
+#endif
+#endif
+
+#ifdef TRACK_CREDITS
+ for(int s = 0; s < _subnets; ++s) {
+ for(int n = 0; n < _nodes; ++n) {
+ BufferState const * const bs = _buf_states[n][s];
+ for(int v = 0; v < _vcs; ++v) {
+ if(_used_credits_out) *_used_credits_out << bs->OccupancyFor(v) << ',';
+ if(_free_credits_out) *_free_credits_out << bs->AvailableFor(v) << ',';
+ if(_max_credits_out) *_max_credits_out << bs->LimitFor(v) << ',';
+ }
+ }
+ for(int r = 0; r < _routers; ++r) {
+ Router const * const rtr = _router[s][r];
+ char trail_char =
+ ((r == _routers - 1) && (s == _subnets - 1)) ? '\n' : ',';
+ if(_used_credits_out) *_used_credits_out << rtr->UsedCredits() << trail_char;
+ if(_free_credits_out) *_free_credits_out << rtr->FreeCredits() << trail_char;
+ if(_max_credits_out) *_max_credits_out << rtr->MaxCredits() << trail_char;
+ }
+ }
+ if(_used_credits_out) *_used_credits_out << flush;
+ if(_free_credits_out) *_free_credits_out << flush;
+ if(_max_credits_out) *_max_credits_out << flush;
+#endif
+
+}
+
+void TrafficManager::DisplayStats(ostream & os) const {
+
+ for(int c = 0; c < _classes; ++c) {
+
+ if(_measure_stats[c] == 0) {
+ continue;
+ }
+
+ cout << "Class " << c << ":" << endl;
+
+ cout
+ << "Packet latency average = " << _plat_stats[c]->Average() << endl
+ << "\tminimum = " << _plat_stats[c]->Min() << endl
+ << "\tmaximum = " << _plat_stats[c]->Max() << endl
+ << "Network latency average = " << _nlat_stats[c]->Average() << endl
+ << "\tminimum = " << _nlat_stats[c]->Min() << endl
+ << "\tmaximum = " << _nlat_stats[c]->Max() << endl
+ << "Slowest packet = " << _slowest_packet[c] << endl
+ << "Flit latency average = " << _flat_stats[c]->Average() << endl
+ << "\tminimum = " << _flat_stats[c]->Min() << endl
+ << "\tmaximum = " << _flat_stats[c]->Max() << endl
+ << "Slowest flit = " << _slowest_flit[c] << endl
+ << "Fragmentation average = " << _frag_stats[c]->Average() << endl
+ << "\tminimum = " << _frag_stats[c]->Min() << endl
+ << "\tmaximum = " << _frag_stats[c]->Max() << endl;
+
+ int count_sum, count_min, count_max;
+ double rate_sum, rate_min, rate_max;
+ double rate_avg;
+ int sent_packets, sent_flits, accepted_packets, accepted_flits;
+ int min_pos, max_pos;
+ double time_delta = (double)(_time - _reset_time);
+ _ComputeStats(_sent_packets[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos);
+ rate_sum = (double)count_sum / time_delta;
+ rate_min = (double)count_min / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ sent_packets = count_sum;
+ cout << "Injected packet rate average = " << rate_avg << endl
+ << "\tminimum = " << rate_min
+ << " (at node " << min_pos << ")" << endl
+ << "\tmaximum = " << rate_max
+ << " (at node " << max_pos << ")" << endl;
+ _ComputeStats(_accepted_packets[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos);
+ rate_sum = (double)count_sum / time_delta;
+ rate_min = (double)count_min / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ accepted_packets = count_sum;
+ cout << "Accepted packet rate average = " << rate_avg << endl
+ << "\tminimum = " << rate_min
+ << " (at node " << min_pos << ")" << endl
+ << "\tmaximum = " << rate_max
+ << " (at node " << max_pos << ")" << endl;
+ _ComputeStats(_sent_flits[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos);
+ rate_sum = (double)count_sum / time_delta;
+ rate_min = (double)count_min / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ sent_flits = count_sum;
+ cout << "Injected flit rate average = " << rate_avg << endl
+ << "\tminimum = " << rate_min
+ << " (at node " << min_pos << ")" << endl
+ << "\tmaximum = " << rate_max
+ << " (at node " << max_pos << ")" << endl;
+ _ComputeStats(_accepted_flits[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos);
+ rate_sum = (double)count_sum / time_delta;
+ rate_min = (double)count_min / time_delta;
+ rate_max = (double)count_max / time_delta;
+ rate_avg = rate_sum / (double)_nodes;
+ accepted_flits = count_sum;
+ cout << "Accepted flit rate average= " << rate_avg << endl
+ << "\tminimum = " << rate_min
+ << " (at node " << min_pos << ")" << endl
+ << "\tmaximum = " << rate_max
+ << " (at node " << max_pos << ")" << endl;
+
+ cout << "Injected packet length average = " << (double)sent_flits / (double)sent_packets << endl
+ << "Accepted packet length average = " << (double)accepted_flits / (double)accepted_packets << endl;
+
+ cout << "Total in-flight flits = " << _total_in_flight_flits[c].size()
+ << " (" << _measured_in_flight_flits[c].size() << " measured)"
+ << endl;
+
+#ifdef TRACK_STALLS
+ _ComputeStats(_buffer_busy_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ os << "Buffer busy stall rate = " << rate_avg << endl;
+ _ComputeStats(_buffer_conflict_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ os << "Buffer conflict stall rate = " << rate_avg << endl;
+ _ComputeStats(_buffer_full_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ os << "Buffer full stall rate = " << rate_avg << endl;
+ _ComputeStats(_buffer_reserved_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ os << "Buffer reserved stall rate = " << rate_avg << endl;
+ _ComputeStats(_crossbar_conflict_stalls[c], &count_sum);
+ rate_sum = (double)count_sum / time_delta;
+ rate_avg = rate_sum / (double)(_subnets*_routers);
+ os << "Crossbar conflict stall rate = " << rate_avg << endl;
+#endif
+
+ }
+}
+
+void TrafficManager::DisplayOverallStats( ostream & os ) const {
+
+ os << "====== Overall Traffic Statistics ======" << endl;
+ for ( int c = 0; c < _classes; ++c ) {
+
+ if(_measure_stats[c] == 0) {
+ continue;
+ }
+
+ os << "====== Traffic class " << c << " ======" << endl;
+
+ os << "Packet latency average = " << _overall_avg_plat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_plat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_plat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Network latency average = " << _overall_avg_nlat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_nlat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_nlat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Flit latency average = " << _overall_avg_flat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_flat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_flat[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Fragmentation average = " << _overall_avg_frag[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_frag[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_frag[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Injected packet rate average = " << _overall_avg_sent_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_sent_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_sent_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Accepted packet rate average = " << _overall_avg_accepted_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_accepted_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_accepted_packets[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Injected flit rate average = " << _overall_avg_sent[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_sent[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_sent[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Accepted flit rate average = " << _overall_avg_accepted[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tminimum = " << _overall_min_accepted[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+ os << "\tmaximum = " << _overall_max_accepted[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Injected packet size average = " << _overall_avg_sent[c] / _overall_avg_sent_packets[c]
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Accepted packet size average = " << _overall_avg_accepted[c] / _overall_avg_accepted_packets[c]
+ << " (" << _total_sims << " samples)" << endl;
+
+ os << "Hops average = " << _overall_hop_stats[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+
+#ifdef TRACK_STALLS
+ os << "Buffer busy stall rate = " << (double)_overall_buffer_busy_stalls[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Buffer conflict stall rate = " << (double)_overall_buffer_conflict_stalls[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Buffer full stall rate = " << (double)_overall_buffer_full_stalls[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Buffer reserved stall rate = " << (double)_overall_buffer_reserved_stalls[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl
+ << "Crossbar conflict stall rate = " << (double)_overall_crossbar_conflict_stalls[c] / (double)_total_sims
+ << " (" << _total_sims << " samples)" << endl;
+#endif
+
+ }
+
+}
+
+string TrafficManager::_OverallStatsCSV(int c) const
+{
+ ostringstream os;
+ os << _traffic[c]
+ << ',' << _use_read_write[c]
+ << ',' << _load[c]
+ << ',' << _overall_min_plat[c] / (double)_total_sims
+ << ',' << _overall_avg_plat[c] / (double)_total_sims
+ << ',' << _overall_max_plat[c] / (double)_total_sims
+ << ',' << _overall_min_nlat[c] / (double)_total_sims
+ << ',' << _overall_avg_nlat[c] / (double)_total_sims
+ << ',' << _overall_max_nlat[c] / (double)_total_sims
+ << ',' << _overall_min_flat[c] / (double)_total_sims
+ << ',' << _overall_avg_flat[c] / (double)_total_sims
+ << ',' << _overall_max_flat[c] / (double)_total_sims
+ << ',' << _overall_min_frag[c] / (double)_total_sims
+ << ',' << _overall_avg_frag[c] / (double)_total_sims
+ << ',' << _overall_max_frag[c] / (double)_total_sims
+ << ',' << _overall_min_sent_packets[c] / (double)_total_sims
+ << ',' << _overall_avg_sent_packets[c] / (double)_total_sims
+ << ',' << _overall_max_sent_packets[c] / (double)_total_sims
+ << ',' << _overall_min_accepted_packets[c] / (double)_total_sims
+ << ',' << _overall_avg_accepted_packets[c] / (double)_total_sims
+ << ',' << _overall_max_accepted_packets[c] / (double)_total_sims
+ << ',' << _overall_min_sent[c] / (double)_total_sims
+ << ',' << _overall_avg_sent[c] / (double)_total_sims
+ << ',' << _overall_max_sent[c] / (double)_total_sims
+ << ',' << _overall_min_accepted[c] / (double)_total_sims
+ << ',' << _overall_avg_accepted[c] / (double)_total_sims
+ << ',' << _overall_max_accepted[c] / (double)_total_sims
+ << ',' << _overall_avg_sent[c] / _overall_avg_sent_packets[c]
+ << ',' << _overall_avg_accepted[c] / _overall_avg_accepted_packets[c]
+ << ',' << _overall_hop_stats[c] / (double)_total_sims;
+
+#ifdef TRACK_STALLS
+ os << ',' << (double)_overall_buffer_busy_stalls[c] / (double)_total_sims
+ << ',' << (double)_overall_buffer_conflict_stalls[c] / (double)_total_sims
+ << ',' << (double)_overall_buffer_full_stalls[c] / (double)_total_sims
+ << ',' << (double)_overall_buffer_reserved_stalls[c] / (double)_total_sims
+ << ',' << (double)_overall_crossbar_conflict_stalls[c] / (double)_total_sims;
+#endif
+
+ return os.str();
+}
+
+void TrafficManager::DisplayOverallStatsCSV(ostream & os) const {
+ for(int c = 0; c < _classes; ++c) {
+ os << "results:" << c << ',' << _OverallStatsCSV() << endl;
+ }
+}
+
+//read the watchlist
+void TrafficManager::_LoadWatchList(const string & filename){
+ ifstream watch_list;
+ watch_list.open(filename.c_str());
+
+ string line;
+ if(watch_list.is_open()) {
+ while(!watch_list.eof()) {
+ getline(watch_list, line);
+ if(line != "") {
+ if(line[0] == 'p') {
+ _packets_to_watch.insert(atoi(line.c_str()+1));
+ } else {
+ _flits_to_watch.insert(atoi(line.c_str()));
+ }
+ }
+ }
+
+ } else {
+ Error("Unable to open flit watch file: " + filename);
+ }
+}
+
+int TrafficManager::_GetNextPacketSize(int cl) const
+{
+ assert(cl >= 0 && cl < _classes);
+
+ vector<int> const & psize = _packet_size[cl];
+ int sizes = psize.size();
+
+ if(sizes == 1) {
+ return psize[0];
+ }
+
+ vector<int> const & prate = _packet_size_rate[cl];
+ int max_val = _packet_size_max_val[cl];
+
+ int pct = RandomInt(max_val);
+
+ for(int i = 0; i < (sizes - 1); ++i) {
+ int const limit = prate[i];
+ if(limit > pct) {
+ return psize[i];
+ } else {
+ pct -= limit;
+ }
+ }
+ assert(prate.back() > pct);
+ return psize.back();
+}
+
+double TrafficManager::_GetAveragePacketSize(int cl) const
+{
+ vector<int> const & psize = _packet_size[cl];
+ int sizes = psize.size();
+ if(sizes == 1) {
+ return (double)psize[0];
+ }
+ vector<int> const & prate = _packet_size_rate[cl];
+ int sum = 0;
+ for(int i = 0; i < sizes; ++i) {
+ sum += psize[i] * prate[i];
+ }
+ return (double)sum / (double)(_packet_size_max_val[cl] + 1);
+}
diff --git a/src/intersim2/trafficmanager.hpp b/src/intersim2/trafficmanager.hpp
new file mode 100644
index 0000000..9694df4
--- /dev/null
+++ b/src/intersim2/trafficmanager.hpp
@@ -0,0 +1,322 @@
+// $Id: trafficmanager.hpp 5365 2012-11-25 02:09:59Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _TRAFFICMANAGER_HPP_
+#define _TRAFFICMANAGER_HPP_
+
+#include <list>
+#include <map>
+#include <set>
+#include <cassert>
+
+#include "module.hpp"
+#include "config_utils.hpp"
+#include "network.hpp"
+#include "flit.hpp"
+#include "buffer_state.hpp"
+#include "stats.hpp"
+#include "traffic.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "injection.hpp"
+
+//register the requests to a node
+class PacketReplyInfo;
+
+class TrafficManager : public Module {
+
+private:
+
+ vector<vector<int> > _packet_size;
+ vector<vector<int> > _packet_size_rate;
+ vector<int> _packet_size_max_val;
+
+protected:
+ int _nodes;
+ int _routers;
+ int _vcs;
+
+ vector<Network *> _net;
+ vector<vector<Router *> > _router;
+
+ // ============ Traffic ============
+
+ int _classes;
+
+ vector<double> _load;
+
+ vector<int> _use_read_write;
+ vector<double> _write_fraction;
+
+ vector<int> _read_request_size;
+ vector<int> _read_reply_size;
+ vector<int> _write_request_size;
+ vector<int> _write_reply_size;
+
+ vector<string> _traffic;
+
+ vector<int> _class_priority;
+
+ vector<vector<int> > _last_class;
+
+ vector<TrafficPattern *> _traffic_pattern;
+ vector<InjectionProcess *> _injection_process;
+
+ // ============ Message priorities ============
+
+ enum ePriority { class_based, age_based, network_age_based, local_age_based, queue_length_based, hop_count_based, sequence_based, none };
+
+ ePriority _pri_type;
+
+ // ============ Injection VC states ============
+
+ vector<vector<BufferState *> > _buf_states;
+#ifdef TRACK_FLOWS
+ vector<vector<vector<int> > > _outstanding_credits;
+ vector<vector<vector<queue<int> > > > _outstanding_classes;
+#endif
+ vector<vector<vector<int> > > _last_vc;
+
+ // ============ Routing ============
+
+ tRoutingFunction _rf;
+ bool _lookahead_routing;
+ bool _noq;
+
+ // ============ Injection queues ============
+
+ vector<vector<int> > _qtime;
+ vector<vector<bool> > _qdrained;
+ vector<vector<list<Flit *> > > _partial_packets;
+
+ vector<map<int, Flit *> > _total_in_flight_flits;
+ vector<map<int, Flit *> > _measured_in_flight_flits;
+ vector<map<int, Flit *> > _retired_packets;
+ bool _empty_network;
+
+ bool _hold_switch_for_packet;
+
+ // ============ physical sub-networks ==========
+
+ int _subnets;
+
+ vector<int> _subnet;
+
+ // ============ deadlock ==========
+
+ int _deadlock_timer;
+ int _deadlock_warn_timeout;
+
+ // ============ request & replies ==========================
+
+ vector<int> _packet_seq_no;
+ vector<list<PacketReplyInfo*> > _repliesPending;
+ vector<int> _requestsOutstanding;
+
+ // ============ Statistics ============
+
+ vector<Stats *> _plat_stats;
+ vector<double> _overall_min_plat;
+ vector<double> _overall_avg_plat;
+ vector<double> _overall_max_plat;
+
+ vector<Stats *> _nlat_stats;
+ vector<double> _overall_min_nlat;
+ vector<double> _overall_avg_nlat;
+ vector<double> _overall_max_nlat;
+
+ vector<Stats *> _flat_stats;
+ vector<double> _overall_min_flat;
+ vector<double> _overall_avg_flat;
+ vector<double> _overall_max_flat;
+
+ vector<Stats *> _frag_stats;
+ vector<double> _overall_min_frag;
+ vector<double> _overall_avg_frag;
+ vector<double> _overall_max_frag;
+
+ vector<vector<Stats *> > _pair_plat;
+ vector<vector<Stats *> > _pair_nlat;
+ vector<vector<Stats *> > _pair_flat;
+
+ vector<Stats *> _hop_stats;
+ vector<double> _overall_hop_stats;
+
+ vector<vector<int> > _sent_packets;
+ vector<double> _overall_min_sent_packets;
+ vector<double> _overall_avg_sent_packets;
+ vector<double> _overall_max_sent_packets;
+ vector<vector<int> > _accepted_packets;
+ vector<double> _overall_min_accepted_packets;
+ vector<double> _overall_avg_accepted_packets;
+ vector<double> _overall_max_accepted_packets;
+ vector<vector<int> > _sent_flits;
+ vector<double> _overall_min_sent;
+ vector<double> _overall_avg_sent;
+ vector<double> _overall_max_sent;
+ vector<vector<int> > _accepted_flits;
+ vector<double> _overall_min_accepted;
+ vector<double> _overall_avg_accepted;
+ vector<double> _overall_max_accepted;
+
+#ifdef TRACK_STALLS
+ vector<vector<int> > _buffer_busy_stalls;
+ vector<vector<int> > _buffer_conflict_stalls;
+ vector<vector<int> > _buffer_full_stalls;
+ vector<vector<int> > _buffer_reserved_stalls;
+ vector<vector<int> > _crossbar_conflict_stalls;
+ vector<double> _overall_buffer_busy_stalls;
+ vector<double> _overall_buffer_conflict_stalls;
+ vector<double> _overall_buffer_full_stalls;
+ vector<double> _overall_buffer_reserved_stalls;
+ vector<double> _overall_crossbar_conflict_stalls;
+#endif
+
+ vector<int> _slowest_packet;
+ vector<int> _slowest_flit;
+
+ map<string, Stats *> _stats;
+
+ // ============ Simulation parameters ============
+
+ enum eSimState { warming_up, running, draining, done };
+ eSimState _sim_state;
+
+ bool _measure_latency;
+
+ int _reset_time;
+ int _drain_time;
+
+ int _total_sims;
+ int _sample_period;
+ int _max_samples;
+ int _warmup_periods;
+
+ int _include_queuing;
+
+ vector<int> _measure_stats;
+ bool _pair_stats;
+
+ vector<double> _latency_thres;
+
+ vector<double> _stopping_threshold;
+ vector<double> _acc_stopping_threshold;
+
+ vector<double> _warmup_threshold;
+ vector<double> _acc_warmup_threshold;
+
+ int _cur_id;
+ int _cur_pid;
+ int _time;
+
+ set<int> _flits_to_watch;
+ set<int> _packets_to_watch;
+
+ bool _print_csv_results;
+
+ //flits to watch
+ ostream * _stats_out;
+
+#ifdef TRACK_FLOWS
+ vector<vector<int> > _injected_flits;
+ vector<vector<int> > _ejected_flits;
+ ostream * _injected_flits_out;
+ ostream * _received_flits_out;
+ ostream * _stored_flits_out;
+ ostream * _sent_flits_out;
+ ostream * _outstanding_credits_out;
+ ostream * _ejected_flits_out;
+ ostream * _active_packets_out;
+#endif
+
+#ifdef TRACK_CREDITS
+ ostream * _used_credits_out;
+ ostream * _free_credits_out;
+ ostream * _max_credits_out;
+#endif
+
+ // ============ Internal methods ============
+protected:
+
+ virtual void _RetireFlit( Flit *f, int dest );
+
+ void _Inject();
+ virtual void _Step( );
+
+ bool _PacketsOutstanding( ) const;
+
+ virtual int _IssuePacket( int source, int cl );
+ virtual void _GeneratePacket( int source, int size, int cl, int time );
+
+ virtual void _ClearStats( );
+
+ void _ComputeStats( const vector<int> & stats, int *sum, int *min = NULL, int *max = NULL, int *min_pos = NULL, int *max_pos = NULL ) const;
+
+ virtual bool _SingleSim( );
+
+ void _DisplayRemaining( ostream & os = cout ) const;
+
+ void _LoadWatchList(const string & filename);
+
+ virtual void _UpdateOverallStats();
+
+ virtual string _OverallStatsCSV(int c = 0) const;
+
+ int _GetNextPacketSize(int cl) const;
+ double _GetAveragePacketSize(int cl) const;
+
+public:
+
+ static TrafficManager * New(Configuration const & config,
+ vector<Network *> const & net);
+
+ TrafficManager( const Configuration &config, const vector<Network *> & net );
+ virtual ~TrafficManager( );
+
+ bool Run( );
+
+ virtual void WriteStats( ostream & os = cout ) const ;
+ virtual void UpdateStats( ) ;
+ virtual void DisplayStats( ostream & os = cout ) const ;
+ virtual void DisplayOverallStats( ostream & os = cout ) const ;
+ virtual void DisplayOverallStatsCSV( ostream & os = cout ) const ;
+
+ inline int getTime() { return _time;}
+ Stats * getStats(const string & name) { return _stats[name]; }
+
+};
+
+template<class T>
+ostream & operator<<(ostream & os, const vector<T> & v) {
+ for(size_t i = 0; i < v.size() - 1; ++i) {
+ os << v[i] << ",";
+ }
+ os << v[v.size()-1];
+ return os;
+}
+
+#endif
diff --git a/src/intersim2/vc.cpp b/src/intersim2/vc.cpp
new file mode 100644
index 0000000..94e8c6b
--- /dev/null
+++ b/src/intersim2/vc.cpp
@@ -0,0 +1,223 @@
+// $Id: vc.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*vc.cpp
+ *
+ *this class describes a virtual channel in a router
+ *it includes buffers and virtual channel state and controls
+ *
+ *This class calls the routing functions
+ */
+
+#include <limits>
+#include <sstream>
+
+#include "globals.hpp"
+#include "booksim.hpp"
+#include "vc.hpp"
+
+const char * const VC::VCSTATE[] = {"idle",
+ "routing",
+ "vc_alloc",
+ "active"};
+
+VC::VC( const Configuration& config, int outputs,
+ Module *parent, const string& name )
+ : Module( parent, name ),
+ _state(idle), _out_port(-1), _out_vc(-1), _pri(0), _watched(false),
+ _expected_pid(-1), _last_id(-1), _last_pid(-1)
+{
+ _lookahead_routing = !config.GetInt("routing_delay");
+ _route_set = _lookahead_routing ? NULL : new OutputSet( );
+
+ string priority = config.GetStr( "priority" );
+ if ( priority == "local_age" ) {
+ _pri_type = local_age_based;
+ } else if ( priority == "queue_length" ) {
+ _pri_type = queue_length_based;
+ } else if ( priority == "hop_count" ) {
+ _pri_type = hop_count_based;
+ } else if ( priority == "none" ) {
+ _pri_type = none;
+ } else {
+ _pri_type = other;
+ }
+
+ _priority_donation = config.GetInt("vc_priority_donation");
+}
+
+VC::~VC()
+{
+ if(!_lookahead_routing) {
+ delete _route_set;
+ }
+}
+
+void VC::AddFlit( Flit *f )
+{
+ assert(f);
+
+ if(_expected_pid >= 0) {
+ if(f->pid != _expected_pid) {
+ ostringstream err;
+ err << "Received flit " << f->id << " with unexpected packet ID: " << f->pid
+ << " (expected: " << _expected_pid << ")";
+ Error(err.str());
+ } else if(f->tail) {
+ _expected_pid = -1;
+ }
+ } else if(!f->tail) {
+ _expected_pid = f->pid;
+ }
+
+ // update flit priority before adding to VC buffer
+ if(_pri_type == local_age_based) {
+ f->pri = numeric_limits<int>::max() - GetSimTime();
+ assert(f->pri >= 0);
+ } else if(_pri_type == hop_count_based) {
+ f->pri = f->hops;
+ assert(f->pri >= 0);
+ }
+
+ _buffer.push_back(f);
+ UpdatePriority();
+}
+
+Flit *VC::RemoveFlit( )
+{
+ Flit *f = NULL;
+ if ( !_buffer.empty( ) ) {
+ f = _buffer.front( );
+ _buffer.pop_front( );
+ _last_id = f->id;
+ _last_pid = f->pid;
+ UpdatePriority();
+ } else {
+ Error("Trying to remove flit from empty buffer.");
+ }
+ return f;
+}
+
+
+
+void VC::SetState( eVCState s )
+{
+ Flit * f = FrontFlit();
+
+ if(f && f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Changing state from " << VC::VCSTATE[_state]
+ << " to " << VC::VCSTATE[s] << "." << endl;
+
+ _state = s;
+}
+
+const OutputSet *VC::GetRouteSet( ) const
+{
+ return _route_set;
+}
+
+void VC::SetRouteSet( OutputSet * output_set )
+{
+ _route_set = output_set;
+ _out_port = -1;
+ _out_vc = -1;
+}
+
+void VC::SetOutput( int port, int vc )
+{
+ _out_port = port;
+ _out_vc = vc;
+}
+
+void VC::UpdatePriority()
+{
+ if(_buffer.empty()) return;
+ if(_pri_type == queue_length_based) {
+ _pri = _buffer.size();
+ } else if(_pri_type != none) {
+ Flit * f = _buffer.front();
+ if((_pri_type != local_age_based) && _priority_donation) {
+ Flit * df = f;
+ for(size_t i = 1; i < _buffer.size(); ++i) {
+ Flit * bf = _buffer[i];
+ if(bf->pri > df->pri) df = bf;
+ }
+ if((df != f) && (df->watch || f->watch)) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit " << df->id
+ << " donates priority to flit " << f->id
+ << "." << endl;
+ }
+ f = df;
+ }
+ if(f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit " << f->id
+ << " sets priority to " << f->pri
+ << "." << endl;
+ _pri = f->pri;
+ }
+}
+
+
+void VC::Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel )
+{
+ rf( router, f, in_channel, _route_set, false );
+ _out_port = -1;
+ _out_vc = -1;
+}
+
+// ==== Debug functions ====
+
+void VC::SetWatch( bool watch )
+{
+ _watched = watch;
+}
+
+bool VC::IsWatched( ) const
+{
+ return _watched;
+}
+
+void VC::Display( ostream & os ) const
+{
+ if ( _state != VC::idle ) {
+ os << FullName() << ": "
+ << " state: " << VCSTATE[_state];
+ if(_state == VC::active) {
+ os << " out_port: " << _out_port
+ << " out_vc: " << _out_vc;
+ }
+ os << " fill: " << _buffer.size();
+ if(!_buffer.empty()) {
+ os << " front: " << _buffer.front()->id;
+ }
+ os << " pri: " << _pri;
+ os << endl;
+ }
+}
diff --git a/src/intersim2/vc.hpp b/src/intersim2/vc.hpp
new file mode 100644
index 0000000..55ca317
--- /dev/null
+++ b/src/intersim2/vc.hpp
@@ -0,0 +1,137 @@
+// $Id: vc.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _VC_HPP_
+#define _VC_HPP_
+
+#include <deque>
+
+#include "flit.hpp"
+#include "outputset.hpp"
+#include "routefunc.hpp"
+#include "config_utils.hpp"
+
+class VC : public Module {
+public:
+ enum eVCState { state_min = 0, idle = state_min, routing, vc_alloc, active,
+ state_max = active };
+ struct state_info_t {
+ int cycles;
+ };
+ static const char * const VCSTATE[];
+
+private:
+
+ deque<Flit *> _buffer;
+
+ eVCState _state;
+
+ OutputSet *_route_set;
+ int _out_port, _out_vc;
+
+ enum ePrioType { local_age_based, queue_length_based, hop_count_based, none, other };
+
+ ePrioType _pri_type;
+
+ int _pri;
+
+ int _priority_donation;
+
+ bool _watched;
+
+ int _expected_pid;
+
+ int _last_id;
+ int _last_pid;
+
+ bool _lookahead_routing;
+
+public:
+
+ VC( const Configuration& config, int outputs,
+ Module *parent, const string& name );
+ ~VC();
+
+ void AddFlit( Flit *f );
+ inline Flit *FrontFlit( ) const
+ {
+ return _buffer.empty() ? NULL : _buffer.front();
+ }
+
+ Flit *RemoveFlit( );
+
+
+ inline bool Empty( ) const
+ {
+ return _buffer.empty( );
+ }
+
+ inline VC::eVCState GetState( ) const
+ {
+ return _state;
+ }
+
+
+ void SetState( eVCState s );
+
+ const OutputSet *GetRouteSet( ) const;
+ void SetRouteSet( OutputSet * output_set );
+
+ void SetOutput( int port, int vc );
+
+ inline int GetOutputPort( ) const
+ {
+ return _out_port;
+ }
+
+
+ inline int GetOutputVC( ) const
+ {
+ return _out_vc;
+ }
+
+ void UpdatePriority();
+
+ inline int GetPriority( ) const
+ {
+ return _pri;
+ }
+ void Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel );
+
+ inline int GetOccupancy() const
+ {
+ return (int)_buffer.size();
+ }
+
+ // ==== Debug functions ====
+
+ void SetWatch( bool watch = true );
+ bool IsWatched( ) const;
+ void Display( ostream & os = cout ) const;
+};
+
+#endif