diff options
| author | Tor Aamodt <[email protected]> | 2010-07-15 18:09:46 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-07-15 18:09:46 -0800 |
| commit | 69f2911e04ffb1b19eef1fafb8c040af271f656e (patch) | |
| tree | 231d3b6bdc3a202f7c255bfcf7bf2c36e32cee9e /src/intersim | |
creating branch for adding support for CUDA 3.x and Fermi
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 6829]
Diffstat (limited to 'src/intersim')
84 files changed, 11199 insertions, 0 deletions
diff --git a/src/intersim/Makefile b/src/intersim/Makefile new file mode 100644 index 0000000..41525fd --- /dev/null +++ b/src/intersim/Makefile @@ -0,0 +1,119 @@ +CREATESHAREDLIB ?=0 +CPP = g++ $(SNOW) +CC = gcc $(SNOW) + +ifeq ($(INTEL),1) + CPP = icpc + CC = icc +endif + + +YACC = bison -d +LEX = flex +PURIFY = /usr/bin/purify +QUANT = /usr/bin/quantify + + +INTERFACE = interconnect_interface.cpp +DEBUG = 0 +CPPFLAGS = -g -Wall +ifneq ($(DEBUG),1) +CPPFLAGS = -O3 -g +else +CPPFLAGS += -D_GLIBCXX_DEBUG -DGLIBCXX_DEBUG_PEDANTIC +endif + +TEST = -DUNIT_TEST +ifneq ($(UNIT_TEST),1) +TEST = +endif + + CPPFLAGS += -fPIC + +PROG = intersim + +CPP_SRCS = $(INTERFACE) \ + config_utils.cpp \ + booksim_config.cpp \ + module.cpp \ + router.cpp \ + iq_router.cpp \ + event_router.cpp \ + vc.cpp \ + routefunc.cpp \ + traffic.cpp \ + allocator.cpp \ + maxsize.cpp \ + network.cpp \ + singlenet.cpp \ + kncube.cpp \ + fly.cpp \ + trafficmanager.cpp \ + random_utils.cpp \ + buffer_state.cpp \ + stats.cpp \ + pim.cpp \ + islip.cpp \ + loa.cpp \ + wavefront.cpp \ + misc_utils.cpp \ + credit.cpp \ + outputset.cpp \ + flit.cpp \ + selalloc.cpp \ + arbiter.cpp \ + injection.cpp \ + rng_wrapper.cpp \ + rng_double_wrapper.cpp \ + statwraper.cpp + +LEX_OBJS = configlex.o +YACC_OBJS = config_tab.o + +#--- Make rules --- + +OBJS = $(CPP_SRCS:.cpp=.o) $(LEX_OBJS) $(YACC_OBJS) + +.PHONY: clean +.PRECIOUS: %_tab.cpp %_tab.hpp %lex.cpp + +lib$(PROG).a: $(OBJS) + ar rcs lib$(PROG).a $(OBJS) + +purify: $(OBJS) + $(PURIFY) -always-use-cache-dir $(CPP) $(OBJS) -o $(PROG) -L/usr/lib + +quantify: $(OBJS) + $(QUANT) -always-use-cache-dir $(CPP) $(OBJS) -o $(PROG) -L/usr/lib + +%lex.o: %lex.cpp %_tab.hpp + $(CPP) $(CPPFLAGS) -c $< -o $@ + +%.o: %.cpp + $(CPP) $(EXTRA) $(CPPFLAGS) $(TEST) -c $< -o $@ + +%.o: %.c + $(CPP) $(CPPFLAGS) $(TEST) $(VCSFLAGS) -c $< -o $@ + +%_tab.cpp: %.y + $(YACC) -b$* -p$* $< + cp -f $*.tab.c $*_tab.cpp + +%_tab.hpp: %_tab.cpp + cp -f $*.tab.h $*_tab.hpp + +%lex.cpp: %.l + $(LEX) -P$* -o$@ $< + cp configlex.cpp configlex.cpp.orig + awk '/configlineno = 1/ {if (line == 0) {line = 1; print} next;} //{print}' configlex.cpp.orig > configlex.cpp + +clean: + rm -f $(OBJS) *_tab.cpp *_tab.hpp *.tab.c *.tab.h *lex.cpp + rm -f $(PROG) + rm -f lib$(PROG).a + rm -f lib$(PROG).so + +interconnect_interface.o: ../cuda-sim/ptx.tab.h + +../cuda-sim/ptx.tab.h: + make -C ../cuda-sim/ ptx.tab.c diff --git a/src/intersim/allocator.cpp b/src/intersim/allocator.cpp new file mode 100644 index 0000000..b7aae5d --- /dev/null +++ b/src/intersim/allocator.cpp @@ -0,0 +1,429 @@ +#include "booksim.hpp"
+#include <iostream>
+#include <assert.h>
+
+#include "allocator.hpp"
+#include "maxsize.hpp"
+#include "pim.hpp"
+#include "islip.hpp"
+#include "loa.hpp"
+#include "wavefront.hpp"
+#include "selalloc.hpp"
+
+//==================================================
+// Allocator base class
+//==================================================
+
+Allocator::Allocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+Module( parent, name ), _inputs( inputs ), _outputs( outputs )
+{
+ _inmatch = new int [_inputs];
+ _outmatch = new int [_outputs];
+ _outmask = new int [_outputs];
+
+ for ( int out = 0; out < _outputs; ++out ) {
+ _outmask[out] = 0; // active
+ }
+}
+
+Allocator::~Allocator( )
+{
+ delete [] _inmatch;
+ delete [] _outmatch;
+ delete [] _outmask;
+}
+
+void Allocator::_ClearMatching( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ _inmatch[i] = -1;
+ }
+
+ for ( int j = 0; j < _outputs; ++j ) {
+ _outmatch[j] = -1;
+ }
+}
+
+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::MaskOutput( int out, int mask )
+{
+ assert( ( out >= 0 ) && ( out < _outputs ) );
+ _outmask[out] = mask;
+}
+
+//==================================================
+// DenseAllocator
+//==================================================
+
+DenseAllocator::DenseAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+Allocator( config, parent, name, inputs, outputs )
+{
+ _request = new sRequest * [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _request[i] = new sRequest [_outputs];
+ }
+
+ Clear( );
+}
+
+DenseAllocator::~DenseAllocator( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete [] _request[i];
+ }
+
+ delete [] _request;
+}
+
+void DenseAllocator::Clear( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ for ( int j = 0; j < _outputs; ++j ) {
+ _request[i][j].label = -1;
+ }
+ }
+}
+
+int DenseAllocator::ReadRequest( int in, int out ) const
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ return _request[in][out].label;
+}
+
+bool DenseAllocator::ReadRequest( sRequest &req, int in, int out ) const
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ req = _request[in][out];
+
+ return( req.label != -1 );
+}
+
+void DenseAllocator::AddRequest( int in, int out, int label,
+ int in_pri, int out_pri )
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ _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 ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ _request[in][out].label = -1;
+}
+
+void DenseAllocator::PrintRequests( ) const
+{
+ cout << "requests for " << _fullname << endl;
+ for ( int i = 0; i < _inputs; ++i ) {
+ for ( int j = 0; j < _outputs; ++j ) {
+ cout << ( _request[i][j].label != -1 ) << " ";
+ }
+ cout << endl;
+ }
+ cout << endl;
+}
+
+//==================================================
+// SparseAllocator
+//==================================================
+
+SparseAllocator::SparseAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+Allocator( config, parent, name, inputs, outputs )
+{
+ _in_req = new list<sRequest> [_inputs];
+ _out_req = new list<sRequest> [_outputs];
+}
+
+
+SparseAllocator::~SparseAllocator( )
+{
+ delete [] _in_req;
+ delete [] _out_req;
+}
+
+void SparseAllocator::Clear( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ _in_req[i].clear( );
+ }
+
+ for ( int j = 0; j < _outputs; ++j ) {
+ _out_req[j].clear( );
+ }
+
+ _in_occ.clear( );
+ _out_occ.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 ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ list<sRequest>::const_iterator match;
+
+ match = _in_req[in].begin( );
+ while ( ( match != _in_req[in].end( ) ) &&
+ ( match->port != out ) ) {
+ match++;
+ }
+
+ if ( match != _in_req[in].end( ) ) {
+ req = *match;
+ found = true;
+ } else {
+ found = false;
+ }
+
+ return found;
+}
+
+void SparseAllocator::AddRequest( int in, int out, int label,
+ int in_pri, int out_pri )
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ list<sRequest>::iterator insert_point;
+ list<int>::iterator occ_insert;
+ sRequest req;
+
+ // insert into occupied inputs list if
+ // input is currently empty
+ if ( _in_req[in].empty( ) ) {
+ occ_insert = _in_occ.begin( );
+ while ( ( occ_insert != _in_occ.end( ) ) &&
+ ( *occ_insert < in ) ) {
+ occ_insert++;
+ }
+ assert( ( occ_insert == _in_occ.end( ) ) ||
+ ( *occ_insert != in ) );
+
+ _in_occ.insert( occ_insert, in );
+ }
+
+ // similarly for the output
+ if ( _out_req[out].empty( ) ) {
+ occ_insert = _out_occ.begin( );
+ while ( ( occ_insert != _out_occ.end( ) ) &&
+ ( *occ_insert < out ) ) {
+ occ_insert++;
+ }
+ assert( ( occ_insert == _out_occ.end( ) ) ||
+ ( *occ_insert != out ) );
+
+ _out_occ.insert( occ_insert, out );
+ }
+
+ // insert input request in order of it's output
+ insert_point = _in_req[in].begin( );
+ while ( ( insert_point != _in_req[in].end( ) ) &&
+ ( insert_point->port < out ) ) {
+ insert_point++;
+ }
+
+ req.port = out;
+ req.label = label;
+ req.in_pri = in_pri;
+ req.out_pri = out_pri;
+
+ bool del = false;
+ bool add = true;
+
+ // For consistent behavior, delete the existing request
+ // if it is for the same output and has a higher
+ // priority
+
+ if ( ( insert_point != _in_req[in].end( ) ) &&
+ ( insert_point->port == out ) ) {
+ if ( insert_point->in_pri < in_pri ) {
+ del = true;
+ } else {
+ add = false;
+ }
+ }
+
+ if ( add ) {
+ _in_req[in].insert( insert_point, req );
+ }
+
+ if ( del ) {
+ _in_req[in].erase( insert_point );
+ }
+
+ insert_point = _out_req[out].begin( );
+ while ( ( insert_point != _out_req[out].end( ) ) &&
+ ( insert_point->port < in ) ) {
+ insert_point++;
+ }
+
+ req.port = in;
+ req.label = label;
+
+ if ( add ) {
+ _out_req[out].insert( insert_point, req );
+ }
+
+ if ( del ) {
+ // This should be consistent, but check for sanity
+ if ( ( insert_point == _out_req[out].end( ) ) ||
+ ( insert_point->port != in ) ) {
+ Error( "Internal allocator error --- input and output requests non consistent" );
+ }
+ _out_req[out].erase( insert_point );
+ }
+}
+
+void SparseAllocator::RemoveRequest( int in, int out, int label )
+{
+ assert( ( in >= 0 ) && ( in < _inputs ) &&
+ ( out >= 0 ) && ( out < _outputs ) );
+
+ list<sRequest>::iterator erase_point;
+ list<int>::iterator occ_remove;
+
+ // insert input request in order of it's output
+ erase_point = _in_req[in].begin( );
+ while ( ( erase_point != _in_req[in].end( ) ) &&
+ ( erase_point->port != out ) ) {
+ erase_point++;
+ }
+
+ assert( erase_point != _in_req[in].end( ) );
+ _in_req[in].erase( erase_point );
+
+ // remove from occupied inputs list if
+ // input is now empty
+ if ( _in_req[in].empty( ) ) {
+ occ_remove = _in_occ.begin( );
+ while ( ( occ_remove != _in_occ.end( ) ) &&
+ ( *occ_remove != in ) ) {
+ occ_remove++;
+ }
+
+ assert( occ_remove != _in_occ.end( ) );
+ _in_occ.erase( occ_remove );
+ }
+
+ // similarly for the output
+ erase_point = _out_req[out].begin( );
+ while ( ( erase_point != _out_req[out].end( ) ) &&
+ ( erase_point->port != in ) ) {
+ erase_point++;
+ }
+
+ assert( erase_point != _out_req[out].end( ) );
+ _out_req[out].erase( erase_point );
+
+ if ( _out_req[out].empty( ) ) {
+ occ_remove = _out_occ.begin( );
+ while ( ( occ_remove != _out_occ.end( ) ) &&
+ ( *occ_remove != out ) ) {
+ occ_remove++;
+ }
+
+ assert( occ_remove != _out_occ.end( ) );
+ _out_occ.erase( occ_remove );
+ }
+}
+
+void SparseAllocator::PrintRequests( ) const
+{
+ list<sRequest>::const_iterator iter;
+
+ cout << "input requests:" << endl;
+ for ( int input = 0; input < _inputs; ++input ) {
+ cout << " input " << input << " : ";
+ for ( iter = _in_req[input].begin( );
+ iter != _in_req[input].end( ); iter++ ) {
+ cout << iter->port << " ";
+ }
+ cout << endl;
+ }
+
+ cout << "output requests:" << endl;
+ for ( int output = 0; output < _outputs; ++output ) {
+ cout << " output " << output << " : ";
+ if ( _outmask[output] == 0 ) {
+ for ( iter = _out_req[output].begin( );
+ iter != _out_req[output].end( ); iter++ ) {
+ cout << iter->port << " ";
+ }
+ cout << endl;
+ } else {
+ cout << "masked" << endl;
+ }
+ }
+}
+
+//==================================================
+// Global allocator allocation function
+//==================================================
+
+Allocator *Allocator::NewAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ const string &alloc_type,
+ int inputs, int input_speedup,
+ int outputs, int output_speedup )
+{
+ Allocator *a = 0;
+
+ if ( alloc_type == "max_size" ) {
+ a = new MaxSizeMatch( config, parent, name, inputs, outputs );
+ } else if ( alloc_type == "pim" ) {
+ a = new PIM( config, parent, name, inputs, outputs );
+ } else if ( alloc_type == "islip" ) {
+ a = new iSLIP_Sparse( config, parent, name, inputs, outputs );
+ } else if ( alloc_type == "loa" ) {
+ a = new LOA( config, parent, name, inputs, input_speedup, outputs, output_speedup );
+ } else if ( alloc_type == "wavefront" ) {
+ a = new Wavefront( config, parent, name, inputs, outputs );
+ } else if ( alloc_type == "select" ) {
+ a = new SelAlloc( config, parent, name, inputs, outputs );
+ }
+
+ return a;
+}
diff --git a/src/intersim/allocator.hpp b/src/intersim/allocator.hpp new file mode 100644 index 0000000..ac77a3a --- /dev/null +++ b/src/intersim/allocator.hpp @@ -0,0 +1,122 @@ +#ifndef _ALLOCATOR_HPP_
+#define _ALLOCATOR_HPP_
+
+#include <string>
+#include <list>
+
+#include "module.hpp"
+#include "config_utils.hpp"
+
+class Allocator : public Module {
+protected:
+ const int _inputs;
+ const int _outputs;
+
+ int *_inmatch;
+ int *_outmatch;
+
+ int *_outmask;
+
+ void _ClearMatching( );
+public:
+
+ struct sRequest {
+ int port;
+ int label;
+ int in_pri;
+ int out_pri;
+ };
+
+ Allocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ virtual ~Allocator( );
+
+ virtual void Clear( ) = 0;
+
+ 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 ) = 0;
+ virtual void RemoveRequest( int in, int out, int label = 1 ) = 0;
+
+ virtual void Allocate( ) = 0;
+
+ void MaskOutput( int out, int mask = 1 );
+
+ int OutputAssigned( int in ) const;
+ int InputAssigned( int out ) const;
+
+ virtual void PrintRequests( ) const = 0;
+
+ static Allocator *NewAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ const string &alloc_type,
+ int inputs, int input_speedup,
+ int outputs, int output_speedup );
+};
+
+//==================================================
+// A dense allocator stores the entire request
+// matrix.
+//==================================================
+
+class DenseAllocator : public Allocator {
+protected:
+ sRequest **_request;
+
+public:
+ DenseAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ virtual ~DenseAllocator( );
+
+ 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 );
+
+ virtual void Allocate( ) = 0;
+
+ void PrintRequests( ) const;
+};
+
+//==================================================
+// A sparse allocator only stores the requests
+// (allows for a more efficient implementation).
+//==================================================
+
+class SparseAllocator : public Allocator {
+protected:
+ list<int> _in_occ;
+ list<int> _out_occ;
+
+ list<sRequest> *_in_req;
+ list<sRequest> *_out_req;
+
+public:
+ SparseAllocator( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ virtual ~SparseAllocator( );
+
+ 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 );
+
+ virtual void Allocate( ) = 0;
+
+ void PrintRequests( ) const;
+};
+
+#endif
diff --git a/src/intersim/arbiter.cpp b/src/intersim/arbiter.cpp new file mode 100644 index 0000000..7225b9b --- /dev/null +++ b/src/intersim/arbiter.cpp @@ -0,0 +1,143 @@ +#include "booksim.hpp"
+#include <assert.h>
+
+#include "arbiter.hpp"
+
+
+Arbiter::Arbiter( const Configuration &,
+ Module *parent, const string& name,
+ int inputs )
+: Module( parent, name ), _inputs( inputs )
+{
+}
+
+Arbiter::~Arbiter( )
+{
+}
+
+void Arbiter::Clear( )
+{
+ _requests.clear( );
+}
+
+void Arbiter::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 Arbiter::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 Arbiter::Match( ) const
+{
+ return _match;
+}
+
+//==================================================
+// PriorityArbiter
+//==================================================
+
+PriorityArbiter::PriorityArbiter( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs )
+: Arbiter( config, parent, name, inputs )
+{
+ _rr_ptr = 0;
+}
+
+PriorityArbiter::~PriorityArbiter( )
+{
+}
+
+void PriorityArbiter::Arbitrate( )
+{
+ list<sRequest>::iterator p;
+
+ int max_index, max_pri;
+ bool wrapped;
+
+ 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;
+ }
+}
diff --git a/src/intersim/arbiter.hpp b/src/intersim/arbiter.hpp new file mode 100644 index 0000000..23b5232 --- /dev/null +++ b/src/intersim/arbiter.hpp @@ -0,0 +1,51 @@ +#ifndef _ARBITER_HPP_
+#define _ARBITER_HPP_
+
+#include <list>
+
+#include "module.hpp"
+#include "config_utils.hpp"
+
+class Arbiter : public Module {
+protected:
+ const int _inputs;
+
+ struct sRequest {
+ int in;
+ int label;
+ int pri;
+ };
+
+ list<sRequest> _requests;
+
+ int _match;
+
+public:
+ Arbiter( const Configuration &,
+ Module *parent, const string& name,
+ int inputs );
+ virtual ~Arbiter( );
+
+ void Clear( );
+
+ void AddRequest( int in, int label = 0, int pri = 0 );
+ void RemoveRequest( int in, int label = 0 );
+
+ virtual void Arbitrate( ) = 0;
+
+ int Match( ) const;
+};
+
+class PriorityArbiter : public Arbiter {
+ int _rr_ptr;
+
+public:
+ PriorityArbiter( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs );
+ ~PriorityArbiter( );
+
+ void Arbitrate( );
+};
+
+#endif
diff --git a/src/intersim/booksim.hpp b/src/intersim/booksim.hpp new file mode 100644 index 0000000..3f0a77e --- /dev/null +++ b/src/intersim/booksim.hpp @@ -0,0 +1,13 @@ +#ifndef _BOOKSIM_HPP_
+#define _BOOKSIM_HPP_
+
+#include <string>
+
+#ifdef _WIN32_
+ #pragma warning (disable: 4786)
+ #include <ostream>
+#endif
+
+using namespace std;
+
+#endif
diff --git a/src/intersim/booksim_config.cpp b/src/intersim/booksim_config.cpp new file mode 100644 index 0000000..da3bd08 --- /dev/null +++ b/src/intersim/booksim_config.cpp @@ -0,0 +1,140 @@ +#include "booksim.hpp"
+#include "booksim_config.hpp"
+
+BookSimConfig::BookSimConfig( )
+{
+ _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_buf_size"] = 0;
+ _int_map["ejection_buf_size"] = 0; // if left zero the simulator will use the vc_buf_size instead
+ _int_map["boundary_buf_size"] = 16;
+
+ //========================================================
+ // Network options
+ //========================================================
+
+ //==== Multi-node topology options =======================
+
+ AddStrField( "topology", "torus" );
+
+ _int_map["k"] = 8;
+ _int_map["n"] = 2;
+
+ AddStrField( "routing_function", "none" );
+ AddStrField( "selection_function", "random" );
+
+ _int_map["link_failures"] = 0;
+ _int_map["fail_seed"] = 0;
+
+ _int_map["wire_delay"] = 0;
+
+ //==== Single-node options ===============================
+
+ _int_map["in_ports"] = 5;
+ _int_map["out_ports"] = 5;
+
+ _int_map["voq"] = 0;
+
+ //========================================================
+ // Router options
+ //========================================================
+
+ //==== General options ===================================
+
+ AddStrField( "router", "iq" );
+
+ _int_map["output_delay"] = 0;
+ _int_map["credit_delay"] = 0;
+ _float_map["internal_speedup"] = 1.0;
+
+ //==== Input-queued ======================================
+
+ _int_map["num_vcs"] = 1;
+ _int_map["vc_buf_size"] = 4;
+ _int_map["vc_buffer_pool"] = 0;
+
+ _int_map["wait_for_tail_credit"] = 1; // reallocate a VC before a tail credit?
+
+ _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"] = 0;
+ _int_map["vc_alloc_delay"] = 0;
+ _int_map["sw_alloc_delay"] = 0;
+ _int_map["st_prepare_delay"] = 0;
+ _int_map["st_final_delay"] = 0;
+
+ //==== Event-driven =====================================
+
+ _int_map["vct"] = 0;
+
+ //==== Allocators ========================================
+
+ AddStrField( "vc_allocator", "max_size" );
+ AddStrField( "sw_allocator", "max_size" );
+
+ _int_map["alloc_iters"] = 1;
+
+ //==== Traffic ========================================
+
+ AddStrField( "traffic", "uniform" );
+
+ _int_map["perm_seed"] = 0; // seed value for random perms
+
+ _float_map["injection_rate"] = 0.2;
+ _int_map["const_flits_per_packet"] = 1;
+
+ AddStrField( "injection_process", "bernoulli" );
+
+ _float_map["burst_alpha"] = 0.5; // burst interval
+ _float_map["burst_beta"] = 0.5; // burst length
+
+ AddStrField( "priority", "age" ); // message priorities
+
+ //==== 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"] = 0; // 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
+
+ _float_map["latency_thres"] = 1000.0; // if avg. latency exceeds the threshold, assume unstable
+
+ _int_map["sim_count"] = 1; // number of simulations to perform
+
+ _int_map["auto_periods"] = 1; // non-zero for the simulator to automatically
+ // control the length of warm-up and the
+ // total length of the simulation
+
+ _int_map["include_queuing"] = 1; // non-zero includes source queuing latency
+
+ _int_map["reorder"] = 0;
+
+ _int_map["flit_timing"] = 0; // know what you're doing
+ _int_map["split_packets"] = 0;
+
+ _int_map["seed"] = 0;
+}
diff --git a/src/intersim/booksim_config.hpp b/src/intersim/booksim_config.hpp new file mode 100644 index 0000000..0e86fab --- /dev/null +++ b/src/intersim/booksim_config.hpp @@ -0,0 +1,11 @@ +#ifndef _BOOKSIM_CONFIG_HPP_
+#define _BOOKSIM_CONFIG_HPP_
+
+#include "config_utils.hpp"
+
+class BookSimConfig : public Configuration {
+public:
+ BookSimConfig( );
+};
+
+#endif
diff --git a/src/intersim/buffer_state.cpp b/src/intersim/buffer_state.cpp new file mode 100644 index 0000000..72a327d --- /dev/null +++ b/src/intersim/buffer_state.cpp @@ -0,0 +1,145 @@ +#include "booksim.hpp"
+#include <iostream>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "buffer_state.hpp"
+#include "random_utils.hpp"
+
+void BufferState::init( const Configuration& config )
+{
+ _Init( config );
+}
+
+BufferState::BufferState( const Configuration& config,
+ Module *parent, const string& name ) :
+Module( parent, name )
+{
+ _Init( config );
+}
+
+void BufferState::_Init( const Configuration& config )
+{
+ _buf_size = config.GetInt( "vc_buf_size" );
+ _vcs = config.GetInt( "num_vcs" );
+
+ _wait_for_tail_credit = config.GetInt( "wait_for_tail_credit" );
+
+ _in_use = new bool [_vcs];
+ _tail_sent = new bool [_vcs];
+ _cur_occupied = new int [_vcs];
+
+ _last_avail = 0;
+
+ for ( int v = 0; v < _vcs; ++v ) {
+ _in_use[v] = false;
+ _tail_sent[v] = false;
+ _cur_occupied[v] = 0;
+ }
+}
+
+BufferState::~BufferState( )
+{
+ delete [] _in_use;
+ delete [] _tail_sent;
+ delete [] _cur_occupied;
+}
+
+void BufferState::ProcessCredit( Credit *c )
+{
+ assert( c );
+
+ for ( int v = 0; v < c->vc_cnt; ++v ) {
+ assert( ( c->vc[v] >= 0 ) && ( c->vc[v] < _vcs ) );
+
+ if ( ( _wait_for_tail_credit ) &&
+ ( !_in_use[c->vc[v]] ) ) {
+ Error( "Received credit for idle buffer" );
+ }
+
+ if ( _cur_occupied[c->vc[v]] > 0 ) {
+ --_cur_occupied[c->vc[v]];
+
+ if ( ( _cur_occupied[c->vc[v]] == 0 ) &&
+ ( _tail_sent[c->vc[v]] ) ) {
+ _in_use[c->vc[v]] = false;
+ }
+ } else {
+ cout << "VC = " << c->vc[v] << endl;
+ Error( "Buffer occupancy fell below zero" );
+ }
+ }
+}
+
+void BufferState::SendingFlit( Flit *f )
+{
+ assert( f && ( f->vc >= 0 ) && ( f->vc < _vcs ) );
+
+ if ( _cur_occupied[f->vc] < _buf_size ) {
+ ++_cur_occupied[f->vc];
+
+ if ( f->tail ) {
+ _tail_sent[f->vc] = true;
+
+ if ( !_wait_for_tail_credit ) {
+ _in_use[f->vc] = false;
+ }
+ }
+ } else {
+ Error( "Flit sent to full buffer" );
+ }
+}
+
+void BufferState::TakeBuffer( int vc )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ if ( _in_use[vc] ) {
+ Error( "Buffer taken while in use" );
+ }
+
+ _in_use[vc] = true;
+ _tail_sent[vc] = false;
+}
+
+bool BufferState::IsFullFor( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return( _cur_occupied[vc] == _buf_size ) ? true : false;
+}
+
+bool BufferState::IsAvailableFor( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return !_in_use[vc];
+}
+
+int BufferState::FindAvailable( )
+{
+ int available_vc = -1;
+ int vc;
+
+ _last_avail = RandomInt( _vcs - 1 );
+
+ for ( int v = 0; v < _vcs; ++v ) {
+ vc = ( v + _last_avail + 1 ) % _vcs; // Round-robin
+
+ if ( IsAvailableFor( vc ) ) {
+ available_vc = vc;
+ _last_avail = vc;
+ break;
+ }
+ }
+
+ return available_vc;
+}
+
+void BufferState::Display( ) const
+{
+ cout << _fullname << " :" << endl;
+ for ( int v = 0; v < _vcs; ++v ) {
+ cout << " buffer class " << v << endl;
+ cout << " in_use = " << _in_use[v] << " tail_sent = " << _tail_sent[v] << endl;
+ cout << " occupied = " << _cur_occupied[v] << endl;
+ }
+}
diff --git a/src/intersim/buffer_state.hpp b/src/intersim/buffer_state.hpp new file mode 100644 index 0000000..8418f02 --- /dev/null +++ b/src/intersim/buffer_state.hpp @@ -0,0 +1,43 @@ +#ifndef _BUFFER_STATE_HPP_
+#define _BUFFER_STATE_HPP_
+
+#include "module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "config_utils.hpp"
+
+class BufferState : public Module {
+
+ int _wait_for_tail_credit;
+ int _buf_size;
+ int _vcs;
+
+ int _last_avail;
+
+ bool *_in_use;
+ bool *_tail_sent;
+ int *_cur_occupied;
+
+ void _Init( const Configuration& config );
+
+public:
+ BufferState() : Module( ) {}
+ void init( const Configuration& config );
+ BufferState( const Configuration& config,
+ Module *parent, const string& name );
+ ~BufferState( );
+
+ void ProcessCredit( Credit *c );
+ void SendingFlit( Flit *f );
+
+ void TakeBuffer( int vc = 0 );
+
+ bool IsFullFor( int vc = 0 ) const;
+ bool IsAvailableFor( int vc = 0 ) const;
+
+ int FindAvailable( );
+
+ void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/config.l b/src/intersim/config.l new file mode 100644 index 0000000..a39b2b1 --- /dev/null +++ b/src/intersim/config.l @@ -0,0 +1,51 @@ +
+%{
+
+#include "booksim.hpp"
+#include <stdlib.h>
+#include <string>
+#include <cstring>
+
+#include "config_tab.hpp"
+#include "config_utils.hpp"
+
+void configerror(string msg);
+extern "C" int configwrap() { return 1; }
+
+extern int config_input(char *, int);
+#undef YY_INPUT
+#define YY_INPUT(b, r, ms) (r = config_input(b, ms))
+
+int configlineno = 1;
+
+%}
+
+%option nounput
+
+%%
+
+ /* Ignore comments and all spaces */
+
+\/\/[^\n]* ;
+[ \t\r]* ;
+
+\n { configlineno++; }
+
+ /* Commands */
+
+[A-Za-z_][A-Za-z0-9_]* { configlval.name = strdup( yytext ); return STR; }
+
+[0-9]+ { configlval.num = strtoul( yytext, 0, 10 ); return NUM; }
+
+[0-9]+\.[0-9]+ { configlval.fnum = strtod( yytext, 0 ); return FNUM; }
+
+. { return yytext[0]; }
+
+%%
+
+void configerror( string msg )
+{
+ Configuration::GetTheConfig( )->ParseError( msg, configlineno );
+}
+
+
diff --git a/src/intersim/config.y b/src/intersim/config.y new file mode 100644 index 0000000..d2388c9 --- /dev/null +++ b/src/intersim/config.y @@ -0,0 +1,33 @@ +%{
+
+#include "booksim.hpp"
+#include <string>
+#include "config_utils.hpp"
+
+int configlex(void);
+void configerror(string msg);
+
+%}
+
+%union {
+ char *name;
+ unsigned int num;
+ double fnum;
+}
+
+%token <name> STR
+%token <num> NUM
+%token <fnum> FNUM
+
+%%
+
+commands : commands command
+ | command
+;
+
+command : STR '=' STR ';' { Configuration::GetTheConfig()->Assign( $1, $3 ); free( $1 ); free( $3 ); }
+ | STR '=' NUM ';' { Configuration::GetTheConfig()->Assign( $1, $3 ); free( $1 ); }
+ | STR '=' FNUM ';' { Configuration::GetTheConfig()->Assign( $1, $3 ); free( $1 ); }
+;
+
+%%
diff --git a/src/intersim/config_utils.cpp b/src/intersim/config_utils.cpp new file mode 100644 index 0000000..a62ea05 --- /dev/null +++ b/src/intersim/config_utils.cpp @@ -0,0 +1,176 @@ +#include "booksim.hpp"
+#include <iostream>
+#include <stdlib.h>
+#include <cstring>
+
+#include "config_utils.hpp"
+
+Configuration *Configuration::theConfig = 0;
+
+Configuration::Configuration( )
+{
+ theConfig = this;
+ _config_file = 0;
+}
+
+void Configuration::AddStrField( const string &field, const string &value )
+{
+ _str_map[field] = strdup( value.c_str( ) );
+}
+
+void Configuration::Assign( const string &field, const string &value )
+{
+ map<string,char *>::const_iterator match;
+
+ match = _str_map.find( field );
+ if ( match != _str_map.end( ) ) {
+ free( _str_map[field] );
+ _str_map[field] = strdup( value.c_str( ) );
+ } else {
+ string errmsg = "Unknown field ";
+ errmsg += field;
+
+ ParseError( errmsg, 0 );
+ }
+}
+
+void Configuration::Assign( const string &field, unsigned int value )
+{
+ map<string,unsigned int>::const_iterator match;
+
+ match = _int_map.find( field );
+ if ( match != _int_map.end( ) ) {
+ _int_map[field] = value;
+ } else {
+ string errmsg = "Unknown field ";
+ errmsg += field;
+
+ ParseError( errmsg, 0 );
+ }
+}
+
+void Configuration::Assign( const string &field, double value )
+{
+ map<string,double>::const_iterator match;
+
+ match = _float_map.find( field );
+ if ( match != _float_map.end( ) ) {
+ _float_map[field] = value;
+ } else {
+ string errmsg = "Unknown field ";
+ errmsg += field;
+
+ ParseError( errmsg, 0 );
+ }
+}
+
+void Configuration::GetStr( const string &field, string &value, const string &def ) const
+{
+ map<string,char *>::const_iterator match;
+
+ match = _str_map.find( field );
+ if ( match != _str_map.end( ) ) {
+ value = match->second;
+ } else {
+ value = def;
+ }
+}
+
+unsigned int Configuration::GetInt( const string &field, unsigned int def ) const
+{
+ map<string,unsigned int>::const_iterator match;
+ unsigned int r = def;
+
+ match = _int_map.find( field );
+ if ( match != _int_map.end( ) ) {
+ r = match->second;
+ }
+
+ return r;
+}
+
+double Configuration::GetFloat( const string &field, double def ) const
+{
+ map<string,double>::const_iterator match;
+ double r = def;
+
+ match = _float_map.find( field );
+ if ( match != _float_map.end( ) ) {
+ r = match->second;
+ }
+
+ return r;
+}
+
+void Configuration::Parse( const string& filename )
+{
+ if ( ( _config_file = fopen( filename.c_str( ), "r" ) ) == 0 ) {
+ cerr << "Could not open configuration file " << filename << endl;
+ exit( -1 );
+ }
+
+ configparse( );
+
+ fclose( _config_file );
+ _config_file = 0;
+}
+
+void Configuration::Parse( const char* filename )
+{
+ if ( ( _config_file = fopen( filename , "r" ) ) == 0 ) {
+ cerr << "Could not open configuration file " << filename << endl;
+ exit( -1 );
+ }
+
+ configparse( );
+
+ fclose( _config_file );
+ _config_file = 0;
+}
+
+
+int Configuration::Input( char *line, int max_size )
+{
+ int length = 0;
+
+ if ( _config_file ) {
+ length = fread( line, 1, max_size, _config_file );
+ }
+
+ return length;
+}
+
+void Configuration::ParseError( const string &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;
+}
+
+//============================================================
+
+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;
+
+ if ( argc > 1 ) {
+ cf->Parse( argv[1] );
+ rc = true;
+ }
+
+ return rc;
+}
diff --git a/src/intersim/config_utils.hpp b/src/intersim/config_utils.hpp new file mode 100644 index 0000000..86cc98e --- /dev/null +++ b/src/intersim/config_utils.hpp @@ -0,0 +1,45 @@ +#ifndef _CONFIG_UTILS_HPP_
+#define _CONFIG_UTILS_HPP_
+
+#include<stdio.h>
+#include<string>
+#include<map>
+
+extern int configparse( );
+
+class Configuration {
+ static Configuration *theConfig;
+ FILE *_config_file;
+
+protected:
+ map<string,char *> _str_map;
+ map<string,unsigned int> _int_map;
+ map<string,double> _float_map;
+
+public:
+ Configuration( );
+
+ void AddStrField( const string &field, const string &value );
+
+ void Assign( const string &field, const string &value );
+ void Assign( const string &field, unsigned int value );
+ void Assign( const string &field, double value );
+
+ void GetStr( const string &field, string &value, const string &def = "" ) const;
+ unsigned int GetInt( const string &field, unsigned int def = 0 ) const;
+ double GetFloat( const string &field, double def = 0.0 ) const;
+
+ void Parse( const string& filename );
+ void Parse( const char* filename );
+
+ int Input( char *line, int max_size );
+ void ParseError( const string &msg, unsigned int lineno ) const;
+
+ static Configuration *GetTheConfig( );
+};
+
+bool ParseArgs( Configuration *cf, int argc, char **argv );
+
+#endif
+
+
diff --git a/src/intersim/credit.cpp b/src/intersim/credit.cpp new file mode 100644 index 0000000..5090943 --- /dev/null +++ b/src/intersim/credit.cpp @@ -0,0 +1,16 @@ +#include "booksim.hpp"
+#include "credit.hpp"
+
+Credit::Credit( int max_vcs )
+{
+ vc = new int [max_vcs];
+ vc_cnt = 0;
+
+ tail = false;
+ id = -1;
+}
+
+Credit::~Credit( )
+{
+ delete [] vc;
+}
diff --git a/src/intersim/credit.hpp b/src/intersim/credit.hpp new file mode 100644 index 0000000..260e0d7 --- /dev/null +++ b/src/intersim/credit.hpp @@ -0,0 +1,15 @@ +#ifndef _CREDIT_HPP_
+#define _CREDIT_HPP_
+
+class Credit {
+public:
+ Credit( int max_vcs = 1 );
+ ~Credit( );
+
+ int *vc;
+ int vc_cnt;
+ bool head, tail;
+ int id;
+};
+
+#endif
diff --git a/src/intersim/doc/fancyhdr.sty b/src/intersim/doc/fancyhdr.sty new file mode 100644 index 0000000..8e12237 --- /dev/null +++ b/src/intersim/doc/fancyhdr.sty @@ -0,0 +1,329 @@ +% fancyhdr.sty version 1.99d
+% Fancy headers and footers for LaTeX.
+% Piet van Oostrum, Dept of Computer Science, University of Utrecht
+% Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands
+% Telephone: +31 30 2532180. Email: [email protected]
+% ========================================================================
+% LICENCE: This is free software. You are allowed to use and distribute
+% this software in any way you like. You are also allowed to make modified
+% versions of it, but you can distribute a modified version only if you
+% clearly indicate that it is a modified version and the person(s) who
+% modified it. This indication should be in a prominent place, e.g. in the
+% top of the file. If possible a contact address, preferably by email,
+% should be given for these persons. If that is feasible the modifications
+% should be indicated in the source code.
+% ========================================================================
+% MODIFICATION HISTORY:
+% Sep 16, 1994
+% version 1.4: Correction for use with \reversemargin
+% Sep 29, 1994:
+% version 1.5: Added the \iftopfloat, \ifbotfloat and \iffloatpage commands
+% Oct 4, 1994:
+% version 1.6: Reset single spacing in headers/footers for use with
+% setspace.sty or doublespace.sty
+% Oct 4, 1994:
+% version 1.7: changed \let\@mkboth\markboth to
+% \def\@mkboth{\protect\markboth} to make it more robust
+% Dec 5, 1994:
+% version 1.8: corrections for amsbook/amsart: define \@chapapp and (more
+% importantly) use the \chapter/sectionmark definitions from ps@headings if
+% they exist (which should be true for all standard classes).
+% May 31, 1995:
+% version 1.9: The proposed \renewcommand{\headrulewidth}{\iffloatpage...
+% construction in the doc did not work properly with the fancyplain style.
+% June 1, 1995:
+% version 1.91: The definition of \@mkboth wasn't restored on subsequent
+% \pagestyle{fancy}'s.
+% June 1, 1995:
+% version 1.92: The sequence \pagestyle{fancyplain} \pagestyle{plain}
+% \pagestyle{fancy} would erroneously select the plain version.
+% June 1, 1995:
+% version 1.93: \fancypagestyle command added.
+% Dec 11, 1995:
+% version 1.94: suggested by Conrad Hughes <[email protected]>
+% CJCH, Dec 11, 1995: added \footruleskip to allow control over footrule
+% position (old hardcoded value of .3\normalbaselineskip is far too high
+% when used with very small footer fonts).
+% Jan 31, 1996:
+% version 1.95: call \@normalsize in the reset code if that is defined,
+% otherwise \normalsize.
+% this is to solve a problem with ucthesis.cls, as this doesn't
+% define \@currsize. Unfortunately for latex209 calling \normalsize doesn't
+% work as this is optimized to do very little, so there \@normalsize should
+% be called. Hopefully this code works for all versions of LaTeX known to
+% mankind.
+% April 25, 1996:
+% version 1.96: initialize \headwidth to a magic (negative) value to catch
+% most common cases that people change it before calling \pagestyle{fancy}.
+% Note it can't be initialized when reading in this file, because
+% \textwidth could be changed afterwards. This is quite probable.
+% We also switch to \MakeUppercase rather than \uppercase and introduce a
+% \nouppercase command for use in headers. and footers.
+% May 3, 1996:
+% version 1.97: Two changes:
+% 1. Undo the change in version 1.8 (using the pagestyle{headings} defaults
+% for the chapter and section marks. The current version of amsbook and
+% amsart classes don't seem to need them anymore. Moreover the standard
+% latex classes don't use \markboth if twoside isn't selected, and this is
+% confusing as \leftmark doesn't work as expected.
+% 2. include a call to \ps@empty in ps@@fancy. This is to solve a problem
+% in the amsbook and amsart classes, that make global changes to \topskip,
+% which are reset in \ps@empty. Hopefully this doesn't break other things.
+% May 7, 1996:
+% version 1.98:
+% Added % after the line \def\nouppercase
+% May 7, 1996:
+% version 1.99: This is the alpha version of fancyhdr 2.0
+% Introduced the new commands \fancyhead, \fancyfoot, and \fancyhf.
+% Changed \headrulewidth, \footrulewidth, \footruleskip to
+% macros rather than length parameters, In this way they can be
+% conditionalized and they don't consume length registers. There is no need
+% to have them as length registers unless you want to do calculations with
+% them, which is unlikely. Note that this may make some uses of them
+% incompatible (i.e. if you have a file that uses \setlength or \xxxx=)
+% May 10, 1996:
+% version 1.99a:
+% Added a few more % signs
+% May 10, 1996:
+% version 1.99b:
+% Changed the syntax of \f@nfor to be resistent to catcode changes of :=
+% Removed the [1] from the defs of \lhead etc. because the parameter is
+% consumed by the \@[xy]lhead etc. macros.
+% June 24, 1997:
+% version 1.99c:
+% corrected \nouppercase to also include the protected form of \MakeUppercase
+% \global added to manipulation of \headwidth.
+% \iffootnote command added.
+% Some comments added about \@fancyhead and \@fancyfoot.
+% Aug 24, 1998
+% version 1.99d
+% Changed the default \ps@empty to \ps@@empty in order to allow
+% \fancypagestyle{empty} redefinition.
+
+\let\fancy@def\gdef
+
+\def\if@mpty#1#2#3{\def\temp@ty{#1}\ifx\@empty\temp@ty #2\else#3\fi}
+
+% Usage: \@forc \var{charstring}{command to be executed for each char}
+% This is similar to LaTeX's \@tfor, but expands the charstring.
+
+\def\@forc#1#2#3{\expandafter\f@rc\expandafter#1\expandafter{#2}{#3}}
+\def\f@rc#1#2#3{\def\temp@ty{#2}\ifx\@empty\temp@ty\else
+ \f@@rc#1#2\f@@rc{#3}\fi}
+\def\f@@rc#1#2#3\f@@rc#4{\def#1{#2}#4\f@rc#1{#3}{#4}}
+
+% Usage: \f@nfor\name:=list\do{body}
+% Like LaTeX's \@for but an empty list is treated as a list with an empty
+% element
+
+\newcommand{\f@nfor}[3]{\edef\@fortmp{#2}%
+ \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}}
+
+% Usage: \def@ult \cs{defaults}{argument}
+% sets \cs to the characters from defaults appearing in argument
+% or defaults if it would be empty. All characters are lowercased.
+
+\newcommand\def@ult[3]{%
+ \edef\temp@a{\lowercase{\edef\noexpand\temp@a{#3}}}\temp@a
+ \def#1{}%
+ \@forc\tmpf@ra{#2}%
+ {\expandafter\if@in\tmpf@ra\temp@a{\edef#1{#1\tmpf@ra}}{}}%
+ \ifx\@empty#1\def#1{#2}\fi}
+%
+% \if@in <char><set><truecase><falsecase>
+%
+\newcommand{\if@in}[4]{%
+ \edef\temp@a{#2}\def\temp@b##1#1##2\temp@b{\def\temp@b{##1}}%
+ \expandafter\temp@b#2#1\temp@b\ifx\temp@a\temp@b #4\else #3\fi}
+
+\newcommand{\fancyhead}{\@ifnextchar[{\f@ncyhf h}{\f@ncyhf h[]}}
+\newcommand{\fancyfoot}{\@ifnextchar[{\f@ncyhf f}{\f@ncyhf f[]}}
+\newcommand{\fancyhf}{\@ifnextchar[{\f@ncyhf {}}{\f@ncyhf {}[]}}
+
+% The header and footer fields are stored in command sequences with
+% names of the form: \f@ncy<x><y><z> with <x> for [eo], <y> form [lcr]
+% and <z> from [hf].
+
+\def\f@ncyhf#1[#2]#3{%
+ \def\temp@c{}%
+ \@forc\tmpf@ra{#2}%
+ {\expandafter\if@in\tmpf@ra{eolcrhf,EOLCRHF}%
+ {}{\edef\temp@c{\temp@c\tmpf@ra}}}%
+ \ifx\@empty\temp@c\else
+ \ifx\PackageError\undefined
+ \errmessage{Illegal char `\temp@c' in fancyhdr argument:
+ [#2]}\else
+ \PackageError{Fancyhdr}{Illegal char `\temp@c' in fancyhdr argument:
+ [#2]}{}\fi
+ \fi
+ \f@nfor\temp@c{#2}%
+ {\def@ult\f@@@eo{eo}\temp@c
+ \def@ult\f@@@lcr{lcr}\temp@c
+ \def@ult\f@@@hf{hf}{#1\temp@c}%
+ \@forc\f@@eo\f@@@eo
+ {\@forc\f@@lcr\f@@@lcr
+ {\@forc\f@@hf\f@@@hf
+ {\expandafter\fancy@def\csname
+ f@ncy\f@@eo\f@@lcr\f@@hf\endcsname
+ {#3}}}}}}
+
+% Fancyheadings version 1 commands. These are more or less deprecated,
+% but they continue to work.
+
+\newcommand{\lhead}{\@ifnextchar[{\@xlhead}{\@ylhead}}
+\def\@xlhead[#1]#2{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#2}}
+\def\@ylhead#1{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#1}}
+
+\newcommand{\chead}{\@ifnextchar[{\@xchead}{\@ychead}}
+\def\@xchead[#1]#2{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#2}}
+\def\@ychead#1{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#1}}
+
+\newcommand{\rhead}{\@ifnextchar[{\@xrhead}{\@yrhead}}
+\def\@xrhead[#1]#2{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#2}}
+\def\@yrhead#1{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#1}}
+
+\newcommand{\lfoot}{\@ifnextchar[{\@xlfoot}{\@ylfoot}}
+\def\@xlfoot[#1]#2{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#2}}
+\def\@ylfoot#1{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#1}}
+
+\newcommand{\cfoot}{\@ifnextchar[{\@xcfoot}{\@ycfoot}}
+\def\@xcfoot[#1]#2{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#2}}
+\def\@ycfoot#1{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#1}}
+
+\newcommand{\rfoot}{\@ifnextchar[{\@xrfoot}{\@yrfoot}}
+\def\@xrfoot[#1]#2{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#2}}
+\def\@yrfoot#1{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#1}}
+
+\newdimen\headwidth
+\newcommand{\headrulewidth}{0.4pt}
+\newcommand{\footrulewidth}{\z@skip}
+\newcommand{\footruleskip}{.3\normalbaselineskip}
+
+% Fancyplain stuff shouldn't be used anymore (rather
+% \fancypagestyle{plain} should be used), but it must be present for
+% compatibility reasons.
+
+\newcommand{\plainheadrulewidth}{\z@skip}
+\newcommand{\plainfootrulewidth}{\z@skip}
+\newif\if@fancyplain \@fancyplainfalse
+\def\fancyplain#1#2{\if@fancyplain#1\else#2\fi}
+
+\headwidth=-123456789sp %magic constant
+
+% Command to reset various things in the headers:
+% a.o. single spacing (taken from setspace.sty)
+% and the catcode of ^^M (so that epsf files in the header work if a
+% verbatim crosses a page boundary)
+% It also defines a \nouppercase command that disables \uppercase and
+% \Makeuppercase. It can only be used in the headers and footers.
+\def\fancy@reset{\restorecr
+ \def\baselinestretch{1}%
+ \def\nouppercase##1{{\let\uppercase\relax\let\MakeUppercase\relax
+ \expandafter\let\csname MakeUppercase \endcsname\relax##1}}%
+ \ifx\undefined\@newbaseline% NFSS not present; 2.09 or 2e
+ \ifx\@normalsize\undefined \normalsize % for ucthesis.cls
+ \else \@normalsize \fi
+ \else% NFSS (2.09) present
+ \@newbaseline%
+ \fi}
+
+% Initialization of the head and foot text.
+
+% The default values still contain \fancyplain for compatibility.
+\fancyhf{} % clear all
+% lefthead empty on ``plain'' pages, \rightmark on even, \leftmark on odd pages
+% evenhead empty on ``plain'' pages, \leftmark on even, \rightmark on odd pages
+\fancyhead[el,or]{\fancyplain{}{\sl\rightmark}}
+\fancyhead[er,ol]{\fancyplain{}{\sl\leftmark}}
+\fancyfoot[c]{\rm\thepage} % page number
+
+% Put together a header or footer given the left, center and
+% right text, fillers at left and right and a rule.
+% The \lap commands put the text into an hbox of zero size,
+% so overlapping text does not generate an errormessage.
+% These macros have 5 parameters:
+% 1. \@lodd or \@rodd % This determines at which side the header will stick
+% out.
+% 2. \f@ncyolh, \f@ncyelh, \f@ncyolf or \f@ncyelf. This is the left component.
+% 3. \f@ncyoch, \f@ncyech, \f@ncyocf or \f@ncyecf. This is the middle comp.
+% 4. \f@ncyorh, \f@ncyerh, \f@ncyorf or \f@ncyerf. This is the right component.
+% 5. \@lodd or \@rodd % This determines at which side the header will stick
+% out. This is the reverse of parameter nr. 1. One of them is always
+% \relax and the other one is \hss (after expansion).
+
+\def\@fancyhead#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\hbox
+{\rlap{\parbox[b]{\headwidth}{\raggedright#2\strut}}\hfill
+\parbox[b]{\headwidth}{\centering#3\strut}\hfill
+\llap{\parbox[b]{\headwidth}{\raggedleft#4\strut}}}\headrule}}#5}
+
+\def\@fancyfoot#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\footrule
+\hbox{\rlap{\parbox[t]{\headwidth}{\raggedright#2\strut}}\hfill
+\parbox[t]{\headwidth}{\centering#3\strut}\hfill
+\llap{\parbox[t]{\headwidth}{\raggedleft#4\strut}}}}}#5}
+
+\def\headrule{{\if@fancyplain\let\headrulewidth\plainheadrulewidth\fi
+\hrule\@height\headrulewidth\@width\headwidth \vskip-\headrulewidth}}
+
+\def\footrule{{\if@fancyplain\let\footrulewidth\plainfootrulewidth\fi
+\vskip-\footruleskip\vskip-\footrulewidth
+\hrule\@width\headwidth\@height\footrulewidth\vskip\footruleskip}}
+
+\def\ps@fancy{%
+\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}%for amsbook
+%
+% Define \MakeUppercase for old LaTeXen.
+% Note: we used \def rather than \let, so that \let\uppercase\relax (from
+% the version 1 documentation) will still work.
+%
+\@ifundefined{MakeUppercase}{\def\MakeUppercase{\uppercase}}{}%
+\@ifundefined{chapter}{\def\sectionmark##1{\markboth
+{\MakeUppercase{\ifnum \c@secnumdepth>\z@
+ \thesection\hskip 1em\relax \fi ##1}}{}}%
+\def\subsectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne
+ \thesubsection\hskip 1em\relax \fi ##1}}}%
+{\def\chaptermark##1{\markboth {\MakeUppercase{\ifnum \c@secnumdepth>\m@ne
+ \@chapapp\ \thechapter. \ \fi ##1}}{}}%
+\def\sectionmark##1{\markright{\MakeUppercase{\ifnum \c@secnumdepth >\z@
+ \thesection. \ \fi ##1}}}}%
+%\csname ps@headings\endcsname % use \ps@headings defaults if they exist
+\ps@@fancy
+\gdef\ps@fancy{\@fancyplainfalse\ps@@fancy}%
+% Initialize \headwidth if the user didn't
+%
+\ifdim\headwidth<0sp
+%
+% This catches the case that \headwidth hasn't been initialized and the
+% case that the user added something to \headwidth in the expectation that
+% it was initialized to \textwidth. We compensate this now. This loses if
+% the user intended to multiply it by a factor. But that case is more
+% likely done by saying something like \headwidth=1.2\textwidth.
+% The doc says you have to change \headwidth after the first call to
+% \pagestyle{fancy}. This code is just to catch the most common cases were
+% that requirement is violated.
+%
+ \global\advance\headwidth123456789sp\global\advance\headwidth\textwidth
+\fi}
+\def\ps@fancyplain{\ps@fancy \let\ps@plain\ps@plain@fancy}
+\def\ps@plain@fancy{\@fancyplaintrue\ps@@fancy}
+\let\ps@@empty\ps@empty
+\def\ps@@fancy{%
+\ps@@empty % This is for amsbook/amsart, which do strange things with \topskip
+\def\@mkboth{\protect\markboth}%
+\def\@oddhead{\@fancyhead\@lodd\f@ncyolh\f@ncyoch\f@ncyorh\@rodd}%
+\def\@oddfoot{\@fancyfoot\@lodd\f@ncyolf\f@ncyocf\f@ncyorf\@rodd}%
+\def\@evenhead{\@fancyhead\@rodd\f@ncyelh\f@ncyech\f@ncyerh\@lodd}%
+\def\@evenfoot{\@fancyfoot\@rodd\f@ncyelf\f@ncyecf\f@ncyerf\@lodd}%
+}
+\def\@lodd{\if@reversemargin\hss\else\relax\fi}
+\def\@rodd{\if@reversemargin\relax\else\hss\fi}
+
+\newif\iffootnote
+\let\latex@makecol\@makecol
+\def\@makecol{\ifvoid\footins\footnotetrue\else\footnotefalse\fi
+\let\topfloat\@toplist\let\botfloat\@botlist\latex@makecol}
+\def\iftopfloat#1#2{\ifx\topfloat\empty #2\else #1\fi}
+\def\ifbotfloat#1#2{\ifx\botfloat\empty #2\else #1\fi}
+\def\iffloatpage#1#2{\if@fcolmade #1\else #2\fi}
+
+\newcommand{\fancypagestyle}[2]{%
+ \@namedef{ps@#1}{\let\fancy@def\def#2\relax\ps@fancy}}
diff --git a/src/intersim/doc/manual.pdf b/src/intersim/doc/manual.pdf Binary files differnew file mode 100644 index 0000000..c12aa4a --- /dev/null +++ b/src/intersim/doc/manual.pdf diff --git a/src/intersim/doc/manual.tex b/src/intersim/doc/manual.tex new file mode 100644 index 0000000..2ec6726 --- /dev/null +++ b/src/intersim/doc/manual.tex @@ -0,0 +1,687 @@ +\documentclass[11pt]{article}
+\usepackage{fancyhdr}
+\usepackage[dvips]{graphicx}
+\usepackage{amsmath,amssymb}
+\usepackage{epsfig}
+\usepackage{calc}
+
+\newcommand{\simname}{BookSim~}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Setup the margin sizes.
+
+\evensidemargin = 0in
+\oddsidemargin = 0in
+\textwidth = 6.5in
+
+\topmargin = -0.5in
+\textheight = 9in
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\author{Brian Towles and William J. Dally}
+\title{\simname 1.0 User's Guide}
+
+\begin{document}
+
+\maketitle
+\tableofcontents
+
+\pagestyle{fancy}
+%\renewcommand{\chaptermark}[1]{\markboth{#1}{}}
+\renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}}
+\fancyhf{} % delete current setting for header and footer
+\fancyhead[LE,RO]{\bfseries\thepage}
+\fancyhead[LO]{\bfseries\rightmark}
+\fancyhead[RE]{\bfseries\leftmark}
+\renewcommand{\headrulewidth}{0.5pt}
+\renewcommand{\footrulewidth}{0.5pt}
+\addtolength{\headheight}{0.5pt} % make space for the rule
+\cfoot{\small\today}
+\fancypagestyle{plain}{%
+ \fancyhf{} % get rid of headers on plain pages
+ \renewcommand{\headrulewidth}{0pt} % and the line
+ \renewcommand{\footrulewidth}{0pt} % and the line
+}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newenvironment{opt_list}[1]{\begin{list}{}{\renewcommand{\makelabel}[1]%
+{\texttt{##1}\hfil}\settowidth{\labelwidth}{\texttt{#1}}\setlength{\leftmargin}%
+{\labelwidth+\labelsep}}}{\end{list}}
+
+\section{Introduction}
+
+This document describes the use of the \simname interconnection
+network simulator. The simulator is designed as a companion to the
+textbook ``Principles and Practices of Interconnection Networks''
+(PPIN) published by Morgan Kaufmann (ISBN: 0122007514) and it is
+assumed that is reader is familiar with the material covered in that
+text.
+
+This user guide is fairly brief as, with most simulators, the best way
+to learn and {\it understand} the simulator is to study the code.
+Most of the simulator's components are designed to be modular so tasks
+such as adding a new routing algorithm, topology, or router
+microarchitecture should not require a complete redesign of the code.
+Once you have downloaded the code, compiled it, and run a simple
+example (Section~\ref{sec:get_started}), the more detailed examples of
+Section~\ref{sec:examples} give a good overview of the capabilities of
+the simulator. A list of configuration options is provided in
+Section~\ref{sec:config_params} for reference.
+
+\section{Getting started}
+\label{sec:get_started}
+
+\subsection{Downloading and building the simulator}
+\label{sec:download}
+
+The latest version of the simulator is available from
+\texttt{http://cva.stanford.edu} as a compressed tar archive. UNIX/Linux
+users can extract this archive using the tar utility
+\begin{verbatim}
+ tar xvfz booksim-1.0.tar.gz
+\end{verbatim}
+Windows users can use a compression program such as WinZip to extract
+the archive.
+
+The simulator itself is written in C++ and has been specifically
+tested with GNU's G++ compiler (version $\ge3$). In addition, both a
+LEX and YACC tool (also known as FLEX and BISON) are needed to create
+the configuration parser. These are standard tools in any UNIX/Linux
+development environment. It is suggested that Windows users download
+the CYGWIN versions (\texttt{http://www.cygwin.com}) of these UNIX
+development tools to simplify their compilation process. The
+\texttt{Makefile} should be edited so that the first lines give the
+paths to the tools. At Stanford, for example, the compiler, YACC, and
+LEX are stored in the \texttt{/usr/pubsw/bin} directory. The
+\texttt{Makefile} reflects this:
+\begin{verbatim}
+CPP = /usr/pubsw/bin/g++
+YACC = /usr/pubsw/bin/byacc -d
+LEX = /usr/pubsw/bin/flex
+\end{verbatim}
+Then, the simulator can be compiled by running \texttt{make} in the
+directory that contains the \texttt{Makefile}.
+
+\subsection{Running a simulation}
+\label{sec:run_example}
+
+The syntax of the simulator is simply
+\begin{verbatim}
+ booksim [configfile]
+\end{verbatim}
+The optional parameter \texttt{configfile} is a file that contains
+configuration information for the simulator. So, for example, to
+simulate the performance of a simple $8 \times 8$ torus (8-ary 2-cube)
+network on uniform traffic, a configuration such as the one shown in
+Figure~\ref{fig:config_example} could be used. This particular
+configuration is stored in \texttt{examples/torus88}.
+
+\begin{figure}
+\begin{verbatim}
+ // Topology
+ topology = torus;
+ k = 8;
+ n = 2;
+
+ // Routing
+ routing_function = dim_order;
+
+ // Flow control
+ num_vcs = 2;
+
+ // Traffic
+ traffic = uniform;
+ injection_rate = 0.15;
+\end{verbatim}
+\caption{Example configuration file for simulating a 8-ary 2-cube
+network.}
+\label{fig:config_example}
+\end{figure}
+
+In addition to specifying the topology, the configuration file also
+contains basic information about the routing algorithm, flow control,
+and traffic. This simple example uses dimension-order routing and, to
+ensure deadlock-freedom of this routing function in the torus, two
+virtual channels are required. The \texttt{injection\_rate} parameter
+is added to tell the simulator to inject 0.15 flits per simulation
+cycle per node. Because the simulator operates at the flit level,
+most parameters are specified in units of flits as is the case with
+the \texttt{injection\_rate}. Also, any line of the configuration
+that begins with \texttt{//} is treated as a comment and ignored by
+the simulator. A detailed list of configuration parameters is given in
+Section~\ref{sec:config_params}.
+
+\subsection{Simulation output}
+
+Continuing our example, running the torus simulation produces the
+output shown in Figure~\ref{fig:sim_output}. Each simulation has
+three basic phases: warm up, measurement, and drain. The length of
+the warm up and measurement phases is a multiple of a basic sample
+period (defined by \texttt{sample\_period} in the configuration). As
+shown in the figure, the current latency and throughput (rate of
+accepted packets) for the simulation is printed after each sample
+period. The overall throughput is determined by the lowest throughput
+of all the destination in the network, but the average throughput is
+also displayed.
+
+\begin{figure}
+\begin{verbatim}
+%=================================
+% Average latency = 6.02008
+% Accepted packets = 0.11 at node 52 (avg = 0.147094)
+% latency change = 1
+% throughput change = 1
+
+...
+
+% Warmed up ...
+%=================================
+% Average latency = 6.0796
+% Accepted packets = 0.119 at node 5 (avg = 0.148266)
+% latency change = 0.00562457
+% throughput change = 0.00379387
+
+...
+
+% Draining all recorded packets ...
+% Draining remaining packets ...
+====== Traffic class 0 ======
+Overall average latency = 6.09083 (1 samples)
+Overall average accepted rate = 0.149475 (1 samples)
+Overall min accepted rate = 0.138551 (1 samples)
+\end{verbatim}
+\caption{Simulator output from running the \texttt{examples/torus88}
+configuration file.}
+\label{fig:sim_output}
+\end{figure}
+
+After the warm up periods have passed, the simulator prints the
+``\texttt{Warmed up}'' message and resets all the simulation statistics.
+Then, the measurement phase begins and statistics continue to be
+reported after each sample period. Once the measurement periods have
+passed, all the measurement packets are drained from the network
+before final latency and throughput numbers are reported. Details of
+the configuration parameters used to control the length of the
+simulation phases are covered in Section~\ref{sec:sim_params}.
+
+\section{Examples}
+\label{sec:examples}
+
+One of the most basic performance measures of any interconnection
+network is its latency versus offered load.
+Figure~\ref{fig:lat_vs_load} shows a simple configuration file for
+making this measurement in a 8-ary 2-mesh network under the transpose
+traffic pattern. This configuration was used to generate Figure 25.2
+in PPIN. The particular configuration accounts for some small delays
+and pipelining of the input-queued router and also introduces a small
+input speedup to account for any inefficiencies in allocation. By
+running simulations for many increments of \texttt{injection\_rate},
+the average latency curve can be found. Then, to compare the
+performance of dimension-order routing against several other routing
+algorithms, for example, the \texttt{routing\_function} option can be
+changed.
+
+\begin{figure}
+\begin{verbatim}
+// Topology
+
+topology = mesh;
+k = 8;
+n = 2;
+
+// Routing
+
+routing_function = dim_order;
+
+// 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 = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = transpose;
+const_flits_per_packet = 20;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
+\end{verbatim}
+\caption{A typical configuration file (\texttt{examples/mesh88\_lat})
+for creating a latency versus offered load curve for a 8-ary 2-mesh
+network.}
+\label{fig:lat_vs_load}
+\end{figure}
+
+Figure~\ref{fig:fly_dist} shows a configuration file that can be used
+to determine the distribution of packet latencies in a 2-ary 6-fly
+network that uses age-based arbitration. Note the use of the
+\texttt{priority} configuration parameter along with the
+\texttt{select} allocators that account for packet priorities. The
+simulator does not output latency distributions by default, but by
+editing \texttt{trafficmanager.cpp}, setting the configuration
+variable \texttt{DISPLAY\_LAT\_DIST} to true, and recompiling, the
+distribution will be displayed at the end of the simulation. This
+technique was used to produced the distribution shown in Figure 25.12
+of PPIN.
+
+\begin{figure}
+\begin{verbatim}
+// Topology
+
+topology = fly;
+k = 2;
+n = 6;
+
+// Routing
+
+routing_function = dest_tag;
+
+// Flow control
+
+num_vcs = 8;
+vc_buf_size = 8;
+
+wait_for_tail_credit = 1;
+
+// Router architecture
+
+vc_allocator = select;
+sw_allocator = select;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = uniform;
+const_flits_per_packet = 20;
+priority = age;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
+\end{verbatim}
+\caption{A configuration file (\texttt{examples/fly26\_age}) for
+finding the distribution of packet latencies using age-based
+arbitration.}
+\label{fig:fly_dist}
+\end{figure}
+
+As a final example, Figure~\ref{fig:single} shows the use of the
+special single-node topology to test the performance of a switch
+allocator --- in this case, the iSLIP allocator. The
+\texttt{in\_ports} and \texttt{out\_ports} options set up a simulation
+of an $8\times 8$ crossbar.
+
+\begin{figure}
+\begin{verbatim}
+// Topology
+
+topology = single;
+in_ports = 8;
+out_ports = 8;
+
+// Routing
+
+routing_function = single;
+
+// Flow control
+
+vc_allocator = islip;
+sw_allocator = islip;
+alloc_iters = 2;
+
+num_vcs = 8;
+vc_buf_size = 1000;
+
+wait_for_tail_credit = 0;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
+\end{verbatim}
+\caption{A single-node configuration file (\texttt{examples/single})
+for testing the performance of a switch allocator.}
+\label{fig:single}
+\end{figure}
+
+\section{Configuration parameters}
+\label{sec:config_params}
+
+All information used to configure a simulation is passed through a
+configuration file as illustrated by the example in
+Section~\ref{sec:run_example}. This section lists the existing
+configuration parameters --- a user can incorporate additional options
+by changing the \texttt{booksim\_config.cpp} file.
+
+\subsection{Topologies}
+\label{sec:topos}
+
+The \texttt{topology} parameter determines the underlying topology of the
+network and the simulator supports four basic topologies:
+\begin{opt_list}{single}
+\item[fly] A $k$-ary $n$-fly (butterfly) topology. The \texttt{k}
+parameter determines the network's radix and the \texttt{n} parameter
+determines the network's dimension.
+
+\item[mesh] A $k$-ary $n$-mesh (mesh) topology. The \texttt{k}
+parameter determines the network's radix and the \texttt{n} parameter determines
+the network's dimension.
+
+\item[single] A network with a single node, used for testing single
+router performance. The number of input and output ports for the node
+is determined by the \texttt{in\_ports} and \texttt{out\_ports} parameters,
+respectively.
+
+\item[torus] A $k$-ary $n$-cube (torus) topology. The \texttt{k}
+parameter determines the network's radix and the \texttt{n} parameter determines
+the network's dimension.
+\end{opt_list}
+
+Both the \texttt{mesh} and \texttt{torus} topologies support the
+addition of random link failures with the \texttt{link\_failures}
+parameter. The value of \texttt{link\_failures} determines the number
+of channels that are randomly removed from the topology and are thus
+no longer available for forwarding packets. Moreover, the
+randomization for failed channels is controlled by selecting an
+integer value for the \texttt{fail\_seed} parameter --- a fixed seed
+gives a fixed set of failed channels, independent of other
+randomization in the simulation. Also, note that only certain routing
+functions support this feature (see Section~\ref{sec:routing_algs}).
+
+\subsection{Routing algorithms}
+\label{sec:routing_algs}
+
+The \texttt{routing\_function} parameter selects a routing algorithm
+for the topology. Many routing algorithms need multiple virtual
+channels for deadlock freedom (VCDF).
+
+\begin{opt_list}{dim\_order\_bal}
+
+\item[dim\_order] Dimension-order routing. Works for the
+\texttt{mesh} topology (1 VCDF) and for the \texttt{torus} topology (2
+VCDF).
+
+\item[dim\_order\_bal] Dimension-order routing for the
+\texttt{torus} topology with a more balanced use of VCs to
+avoid deadlock (2 VCDF).
+
+\item[dim\_order\_ni] A non-interfering version of
+dimension-order routing. Works on the \texttt{torus} or \texttt{mesh}
+topology and requires one VC per network terminal.
+
+\item[min\_adapt] A minimal adaptive routing algorithm for
+the \texttt{mesh} topology (2 VCDF) and for the \texttt{torus}
+topology (3 VCDF).
+
+\item[planar\_adapt] Planar-adaptive routing for the
+\texttt{mesh} topology (2 VCDF). Supports routing around failed channels.
+
+\item[romm] ROMM routing for the \texttt{mesh} (2 VCDF).
+Load is balanced by routing in two phases: one from the source to a
+random intermediate node in the minimal quadrant and a second from the
+intermediate to the destination.
+
+\item[romm\_ni] A non-interfering version of ROMM routing for
+the \texttt{mesh} that requires one VC per network terminal.
+
+\item[single] A dummy routing function used for the
+\texttt{single} topology.
+
+\item[valiant] Valiant's randomized routing algorithm for the
+\texttt{mesh} (2 VCDF) and \texttt{torus} (4 VCDF) topology.
+
+\item[valiant\_ni] A non-interfering version of Valiant's algorithm
+for the \texttt{torus} that requires 4 VCs per network terminal.
+
+\end{opt_list}
+
+Also, the simulator code is structured so that additional routing
+algorithms can be added with minimal changes to the overall simulator
+(see the \texttt{routefunc.cpp} file in the simulator's source code).
+
+\subsection{Flow control}
+
+The simulator supports basic virtual-channel flow control with
+credit-based backpressure.
+
+\begin{opt_list}{wait\_for\_tail\_credit}
+
+\item[num\_vcs] The number of virtual channels per physical channel.
+
+\item[vc\_buf\_size] The depth of each virtual in flits.
+
+\item[voq] If non-zero, use virtual-output queuing. With virtual
+output queuing, a separate virtual channel is assigned to each
+destination in the network. This option is most useful when used with
+a non-interfering routing algorithm (Section~\ref{sec:routing_algs}).
+
+\item[wait\_for\_tail\_credit] If non-zero, do not reallocate a virtual
+channel until the tail flit has left that virtual channel. This
+conservative approach prevents a dependency from being formed between
+two packets sharing the same virtual channel in succession.
+\end{opt_list}
+
+\subsection{Router organizations}
+
+The simulator also supports two different router microarchitectures.
+The input-queued router follows the general organization described in
+PPIN while the event-driven router is modeled after the router used in
+the Avici TSR and described in U.S. Patent 6,370,145. The
+microarchitecture is selected using the \texttt{router} option. Also,
+both routers share a small set of options.
+
+\begin{opt_list}{internal\_speedup}
+\item[credit\_delay] The processing delay (in cycles) for a credit.
+Does not include the wire delay for transmitting the credit.
+
+\item[internal\_speedup] An arbitrary speedup of the internals of the
+routers over the channel transmission rate. For example, a speedup
+1.5 means that, on average, 1.5 flits can be forwarded by the router
+in the time required for a single flit to be transmitted across a
+channel. Also, the configuration parser expects a floating point
+number for this field, so integer speedups should also include a
+decimal point (e.g. ``2.0'').
+
+\item[output\_delay] The processing delay incurred in the output queue
+of a router.
+\end{opt_list}
+
+\subsubsection{The input-queued router}
+\label{sec:iq_router}
+
+The input-queued router (\texttt{router = iq}) follows the pipeline
+described in PPIN of route computation, virtual-channel allocation,
+switch allocation, and switch traversal. There are several options
+specific to the input-queued router.
+
+\begin{opt_list}{st\_prepare\_delay}
+
+\item[input\_speedup] An integer speedup of the input ports in space.
+A speedup of 2, for example, gives each input two input ports into the
+crossbar. Access to these ports is statically allocated based on the
+virtual channel number: virtual channel $v$ at input $i$ is connected
+to port $i \cdot s + (v \mod s)$ for an input speedup of $s$.
+
+\item[output\_speedup] An integer speedup of the output ports in
+space. Similar to \texttt{input\_speedup}
+
+\item[routing\_delay] The delay (in cycles) of route computation.
+
+\item[sw\_allocator] The type of allocator used for switch allocation.
+See Section~\ref{sec:alloc} for a list of the possible allocators.
+
+\item[sw\_alloc\_delay] The delay (in cycles) of switch allocation.
+
+\item[vc\_allocator] The type of allocator used for virtual-channel
+allocation. See Section~\ref{sec:alloc} for a list of the possible
+allocators.
+
+\item[vc\_alloc\_delay] The delay (in cycles) of virtual-channel
+allocation.
+
+\end{opt_list}
+
+\subsubsection{The event-driven router}
+\label{sec:event_router}
+
+The event-driven router (\texttt{router = event}) is a
+microarchitecture designed specifically to support a large number of
+virtual channels (VCs) efficiently. Instead of continuously polling
+the state of the virtual channels, as in the input-queued router, only
+changes in VC state are tracked. The efficiency then comes from the
+fact that the number of state changes per cycle is constant and
+independent of the number of VCs.
+
+\subsection{Allocators}
+\label{sec:alloc}
+
+Many of the allocators used in the simulator are configurable (see
+the input-queued router in Section~\ref{sec:iq_router}) and several
+allocation algorithms are available.
+\begin{opt_list}{wavefront}
+
+\item[max\_size] Maximum-size matching.
+\item[islip] iSLIP separable allocator.
+\item[pim] Parallel iterative matching separable allocator.
+\item[loa] Lonely output allocator.
+\item[wavefront] Wavefront matching.
+\item[select] Priority-based allocator. Allocation is performed as in
+iSLIP, but with preference towards higher priority packets (see
+\texttt{priority} option in Section~\ref{sec:traffic}).
+
+\end{opt_list}
+
+Allocation can also be improved by performing multiple iterations of
+the algorithm and the number of iterations is controlled by the
+\texttt{alloc\_iters} parameter.
+
+\subsection{Traffic}
+\label{sec:traffic}
+
+The rate at which flits are injected into the simulator is set using
+the \texttt{injection\_rate} option. The simulator's cycle time is a
+flit cycle, the time it takes a single flit to be injected at a
+source, and the injection rate is specified in flits per flit cycle.
+For example, setting \texttt{injection\_rate = 0.25} means that each
+source injects a new flit one of every four simulator cycles. The
+injection process can also be specified as either Bernoulli
+(\texttt{injection\_process = bernoulli}) or an on-off process
+(\texttt{injection\_process = on\_off}). The burstiness of the latter
+injection process is controlled via the \texttt{burst\_alpha} and
+\texttt{burst\_beta} parameter. See PPIN Section 24.2.2 for a
+description of the on-off process and its parameters.
+
+The unit of injection is packets, which may be comprised of many
+flits. The number of flits per packet is set using the
+\texttt{const\_flits\_per\_packet} option. Each packet may also have an
+associated priority, either age-based (\texttt{age}) or none
+(\texttt{none}), as specified by the \texttt{priority} option.
+
+The simulator also supports several different traffic patterns that
+are specified using the \texttt{traffic} option. To describe these
+patterns, we use the same notation of PPIN Section 3.2: $s_i$ ($d_i$)
+denotes the $i^\textrm{th}$ bit of the source (destination) address
+whereas $s_x$ ($d_x$) denotes the $x^\textrm{th}$ radix-$k$ digit of
+the source (destination) address. The bit length of an address is $b
+= \log_2 N$, where $N$ is the number of nodes in the network.
+
+\begin{opt_list}{transpose}
+\item[uniform] Each source sends an equal amount of traffic to each
+destination (\texttt{traffic = uniform}).
+\item[bitcomp] Bit complement. $d_i = \neg s_i$.
+\item[bitrev] Bit reverse. $d_i = s_{b-i-1}$.
+\item[shuffle] $d_i = s_{i-1 \mod b}$.
+\item[transpose] $d_i = s_{i+b/2 \mod b}$.
+\item[tornado] $d_x = s_x + \lceil k/2 \rceil - 1 \mod k$.
+\item[neighbor] $d_x = s_x + 1 \mod k$.
+\item[randperm] Random permutation. A fixed permutation traffic
+pattern is chosen uniformly at random from the set of all
+permutations. The seed used to generate this permutation is set by
+the \texttt{perm\_seed} option. So, randomly selecting values for
+\texttt{perm\_seed} gives a random sampling of permutation while a
+fixed value of \texttt{perm\_seed} allows the same permutation to be
+used for several experiments.
+\end{opt_list}
+
+\subsection{Simulation parameters}
+\label{sec:sim_params}
+
+The duration and other aspects of a simulation are controlled using
+the set of simulation parameters.
+
+\begin{opt_list}{warmup\_periods}
+
+\item[sim\_type] A simulation can either focus on
+\texttt{throughput} or \texttt{latency}. The key difference between
+these two types is that a \texttt{latency} simulation will wait for
+all measurement packets to drain before ending the simulation to
+ensure an accurate latency measurement. In \texttt{throughput}
+simulations, this final drain step is eliminated to allow simulation
+of networks operating beyond their saturation point.
+
+\item[sample\_period] The sample period is expressed in simulator
+cycles and is used as a multiplier when specifying the warm-up length
+of a simulation and the maximum number of samples. Also, intermediate
+statistics are displayed once every \texttt{sample\_period} cycles.
+
+\item[warmup\_periods] The length of the simulator warm up expressed
+as a multiple of the \texttt{sample\_period}. After warming up, all
+statistics counters are reset.
+
+\item[max\_samples] The total length of simulation expressed as a
+multiple of the \texttt{sample\_period}.
+
+\item[latency\_thres] If the sampled latency of the current simulation
+exceeds \texttt{latency\_thres}, the simulation is immediately ended.
+
+\item[sim\_count] The number of back-to-back simulations to run for the
+given configuration. Useful for creating ensemble averages of
+particular statistics.
+
+\item[seed] A random seed for the simulation.
+
+\item[reorder] A non-zero value indicates that packet order should be
+maintained and reordering time is accounted for in the overall latency.
+
+\end{opt_list}
+
+\appendix
+
+\section{Random number generation}
+
+The simulator uses Knuth's integer and floating point pseudorandom
+number generators. These algorithms and their explanations appear in
+``The Art of Computer Programming: Seminumerical Algorithms''.
+
+\end{document}
\ No newline at end of file diff --git a/src/intersim/event_router.cpp b/src/intersim/event_router.cpp new file mode 100644 index 0000000..09172cd --- /dev/null +++ b/src/intersim/event_router.cpp @@ -0,0 +1,923 @@ +#include <string>
+#include <sstream>
+#include <iostream>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "event_router.hpp"
+#include "stats.hpp"
+
+EventRouter::EventRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs )
+: Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ ostringstream module_name;
+
+ _vcs = config.GetInt( "num_vcs" );
+ _vc_size = config.GetInt( "vc_buf_size" );
+
+ // 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
+
+ _rf = GetRoutingFunction( config );
+
+ // Alloc VC's
+
+ _vc = new VC * [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _vc[i] = new VC [_vcs];
+ for( int j=0; j < _vcs; ++j ) {
+ _vc[i][j].init( config, _outputs );
+ }
+
+ for ( int v = 0; v < _vcs; ++v ) { // Name the vc modules
+ module_name << "vc_i" << i << "_v" << v;
+ _vc[i][v].SetName( this, module_name.str( ) );
+ module_name.seekp( 0, ios::beg );
+ }
+ }
+
+ // Alloc next VCs' state
+
+ _output_state = new EventNextVCState [_outputs];
+ for( int j=0; j < _outputs; ++j ) {
+ _output_state[j].init( config );
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ module_name << "output" << o << "_vc_state";
+ _output_state[o].SetName( this, module_name.str( ) );
+ module_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc arbiters
+
+ _arrival_arbiter = new PriorityArbiter * [_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 = new PriorityArbiter * [_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,
+ _st_prepare_delay + _st_final_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 = new queue<Flit *> [_inputs];
+ _output_buffer = new queue<Flit *> [_outputs];
+
+ _in_cred_buffer = new queue<Credit *> [_inputs];
+ _out_cred_buffer = new queue<Credit *> [_outputs];
+
+ _arrival_queue = new queue<tArrivalEvent *> [_inputs];
+ _transport_queue = new queue<tTransportEvent *> [_outputs];
+
+ // Misc.
+
+ _transport_free = new bool [_inputs];
+ _transport_match = new int [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _transport_free[i] = true;
+ _transport_match[i] = -1;
+ }
+}
+
+EventRouter::~EventRouter( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete [] _vc[i];
+ }
+
+ delete [] _vc;
+ delete [] _output_state;
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ delete _arrival_arbiter[o];
+ }
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete _transport_arbiter[i];
+ }
+
+ delete [] _arrival_arbiter;
+ delete [] _transport_arbiter;
+
+ delete _crossbar_pipe;
+ delete _credit_pipe;
+ delete _arrival_pipe;
+
+ delete [] _input_buffer;
+ delete [] _output_buffer;
+
+ delete [] _in_cred_buffer;
+ delete [] _out_cred_buffer;
+
+ delete [] _arrival_queue;
+ delete [] _transport_queue;
+
+ delete [] _transport_free;
+ delete [] _transport_match;
+}
+
+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]);
+
+ if ( f ) {
+ _input_buffer[input].push( f );
+ }
+ }
+}
+
+void EventRouter::_ReceiveCredits( )
+{
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = *((*_output_credits)[output]);
+
+ 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;
+ VC *cur_vc;
+
+ 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_vc = &_vc[input][f->vc];
+
+ if ( !cur_vc->AddFlit( f ) ) {
+ cout << "Error processing flit:" << endl << *f;
+ Error( "VC buffer overflow" );
+ }
+
+ // Head flit arriving at idle VC
+ if ( cur_vc->GetState( ) == VC::idle ) {
+
+ 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_vc->Route( _rf, this, f, input );
+ route_set = cur_vc->GetRouteSet( );
+
+ if ( !route_set->GetPortVC( &out_port, &out_vc ) ) {
+ Error( "The event-driven router requires routing functions with a single (port,vc) output" );
+ }
+
+ cur_vc->SetOutput( out_port, out_vc );
+ cur_vc->SetState( VC::active );
+ } else {
+ if ( f->head ) {
+ cout << *f;
+ Error( "Received head flit at non-idle VC." );
+ }
+ }
+
+ if ( f->watch ) {
+ cout << "Received flit at " << _fullname << ". Output port = "
+ << cur_vc->GetOutputPort( ) << ", output VC = "
+ << cur_vc->GetOutputVC( ) << endl;
+ cout << *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_vc->GetOutputPort( );
+ aevt->src_vc = f->vc;
+ aevt->dst_vc = cur_vc->GetOutputVC( );
+ 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( );
+
+ if ( c->vc_cnt != 1 ) {
+ Error( "Code can't handle credit counts not equal to 1." );
+ }
+
+ EventNextVCState::eNextVCState state =
+ _output_state[output].GetState( c->vc[0] );
+
+ credits = _output_state[output].GetCredits( c->vc[0] );
+ pres = _output_state[output].GetPresence( c->vc[0] );
+
+ if ( _vct ) {
+ // In cut-through mode, only head credits indicate a change in
+ // channel state.
+
+ if ( c->head ) {
+ credits++;
+ _output_state[output].SetCredits( c->vc[0], credits );
+ _ProcessWaiting( output, c->vc[0] );
+ }
+ } else {
+ credits++;
+ _output_state[output].SetCredits( c->vc[0], credits );
+
+ if ( c->tail ) { // tail flit -- recycle VC
+ if ( state != EventNextVCState::busy ) {
+ Error( "Received tail credit at non-busy output VC" );
+ }
+
+ _ProcessWaiting( output, c->vc[0] );
+ } else if ( ( state == EventNextVCState::busy ) && ( pres > 0 ) ) {
+ // Flit is present => generate transport event
+
+ tevt = new tTransportEvent;
+ tevt->input = _output_state[output].GetInput( c->vc[0] );
+ tevt->src_vc = _output_state[output].GetInputVC( c->vc[0] );
+ tevt->dst_vc = c->vc[0];
+ tevt->watch = false;
+ tevt->id = -1;
+
+ _transport_queue[output].push( tevt );
+
+ pres--;
+ credits--;
+ _output_state[output].SetPresence( c->vc[0], pres );
+ _output_state[output].SetCredits( c->vc[0], credits );
+ }
+ }
+
+ delete c;
+ }
+
+ // 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;
+ VC *cur_vc;
+ 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_vc = &_vc[input][tevt->src_vc];
+
+ // Some sanity checking first
+
+ if ( ( cur_vc->GetState( ) != VC::active ) ) {
+ Error( "Non-active VC received grant." );
+ }
+
+ if ( cur_vc->Empty( ) ) {
+ return; //Error( "Empty VC received grant." );
+ }
+
+ if ( tevt->dst_vc != cur_vc->GetOutputVC( ) ) {
+ Error( "Transport event's VC does not match input's destination VC." );
+ }
+
+ f = cur_vc->RemoveFlit( );
+
+ if ( _vct ) {
+ if ( f->tail ) {
+ _transport_free[input] = true;
+ _transport_match[input] = -1;
+
+ _transport_queue[output].pop( );
+ delete tevt;
+
+ cur_vc->SetState( VC::idle );
+ } 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 ) {
+ cur_vc->SetState( VC::idle );
+ }
+ }
+
+ c = _NewCredit( );
+ c->vc[c->vc_cnt] = f->vc;
+ c->head = f->head;
+ c->tail = f->tail;
+ c->vc_cnt++;
+ c->id = f->id;
+ _credit_pipe->Write( c, input );
+
+ if ( f->watch && c->tail ) {
+ cout << _fullname << " sending tail credit back for flit " << f->id << endl;
+ }
+
+ // Update and forward the flit to the crossbar
+
+ f->hops++;
+ f->vc = cur_vc->GetOutputVC( );
+ _crossbar_pipe->Write( f, output );
+
+ if ( f->watch ) {
+ cout << "Forwarding flit through crossbar at " << _fullname << ":" << endl;
+ cout << *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( )
+{
+ Flit *f;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_output_buffer[output].empty( ) ) {
+ f = _output_buffer[output].front( );
+ _output_buffer[output].pop( );
+ } else {
+ f = 0;
+ }
+
+ *(*_output_channels)[output] = f;
+ }
+}
+
+void EventRouter::_SendCredits( )
+{
+ Credit *c;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_in_cred_buffer[input].empty( ) ) {
+ c = _in_cred_buffer[input].front( );
+ _in_cred_buffer[input].pop( );
+ } else {
+ c = 0;
+ }
+
+ *(*_input_credits)[input] = c;
+ }
+}
+
+void EventRouter::Display( ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int v = 0; v < _vcs; ++v ) {
+ _vc[input][v].Display( );
+ }
+ }
+}
+
+void EventNextVCState::init( const Configuration& config )
+{
+ _Init( config );
+}
+
+EventNextVCState::EventNextVCState( const Configuration& config,
+ Module *parent, const string& name ) :
+Module( parent, name )
+{
+ _Init( config );
+}
+
+void EventNextVCState::_Init( const Configuration& config )
+{
+ _buf_size = config.GetInt( "vc_buf_size" );
+ _vcs = config.GetInt( "num_vcs" );
+
+ _credits = new int [_vcs];
+ _presence = new int [_vcs];
+ _input = new int [_vcs];
+ _inputVC = new int [_vcs];
+ _waiting = new list<tWaiting *> [_vcs];
+ _state = new eNextVCState [_vcs];
+
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+ _presence[vc] = 0;
+ _credits[vc] = _buf_size;
+ _state[vc] = idle;
+ }
+}
+
+EventNextVCState::~EventNextVCState( )
+{
+ delete [] _credits;
+ delete [] _presence;
+ delete [] _input;
+ delete [] _inputVC;
+ delete [] _waiting;
+ delete [] _state;
+}
+
+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/intersim/event_router.hpp b/src/intersim/event_router.hpp new file mode 100644 index 0000000..91bc005 --- /dev/null +++ b/src/intersim/event_router.hpp @@ -0,0 +1,151 @@ +#ifndef _EVENT_ROUTER_HPP_
+#define _EVENT_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "vc.hpp"
+#include "arbiter.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;
+
+ int *_credits;
+ int *_presence;
+ int *_input;
+ int *_inputVC;
+
+ list<tWaiting *> *_waiting;
+
+ eNextVCState *_state;
+
+ void _Init( const Configuration& config );
+
+public:
+ EventNextVCState() : Module() {}
+ void init( const Configuration& config );
+ EventNextVCState( const Configuration& config,
+ Module *parent, const string& name );
+ ~EventNextVCState( );
+
+ 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 _vc_size;
+
+ int _vct;
+
+ VC **_vc;
+
+ tRoutingFunction _rf;
+
+ EventNextVCState *_output_state;
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+ PipelineFIFO<Credit> *_credit_pipe;
+
+ queue<Flit *> *_input_buffer;
+ queue<Flit *> *_output_buffer;
+
+ queue<Credit *> *_in_cred_buffer;
+ 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;
+ queue<tArrivalEvent *> *_arrival_queue;
+ PriorityArbiter **_arrival_arbiter;
+
+ struct tTransportEvent {
+ int input;
+ int src_vc;
+ int dst_vc;
+
+ int id; // debug
+ bool watch; // debug
+ };
+
+ queue<tTransportEvent *> *_transport_queue;
+ PriorityArbiter **_transport_arbiter;
+
+ bool *_transport_free;
+ 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( );
+
+public:
+ EventRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs );
+ virtual ~EventRouter( );
+
+ virtual void ReadInputs( );
+ virtual void InternalStep( );
+ virtual void WriteOutputs( );
+
+ void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/examples/fly26_age b/src/intersim/examples/fly26_age new file mode 100644 index 0000000..1abff5d --- /dev/null +++ b/src/intersim/examples/fly26_age @@ -0,0 +1,41 @@ +// Topology
+
+topology = fly;
+k = 2;
+n = 6;
+
+// Routing
+
+routing_function = dest_tag;
+
+// Flow control
+
+num_vcs = 8;
+vc_buf_size = 8;
+
+wait_for_tail_credit = 1;
+
+// Router architecture
+
+vc_allocator = select;
+sw_allocator = select;
+alloc_iters = 1;
+
+credit_delay = 2;
+routing_delay = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = uniform;
+const_flits_per_packet = 20;
+priority = age;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
\ No newline at end of file diff --git a/src/intersim/examples/mesh b/src/intersim/examples/mesh new file mode 100644 index 0000000..b374981 --- /dev/null +++ b/src/intersim/examples/mesh @@ -0,0 +1,40 @@ +// Topology
+
+topology = mesh;
+k = 2;
+n = 2;
+
+// Routing
+
+routing_function = dim_order;
+
+// 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 = 1;
+routing_delay = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = transpose;
+const_flits_per_packet = 20;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
diff --git a/src/intersim/examples/mesh2 b/src/intersim/examples/mesh2 new file mode 100644 index 0000000..8eb0521 --- /dev/null +++ b/src/intersim/examples/mesh2 @@ -0,0 +1,41 @@ +// Topology
+
+topology = mesh;
+k = 2;
+n = 2;
+
+// Routing
+
+routing_function = dim_order;
+
+// 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 = 1;
+routing_delay = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = gpgpusim;
+const_flits_per_packet = 3;
+
+injection_process = gpgpu_injector;
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
diff --git a/src/intersim/examples/mesh4 b/src/intersim/examples/mesh4 new file mode 100644 index 0000000..8492df6 --- /dev/null +++ b/src/intersim/examples/mesh4 @@ -0,0 +1,41 @@ +// Topology
+
+topology = mesh;
+k = 2;
+n = 1;
+
+// Routing
+
+routing_function = dim_order;
+
+// Flow control
+
+num_vcs = 1;
+vc_buf_size = 1;
+
+wait_for_tail_credit = 1;
+
+// Router architecture
+
+vc_allocator = islip;
+sw_allocator = islip;
+alloc_iters = 1;
+
+credit_delay = 1;
+routing_delay = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 1;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = gpgpusim;
+const_flits_per_packet = 3;
+
+injection_process = gpgpu_injector;
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
diff --git a/src/intersim/examples/mesh88_lat b/src/intersim/examples/mesh88_lat new file mode 100644 index 0000000..fca1fb4 --- /dev/null +++ b/src/intersim/examples/mesh88_lat @@ -0,0 +1,40 @@ +// Topology
+
+topology = mesh;
+k = 8;
+n = 2;
+
+// Routing
+
+routing_function = dim_order;
+
+// 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 = 1;
+vc_alloc_delay = 1;
+
+input_speedup = 2;
+output_speedup = 1;
+internal_speedup = 1.0;
+
+// Traffic
+
+traffic = transpose;
+const_flits_per_packet = 20;
+
+// Simulation
+
+sim_type = latency;
+injection_rate = 0.1;
\ No newline at end of file diff --git a/src/intersim/examples/single b/src/intersim/examples/single new file mode 100644 index 0000000..addb549 --- /dev/null +++ b/src/intersim/examples/single @@ -0,0 +1,20 @@ +// Topology
+
+topology = single;
+in_ports = 8;
+out_ports = 8;
+
+// Routing
+
+routing_function = single;
+
+// Flow control
+
+vc_allocator = islip;
+sw_allocator = islip;
+alloc_iters = 2;
+
+num_vcs = 8;
+vc_buf_size = 1000;
+
+wait_for_tail_credit = 0;
\ No newline at end of file diff --git a/src/intersim/examples/torus88 b/src/intersim/examples/torus88 new file mode 100644 index 0000000..723e3ac --- /dev/null +++ b/src/intersim/examples/torus88 @@ -0,0 +1,14 @@ +// 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/intersim/flit.cpp b/src/intersim/flit.cpp new file mode 100644 index 0000000..8ec248b --- /dev/null +++ b/src/intersim/flit.cpp @@ -0,0 +1,12 @@ +#include "booksim.hpp"
+#include "flit.hpp"
+
+ostream& operator<<( ostream& os, const Flit& f )
+{
+ os << " Flit ID: " << f.id << " (" << &f << ")"
+ << " Head: " << f.head << " Tail: " << f.tail << endl;
+ os << " Source : " << f.src << " Dest : " << f.dest << endl;
+ os << " Injection time : " << f.time << endl;
+
+ return os;
+}
diff --git a/src/intersim/flit.hpp b/src/intersim/flit.hpp new file mode 100644 index 0000000..d22e531 --- /dev/null +++ b/src/intersim/flit.hpp @@ -0,0 +1,46 @@ +#ifndef _FLIT_HPP_
+#define _FLIT_HPP_
+
+#include "booksim.hpp"
+
+#include <iostream>
+
+struct Flit {
+ void* data;
+ int net_num; // which network is this flit in (we might have several icnt networks)
+
+ int vc;
+
+ bool head;
+ bool tail;
+ bool true_tail;
+
+ int time;
+
+ int sn;
+ int rob_time;
+
+ int id;
+ bool record;
+
+ int src;
+ int dest;
+
+ int pri;
+
+ int hops;
+ bool watch;
+
+ // Fields for multi-phase algorithms
+ mutable int intm;
+ mutable int ph;
+
+ mutable int dr;
+
+ // Which VC parition to use for deadlock avoidance in a ring
+ mutable int ring_par;
+};
+
+ostream& operator<<( ostream& os, const Flit& f );
+
+#endif
diff --git a/src/intersim/fly.cpp b/src/intersim/fly.cpp new file mode 100644 index 0000000..1793cc2 --- /dev/null +++ b/src/intersim/fly.cpp @@ -0,0 +1,133 @@ +#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+
+#include "fly.hpp"
+#include "misc_utils.hpp"
+
+//#define DEBUG_FLY
+
+KNFly::KNFly( const Configuration &config ) :
+Network( config )
+{
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void KNFly::_ComputeSize( const Configuration &config )
+{
+ _k = config.GetInt( "k" );
+ _n = config.GetInt( "n" );
+
+ gK = _k; gN = _n;
+
+ _sources = powi( _k, _n );
+ _dests = 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)*_sources;
+}
+
+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 );
+ router_name.seekp( 0, ios::beg );
+
+#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] );
+#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*_sources + 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)*_sources + 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/intersim/fly.hpp b/src/intersim/fly.hpp new file mode 100644 index 0000000..76ebb12 --- /dev/null +++ b/src/intersim/fly.hpp @@ -0,0 +1,26 @@ +#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 );
+
+ int GetN( ) const;
+ int GetK( ) const;
+
+ double Capacity( ) const;
+};
+
+#endif
diff --git a/src/intersim/injection.cpp b/src/intersim/injection.cpp new file mode 100644 index 0000000..68483cb --- /dev/null +++ b/src/intersim/injection.cpp @@ -0,0 +1,100 @@ +#include "booksim.hpp"
+#include <map>
+#include <assert.h>
+#include <cstdlib>
+#include "injection.hpp"
+#include "network.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+
+map<string, tInjectionProcess> gInjectionProcessMap;
+
+double gBurstAlpha;
+double gBurstBeta;
+
+int gConstPacketSize;
+
+int *gNodeStates = 0;
+//=============================================================
+
+int bernoulli( int /*source*/, double rate )
+{
+ return( RandomFloat( ) < ( rate / (double)gConstPacketSize ) ) ?
+ gConstPacketSize : 0;
+}
+
+//=============================================================
+
+int on_off( int source, double rate )
+{
+ double r1;
+ bool issue;
+
+ assert( ( source >= 0 ) && ( source < gNodes ) );
+
+ if ( !gNodeStates ) {
+ gNodeStates = new int [gNodes];
+
+ for ( int n = 0; n < gNodes; ++n ) {
+ gNodeStates[n] = 0;
+ }
+ }
+
+ // advance state
+
+ if ( gNodeStates[source] == 0 ) {
+ if ( RandomFloat( ) < gBurstAlpha ) { // from off to on
+ gNodeStates[source] = 1;
+ }
+ } else if ( RandomFloat( ) < gBurstBeta ) { // from on to off
+ gNodeStates[source] = 0;
+ }
+
+ // generate packet
+
+ issue = false;
+ if ( gNodeStates[source] ) { // on?
+ r1 = rate * ( 1.0 + gBurstBeta / gBurstAlpha ) /
+ (double)gConstPacketSize;
+
+ if ( RandomFloat( ) < r1 ) {
+ issue = true;
+ }
+ }
+
+ return issue ? gConstPacketSize : 0;
+}
+
+//=============================================================
+
+void InitializeInjectionMap( )
+{
+ /* Register injection processes functions here */
+
+ gInjectionProcessMap["bernoulli"] = &bernoulli;
+ gInjectionProcessMap["on_off"] = &on_off;
+}
+
+tInjectionProcess GetInjectionProcess( const Configuration& config )
+{
+ map<string, tInjectionProcess>::const_iterator match;
+ tInjectionProcess ip;
+
+ string fn;
+
+ config.GetStr( "injection_process", fn );
+ match = gInjectionProcessMap.find( fn );
+
+ if ( match != gInjectionProcessMap.end( ) ) {
+ ip = match->second;
+ } else {
+ cout << "Error: Undefined injection process '" << fn << "'." << endl;
+ exit(-1);
+ }
+
+ gConstPacketSize = config.GetInt( "const_flits_per_packet" );
+ gBurstAlpha = config.GetFloat( "burst_alpha" );
+ gBurstBeta = config.GetFloat( "burst_beta" );
+
+ return ip;
+}
diff --git a/src/intersim/injection.hpp b/src/intersim/injection.hpp new file mode 100644 index 0000000..60a017a --- /dev/null +++ b/src/intersim/injection.hpp @@ -0,0 +1,12 @@ +#ifndef _INJECTION_HPP_
+#define _INJECTION_HPP_
+
+#include "config_utils.hpp"
+
+typedef int (*tInjectionProcess)( int, double );
+
+void InitializeInjectionMap( );
+
+tInjectionProcess GetInjectionProcess( const Configuration& config );
+
+#endif
diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp new file mode 100644 index 0000000..bb30f81 --- /dev/null +++ b/src/intersim/interconnect_interface.cpp @@ -0,0 +1,574 @@ +#include "booksim.hpp" +#include <string> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <queue> + +#include "routefunc.hpp" +#include "traffic.hpp" +#include "booksim_config.hpp" +#include "trafficmanager.hpp" +#include "random_utils.hpp" +#include "network.hpp" +#include "singlenet.hpp" +#include "kncube.hpp" +#include "fly.hpp" +#include "injection.hpp" +#include "interconnect_interface.h" +#include "../gpgpu-sim/mem_fetch.h" +#include <string.h> + +extern unsigned long long gpu_sim_cycle; +int _flit_size ; +extern unsigned int warp_size; + +bool doub_net = false; //double networks disabled by default + +BookSimConfig icnt_config; +TrafficManager** traffic; +unsigned int g_num_vcs; //number of virtual channels +queue<Flit *> ** ejection_buf; +vector<int> round_robin_turn; //keep track of boundary_buf last used in icnt_pop +unsigned int ejection_buffer_capacity ; +unsigned int boundary_buf_capacity ; + +unsigned int input_buffer_capacity ; + +class boundary_buf{ +private: + queue<void *> buf; + queue<bool> tail_flag; + int packet_n; + unsigned capacity; +public: + boundary_buf(){ + capacity = boundary_buf_capacity; //maximum flits the buffer can hold + packet_n=0; + } + bool is_full(void){ + return (buf.size()>=capacity); + } + bool has_packet() { + return (packet_n); + } + void * pop_packet(){ + assert (packet_n); + void * data = NULL; + void * temp_d = buf.front(); + while (data==NULL) { + if (tail_flag.front()) { + data = buf.front(); + packet_n--; + } + assert(temp_d == buf.front()); //all flits must belong to the same packet + buf.pop(); + tail_flag.pop(); + } + return data; + } + void push_flit_data(void* data,bool is_tail) { + buf.push(data); + tail_flag.push(is_tail); + if (is_tail) { + packet_n++; + } + } +}; + +boundary_buf** clock_boundary_buf; + +class mycomparison { +public: + bool operator() (const void* lhs, const void* rhs) const + { + return( ((mem_fetch_t *)lhs)->icnt_receive_time > ((mem_fetch_t *) rhs)->icnt_receive_time); + } +}; + +bool perfect_icnt = 0; +int fixed_lat_icnt = 0; + +priority_queue<void * , vector<void* >, mycomparison> * out_buf_fixedlat_buf; + + +//perfect icnt stats: +unsigned int* max_fixedlat_buf_size; + +static unsigned int net_c; //number of inetrconnection networks + +static unsigned int _n_shader = 0; +static unsigned int _n_mem = 0; + +static int * node_map; //deviceID to mesh location 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) +static int * reverse_map; + +void map_gen(int dim,int memcount, int memnodes[]) +{ + int k = 0; + int i=0 ; + int j=0 ; + int memfound=0; + for (i = 0; i < dim*dim ; i++) { + memfound=0; + for (j = 0; j<memcount ; j++) { + if (memnodes[j]==i) { + memfound=1; + } + } + if (!memfound) { + node_map[k]=i; + k++; + } + } + for (int j = 0; j<memcount ; j++) { + node_map[k]=memnodes[j]; + k++; + } + assert(k==dim*dim); +} + +void display_map(int dim,int count){ + int i=0; + for (i=0;i<count;i++) { + printf("%d ",node_map[i]); + if (i%dim ==0) { + printf("\n"); + } + } +} + +void create_node_map(int n_shader, int n_mem, int size, int use_map) { + node_map = (int*)malloc((size)*sizeof(int)); + if (use_map) { + switch (size) { + case 16 : + { // good for 8 shaders and 8 memory cores + int newmap[] = { + 0, 2, 5, 7, + 8,10,13,15, + 1, 3, 4, 6, //memory nodes + 9,11,12,14 //memory nodes + }; + memcpy (node_map, newmap,16*sizeof(int)); + break; + } + case 64: + { // good for 56 shaders and 8 memory cores + int newmap[] = { + 0, 1, 2, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 16, 18, + 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 30, 31, 32, 33, 34, 35, + 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 48, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 62, 63, + 3, 15, 17, 29, 36, 47, 49, 61 //memory nodes are in this line + }; + memcpy (node_map, newmap,64*sizeof(int)); + break; + } + case 121: + { // good for 110 shaders and 11 memory cores + int newmap[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, + 24, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, + 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 96, + 97, 98, 99,101,102,103,104,105,106,107,109, + 110,111,112,113,114,115,116,117,118,119,120, + 12, 20, 25, 28, 57, 60, 63, 92, 95,100,108 //memory nodes are in this line + }; + memcpy (node_map, newmap,121*sizeof(int)); + break; + } + case 36: + { + int memnodes[8]={3,7,10,12,23,25,28,32}; + map_gen(6/*dim*/,8/*memcount*/,memnodes); + break; + } + default: + { + cout<<"WARNING !!! NO MAPPING IMPLEMENTED YET FOR THIS CONFIG"<<endl; + for (int i=0;i<size;i++) { + node_map[i]=i; + } + } + } + } else { // !use_map + for (int i=0;i<size;i++) { + node_map[i]=i; + } + } + reverse_map = (int*)malloc((size)*sizeof(int)); + for (int i = 0; i < size ; i++) { + for (int j = 0; j<size ; j++) { + if (node_map[j]==i) { + reverse_map[i]=j; + break; + } + } + } + printf("nodemap\n"); + display_map((int) sqrt(size),size); + +} + +int fixed_latency(int input, int output) +{ + int latency; + if (perfect_icnt) { + latency = 1; + } else { + int dim = icnt_config.GetInt( "k" ); + int xhops = abs ( input%dim - output%dim); + int yhops = abs ( input/dim - output/dim); + latency = ( (xhops+yhops)*fixed_lat_icnt ); + } + return latency; +} + +//This function gets a mapped node number and tells if it is a shader node or a memory node +static inline bool is_shd(int node) +{ + if (reverse_map[node] < (int) _n_shader) + return true; + else + return false; +} + +static inline bool is_mem(int node) +{ + return !is_shd(node); +} + +//////////////////// +void interconnect_stats() +{ + if (!fixed_lat_icnt) { + for (unsigned i=0; i<net_c;i++) { + cout <<"Traffic "<<i<< " Stat" << endl; + traffic[i]->ShowStats(); + if (icnt_config.GetInt("enable_link_stats")) { + cout << "%=================================" << endl; + cout <<"Traffic "<<i<< "Link utilizations:" << endl; + traffic[i]->_net->Display(); + } + } + } else { + //show max queue sizes + cout<<"Max Fixed Latency ICNT queue size for"<<endl; + for (unsigned i=0;i<(_n_mem + _n_shader);i++) { + cout<<" node[" << i <<"] is "<<max_fixedlat_buf_size[i]; + } + cout<<endl; + } +} + +void icnt_overal_stat() //should be called upon simulation exit to give an overal stat +{ + if (!fixed_lat_icnt) { + for (unsigned i=0; i<net_c;i++) { + traffic[i]->ShowOveralStat(); + } + } +} + +void icnt_init_grid (){ + for (unsigned i=0; i<net_c;i++) { + traffic[i]->IcntInitPerGrid(0/*_time*/); //initialization before gpu grid start + } +} + +int interconnect_has_buffer(unsigned int input_node, + unsigned int *size) +{ + + unsigned int input = node_map[input_node]; + int has_buffer; + int tot_req_size = 0; + for (unsigned int i=0; i<(_n_mem+_n_shader);i++ ) { + if (size[i]) { + tot_req_size+= size[i]; + } + } + unsigned int n_flits = tot_req_size / _flit_size + ((tot_req_size % _flit_size)? 1:0); + if (!(fixed_lat_icnt || perfect_icnt)) { + has_buffer = (traffic[0]->_partial_packets[input][0].size() + n_flits) <= input_buffer_capacity; + if ((net_c>1) && is_mem(input)) { + has_buffer = (traffic[1]->_partial_packets[input][0].size() + n_flits) <= input_buffer_capacity; + } + } else { + has_buffer = 1; + } + return has_buffer; +} + +void interconnect_push ( unsigned int input_node, unsigned int output_node, + void* data, unsigned int size) +{ + int output = node_map[output_node]; + int input = node_map[input_node]; + +#if 0 + cout<<"Call interconnect push input: "<<input<<" output: "<<output<<endl; +#endif + + if (fixed_lat_icnt) { + ((mem_fetch_t *) data)->icnt_receive_time = gpu_sim_cycle + fixed_latency(input,output); + out_buf_fixedlat_buf[output].push(data); //deliver the whole packet to destination in zero cycles + if (out_buf_fixedlat_buf[output].size() > max_fixedlat_buf_size[output]) { + max_fixedlat_buf_size[output]= out_buf_fixedlat_buf[output].size(); + } + } else { + + unsigned int n_flits = size / _flit_size + ((size % _flit_size)? 1:0); + int nc; + if (!doub_net) { + nc=0; + } else //doub_net enabled + if (is_shd(input) ) { + nc=0; + } else { + nc=1; + } + traffic[nc]->_GeneratePacket( input, n_flits, 0 /*class*/, traffic[nc]->_time, data, output); +#if DOUB + cout <<"Traffic[" << nc << "] (mapped) sending form "<< input << " to " << output <<endl; +#endif + } + +} + +void* interconnect_pop(unsigned int output_node) +{ + int output = node_map[output_node]; +#if DEBUG + cout<<"Call interconnect POP " << output<<endl; +#endif + void* data = NULL; + if (fixed_lat_icnt) { + if (!out_buf_fixedlat_buf[output].empty()) { + if (((mem_fetch_t *)out_buf_fixedlat_buf[output].top())->icnt_receive_time <= gpu_sim_cycle) { + data = out_buf_fixedlat_buf[output].top(); + out_buf_fixedlat_buf[output].pop(); + assert (((mem_fetch_t *)data)->icnt_receive_time); + } + } + } else { + unsigned vc; + unsigned turn = round_robin_turn[output]; + for (vc=0;(vc<g_num_vcs) && (data==NULL);vc++) { + if (clock_boundary_buf[output][turn].has_packet()) { + data = clock_boundary_buf[output][turn].pop_packet(); + } + turn++; + if (turn == g_num_vcs) turn = 0; + } + if (data) { + round_robin_turn[output] = turn; + } + } + return data; +} + +extern int MATLAB_OUTPUT ; +extern int DISPLAY_LAT_DIST ; +extern int DISPLAY_HOP_DIST ; +extern int DISPLAY_PAIR_LATENCY ; +extern unsigned int gpu_n_thread_per_shader; +extern char *gpgpu_cache_dl1_opt; +extern int gpgpu_no_dl1; + + +void init_interconnect (char* 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.Parse( config_file ); + + net_c = icnt_config.GetInt( "network_count" ); + if (net_c==2) { + doub_net = true; + } else if (net_c<1 || net_c>2) { + cout <<net_c<<" Network_count less than 1 or more than 2 not supported."<<endl; + abort(); + } + + g_num_vcs = icnt_config.GetInt( "num_vcs" ); + InitializeRoutingMap( ); + InitializeTrafficMap( ); + InitializeInjectionMap( ); + + RandomSeed( icnt_config.GetInt("seed") ); + + Network **net; + + traffic = new TrafficManager *[net_c]; + net = new Network *[net_c]; + + for (unsigned i=0;i<net_c;i++) { + string topo; + + icnt_config.GetStr( "topology", topo ); + + if ( topo == "torus" ) { + net[i] = new KNCube( icnt_config, true ); + } else if ( topo =="mesh" ) { + net[i] = new KNCube( icnt_config, false ); + } else if ( topo == "fly" ) { + net[i] = new KNFly( icnt_config ); + } else if ( topo == "single" ) { + net[i] = new SingleNet( icnt_config ); + } else { + cerr << "Unknown topology " << topo << endl; + exit(-1); + } + + if ( icnt_config.GetInt( "link_failures" ) ) { + net[i]->InsertRandomFaults( icnt_config ); + } + + traffic[i] = new TrafficManager ( icnt_config, net[i], i/*id*/ ); + } + + fixed_lat_icnt = icnt_config.GetInt( "fixed_lat_per_hop" ); + + if (icnt_config.GetInt( "perfect_icnt" )) { + perfect_icnt = true; + fixed_lat_icnt = 1; + } + _flit_size = icnt_config.GetInt( "flit_size" ); + if (icnt_config.GetInt("ejection_buf_size")) { + ejection_buffer_capacity = icnt_config.GetInt( "ejection_buf_size" ) ; + } else { + ejection_buffer_capacity = icnt_config.GetInt( "vc_buf_size" ); + } + boundary_buf_capacity = icnt_config.GetInt( "boundary_buf_size" ) ; + if (icnt_config.GetInt("input_buf_size")) { + input_buffer_capacity = icnt_config.GetInt("input_buf_size"); + } else { + if (gpgpu_cache_dl1_opt && !gpgpu_no_dl1) { + int l1cache_linesize = 32; + sscanf(gpgpu_cache_dl1_opt,"%*d:%d:%*d:%*c", &l1cache_linesize); + input_buffer_capacity = gpu_n_thread_per_shader*(l1cache_linesize/_flit_size+(int)ceil(8.0f/_flit_size)); + } else { + input_buffer_capacity = gpu_n_thread_per_shader*((int)ceil(8.0f/_flit_size)); + } + } + create_buf(traffic[0]->_dests,warp_size,icnt_config.GetInt( "num_vcs" )); + MATLAB_OUTPUT = icnt_config.GetInt("MATLAB_OUTPUT"); + DISPLAY_LAT_DIST = icnt_config.GetInt("DISPLAY_LAT_DIST"); + DISPLAY_HOP_DIST = icnt_config.GetInt("DISPLAY_HOP_DIST"); + DISPLAY_PAIR_LATENCY = icnt_config.GetInt("DISPLAY_PAIR_LATENCY"); + create_node_map(n_shader,n_mem,traffic[0]->_dests, icnt_config.GetInt("use_map")); + for (unsigned i=0;i<net_c;i++) { + traffic[i]->_FirstStep(); + } +} + +void advance_interconnect () +{ + if (!fixed_lat_icnt) { + for (unsigned i=0;i<net_c;i++) { + traffic[i]->_Step( ); + } + } +} + +unsigned interconnect_busy() +{ + unsigned i,j; + for(i=0; i<net_c;i++) { + if (traffic[i]->_measured_in_flight) { + return 1; + } + } + for ( i=0 ;i<(_n_shader+_n_mem);i++ ) { + if ( !traffic[0]->_partial_packets[i] [0].empty() ) { + return 1; + } + if ( doub_net && !traffic[1]->_partial_packets[i] [0].empty() ) { + return 1; + } + for ( j=0;j<g_num_vcs;j++ ) { + if ( !ejection_buf[i][j].empty() || clock_boundary_buf[i][j].has_packet() ) { + return 1; + } + } + } + return 0; +} + +//create buffers for src_n nodes +void create_buf(int src_n,int warp_n,int vc_n) +{ + int i; + ejection_buf = new queue<Flit *>* [src_n]; + clock_boundary_buf = new boundary_buf* [src_n]; + round_robin_turn.resize( src_n ); + for (i=0;i<src_n;i++){ + ejection_buf[i]= new queue<Flit *>[vc_n]; + clock_boundary_buf[i]= new boundary_buf[vc_n]; + round_robin_turn[vc_n-1]; + } + if (fixed_lat_icnt) { + out_buf_fixedlat_buf = new priority_queue<void * , vector<void* >, mycomparison> [src_n]; + max_fixedlat_buf_size = new unsigned int [src_n]; + for (i=0;i<src_n;i++) { + max_fixedlat_buf_size[i]=0; + } + } + +} + +void write_out_buf(int output, Flit *flit) { + int vc = flit->vc; + assert (ejection_buf[output][vc].size() < ejection_buffer_capacity); + ejection_buf[output][vc].push(flit); +} + +void transfer2boundary_buf(int output) { + Flit* flit; + unsigned vc; + for (vc=0; vc<g_num_vcs;vc++) { + if ( !ejection_buf[output][vc].empty() && !clock_boundary_buf[output][vc].is_full() ) { + flit = ejection_buf[output][vc].front(); + ejection_buf[output][vc].pop(); + clock_boundary_buf[output][vc].push_flit_data( flit->data, flit->tail); + traffic[flit->net_num]->credit_return_queue[output].push(flit); //will send back credit + if ( flit->head ) { + assert (flit->dest == output); + } +#if DOUB + cout <<"Traffic " <<nc<<" push out flit to (mapped)" << output <<endl; +#endif + } + } +} + +void time_vector_update(unsigned int uid, int slot , long int cycle, int type); +extern unsigned long long gpu_tot_sim_cycle; +void time_vector_update_icnt_injected(void* data, int input) { + mem_fetch_t* mf = (mem_fetch_t*) data; + unsigned int uid = mf->write? mf->request_uid : mf->mshr->insts[0].uid; + long int cycle = gpu_sim_cycle + gpu_tot_sim_cycle; + int req_type = mf->write? WT_REQ : RD_REQ; + if (is_mem(input)) { + time_vector_update( uid, MR_2SH_ICNT_INJECTED, cycle, req_type ); + } else { + time_vector_update( uid, MR_ICNT_INJECTED, cycle,req_type ); + } +} diff --git a/src/intersim/interconnect_interface.h b/src/intersim/interconnect_interface.h new file mode 100644 index 0000000..541f992 --- /dev/null +++ b/src/intersim/interconnect_interface.h @@ -0,0 +1,35 @@ +#ifndef INTERCONNECT_INTERFACE_H +#define INTERCONNECT_INTERFACE_H + +#include "flit.hpp" +#include "trafficmanager.hpp" + +struct glue_buf { + int flit_c; // flit count + void *data; + int net_num; // which network is this flit in (we might have several icnt networks) + int src; + int dest; +}; + +//node side functions +int interconnect_has_buffer(unsigned int input, unsigned int *size); +void interconnect_push ( unsigned int input, unsigned int output, + void* data, unsigned int size); +void* interconnect_pop(unsigned int output); +void init_interconnect (char* config_file, + unsigned int n_shader, unsigned int n_mem); +void advance_interconnect(); +unsigned interconnect_busy(); +void interconnect_stats() ; + +//interconnect side functions +void create_buf(int src_n,int warp_n, int vc_n); +int in_map (int input) ; +void write_out_buf(int output, Flit * data); +void transfer2boundary_buf(int output); +void time_vector_update_icnt_injected(void* mf, int input); + +#endif + + diff --git a/src/intersim/iq_router.cpp b/src/intersim/iq_router.cpp new file mode 100644 index 0000000..137c0bb --- /dev/null +++ b/src/intersim/iq_router.cpp @@ -0,0 +1,633 @@ +#include <string>
+#include <sstream>
+#include <iostream>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "iq_router.hpp"
+
+IQRouter::IQRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs )
+: Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ string alloc_type;
+ ostringstream vc_name;
+
+ _vcs = config.GetInt( "num_vcs" );
+ _vc_size = config.GetInt( "vc_buf_size" );
+
+ _iq_time = 0;
+
+ _output_extra_latency = config.GetInt( "output_extra_latency" );
+
+ // Routing
+
+ _rf = GetRoutingFunction( config );
+
+ // Alloc VC's
+
+ _vc = new VC * [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _vc[i] = new VC [_vcs];
+ for( int j=0; j < _vcs; j++ )
+ _vc[i][j].init( config, _outputs );
+
+ for ( int v = 0; v < _vcs; ++v ) { // Name the vc modules
+ vc_name << "vc_i" << i << "_v" << v;
+ _vc[i][v].SetName( this, vc_name.str( ) );
+ vc_name.seekp( 0, ios::beg );
+ }
+ }
+
+ // Alloc next VCs' buffer state
+
+ _next_vcs = new BufferState [_outputs];
+ for( int j=0; j < _outputs; j++ ) {
+ _next_vcs[j].init( config );
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ vc_name << "next_vc_o" << o;
+ _next_vcs[o].SetName( this, vc_name.str( ) );
+ vc_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc allocators
+
+ config.GetStr( "vc_allocator", alloc_type );
+ _vc_allocator = Allocator::NewAllocator( config,
+ this, "vc_allocator",
+ alloc_type,
+ _vcs*_inputs, 1,
+ _vcs*_outputs, 1 );
+
+ if ( !_vc_allocator ) {
+ cout << "ERROR: Unknown vc_allocator type " << alloc_type << endl;
+ exit(-1);
+ }
+
+ config.GetStr( "sw_allocator", alloc_type );
+ _sw_allocator = Allocator::NewAllocator( config,
+ this, "sw_allocator",
+ alloc_type,
+ _inputs*_input_speedup, _input_speedup,
+ _outputs*_output_speedup, _output_speedup );
+
+ if ( !_sw_allocator ) {
+ cout << "ERROR: Unknown sw_allocator type " << alloc_type << endl;
+ exit(-1);
+ }
+
+ _sw_rr_offset = new int [_inputs*_input_speedup];
+ for ( int i = 0; i < _inputs*_input_speedup; ++i ) {
+ _sw_rr_offset[i] = 0;
+ }
+
+ // Alloc pipelines (to simulate processing/transmission delays)
+
+ _crossbar_pipe =
+ new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs*_output_speedup,
+ _st_prepare_delay + _st_final_delay );
+
+ _credit_pipe =
+ new PipelineFIFO<Credit>( this, "credit_pipeline", _inputs,
+ _credit_delay );
+
+ // Input and output queues
+
+ _input_buffer = new queue<Flit *> [_inputs];
+ _output_buffer = new queue<pair<Flit *, int> > [_outputs];
+
+ _in_cred_buffer = new queue<Credit *> [_inputs];
+ _out_cred_buffer = new queue<Credit *> [_outputs];
+
+ // Switch configuration (when held for multiple cycles)
+
+ _hold_switch_for_packet = config.GetInt( "hold_switch_for_packet" );
+ _switch_hold_in = new int [_inputs*_input_speedup];
+ _switch_hold_out = new int [_outputs*_output_speedup];
+ _switch_hold_vc = new int [_inputs*_input_speedup];
+
+ for ( int i = 0; i < _inputs*_input_speedup; ++i ) {
+ _switch_hold_in[i] = -1;
+ _switch_hold_vc[i] = -1;
+ }
+
+ for ( int i = 0; i < _outputs*_output_speedup; ++i ) {
+ _switch_hold_out[i] = -1;
+ }
+}
+
+IQRouter::~IQRouter( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete [] _vc[i];
+ }
+
+ delete [] _vc;
+ delete [] _next_vcs;
+
+ delete _vc_allocator;
+ delete _sw_allocator;
+
+ delete [] _sw_rr_offset;
+
+ delete _crossbar_pipe;
+ delete _credit_pipe;
+
+ delete [] _input_buffer;
+ delete [] _output_buffer;
+
+ delete [] _in_cred_buffer;
+ delete [] _out_cred_buffer;
+
+ delete [] _switch_hold_in;
+ delete [] _switch_hold_vc;
+ delete [] _switch_hold_out;
+}
+
+void IQRouter::ReadInputs( )
+{
+ _ReceiveFlits( );
+ _ReceiveCredits( );
+}
+
+void IQRouter::InternalStep( )
+{
+ _InputQueuing( );
+ _Route( );
+ _VCAlloc( );
+ _SWAlloc( );
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+ _vc[input][vc].AdvanceTime( );
+ }
+ }
+
+ _crossbar_pipe->Advance( );
+ _credit_pipe->Advance( );
+ ++_iq_time;
+
+ _OutputQueuing( );
+}
+
+#include "interconnect_interface.h"
+void IQRouter::WriteOutputs( )
+{
+// Flit *f;
+// for ( int output = 0; output < _outputs; ++output ) {
+// if ( !_output_buffer[output].empty( ) ) {
+ // f = _output_buffer[output].front( );
+ // if ( out_buf_has_space (f->dest,f->data, f->head , f->tail) ){
+ _SendFlits( );
+ _SendCredits( );
+ //}
+ //}
+ // }
+}
+
+void IQRouter::_ReceiveFlits( )
+{
+ Flit *f;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ f = *((*_input_channels)[input]);
+
+ if ( f ) {
+ _input_buffer[input].push( f );
+ }
+ }
+}
+
+void IQRouter::_ReceiveCredits( )
+{
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = *((*_output_credits)[output]);
+
+ if ( c ) {
+ _out_cred_buffer[output].push( c );
+ }
+ }
+}
+
+void IQRouter::_InputQueuing( )
+{
+ Flit *f;
+ Credit *c;
+ VC *cur_vc;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_input_buffer[input].empty( ) ) {
+ f = _input_buffer[input].front( );
+ _input_buffer[input].pop( );
+
+ cur_vc = &_vc[input][f->vc];
+
+ if ( !cur_vc->AddFlit( f ) ) {
+ Error( "VC buffer overflow" );
+ }
+
+ if ( f->watch ) {
+ cout << "Received flit at " << _fullname << endl;
+ cout << *f;
+ }
+ }
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+
+ cur_vc = &_vc[input][vc];
+
+ if ( cur_vc->GetState( ) == VC::idle ) {
+ f = cur_vc->FrontFlit( );
+
+ if ( f ) {
+ if ( !f->head ) {
+ Error( "Received non-head flit at idle VC" );
+ }
+
+ cur_vc->Route( _rf, this, f, input );
+ cur_vc->SetState( VC::routing );
+ }
+ }
+ }
+ }
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_out_cred_buffer[output].empty( ) ) {
+ c = _out_cred_buffer[output].front( );
+ _out_cred_buffer[output].pop( );
+
+ _next_vcs[output].ProcessCredit( c );
+ delete c;
+ }
+ }
+}
+
+void IQRouter::_Route( )
+{
+ VC *cur_vc;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+
+ cur_vc = &_vc[input][vc];
+
+ if ( ( cur_vc->GetState( ) == VC::routing ) &&
+ ( cur_vc->GetStateTime( ) >= _routing_delay ) ) {
+
+ cur_vc->SetState( VC::vc_alloc );
+ }
+ }
+ }
+}
+
+void IQRouter::_AddVCRequests( VC* cur_vc, int input_index, bool watch )
+{
+ const OutputSet *route_set;
+ BufferState *dest_vc;
+ int vc_cnt, out_vc;
+ int in_priority, out_priority;
+
+ route_set = cur_vc->GetRouteSet( );
+ out_priority = cur_vc->GetPriority( );
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ vc_cnt = route_set->NumVCs( output );
+ dest_vc = &_next_vcs[output];
+
+ for ( int vc_index = 0; vc_index < vc_cnt; ++vc_index ) {
+ out_vc = route_set->GetVC( output, vc_index, &in_priority );
+
+ if ( watch ) {
+ cout << " trying vc " << out_vc << " (out = " << output << ") ... ";
+ }
+
+ // 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,
+ // 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_vc->IsAvailableFor( out_vc ) ) {
+ _vc_allocator->AddRequest( input_index, output*_vcs + out_vc, 1,
+ in_priority, out_priority );
+ if ( watch ) {
+ cout << "available" << endl;
+ }
+ } else if ( watch ) {
+ cout << "busy" << endl;
+ }
+ }
+ }
+}
+
+void IQRouter::_VCAlloc( )
+{
+ VC *cur_vc;
+ BufferState *dest_vc;
+ int input_and_vc;
+ int match_input;
+ int match_vc;
+
+ Flit *f;
+ bool watched;
+
+ _vc_allocator->Clear( );
+ watched = false;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+
+ cur_vc = &_vc[input][vc];
+
+ if ( ( cur_vc->GetState( ) == VC::vc_alloc ) &&
+ ( cur_vc->GetStateTime( ) >= _vc_alloc_delay ) ) {
+
+ f = cur_vc->FrontFlit( );
+ if ( f->watch ) {
+ cout << "VC requesting allocation at " << _fullname << endl;
+ cout << " input_index = " << input*_vcs + vc << endl;
+ cout << *f;
+ watched = true;
+ }
+
+ _AddVCRequests( cur_vc, input*_vcs + vc, f->watch );
+ }
+ }
+ }
+
+ /*if ( watched ) {
+ _vc_allocator->PrintRequests( );
+ }*/
+
+ _vc_allocator->Allocate( );
+
+ // Winning flits get a VC
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ for ( int vc = 0; vc < _vcs; ++vc ) {
+ input_and_vc = _vc_allocator->InputAssigned( output*_vcs + vc );
+
+ if ( input_and_vc != -1 ) {
+ match_input = input_and_vc / _vcs;
+ match_vc = input_and_vc - match_input*_vcs;
+
+ cur_vc = &_vc[match_input][match_vc];
+ dest_vc = &_next_vcs[output];
+
+ cur_vc->SetState( VC::active );
+ cur_vc->SetOutput( output, vc );
+ dest_vc->TakeBuffer( vc );
+
+ f = cur_vc->FrontFlit( );
+
+ if ( f->watch ) {
+ cout << "Granted VC allocation at " << _fullname
+ << " (input index " << input_and_vc << " )" << endl;
+ cout << *f;
+ }
+ }
+ }
+ }
+}
+
+void IQRouter::_SWAlloc( )
+{
+ Flit *f;
+ Credit *c;
+
+ VC *cur_vc;
+ BufferState *dest_vc;
+
+ int input;
+ int output;
+ int vc;
+
+ int expanded_input;
+ int expanded_output;
+
+ _sw_allocator->Clear( );
+
+ for ( input = 0; input < _inputs; ++input ) {
+ for ( int s = 0; s < _input_speedup; ++s ) {
+ expanded_input = s*_inputs + input;
+
+ // Arbitrate (round-robin) between multiple
+ // requesting VCs at the same input (handles
+ // the case when multiple VC's are requesting
+ // the same output port)
+ vc = _sw_rr_offset[ expanded_input ];
+
+ for ( int v = 0; v < _vcs; ++v ) {
+
+ // This continue acounts for the interleaving of
+ // VCs when input speedup is used
+ if ( ( vc % _input_speedup ) != s ) {
+ vc = ( vc + 1 ) % _vcs;
+ continue;
+ }
+
+ cur_vc = &_vc[input][vc];
+
+ if ( ( cur_vc->GetState( ) == VC::active ) &&
+ ( !cur_vc->Empty( ) ) ) {
+
+ dest_vc = &_next_vcs[cur_vc->GetOutputPort( )];
+
+ if ( !dest_vc->IsFullFor( cur_vc->GetOutputVC( ) ) ) {
+
+ // 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.
+
+ assert( expanded_input == (vc%_input_speedup)*_inputs + input );
+ expanded_output = (input%_output_speedup)*_outputs + cur_vc->GetOutputPort( );
+
+ if ( ( _switch_hold_in[expanded_input] == -1 ) &&
+ ( _switch_hold_out[expanded_output] == -1 ) ) {
+
+ // We could have requested this same input-output pair in a previous
+ // iteration, only replace the previous request if the current
+ // request has a higher priority (this is default behavior of the
+ // allocators). Switch allocation priorities are strictly
+ // determined by the packet priorities.
+
+ _sw_allocator->AddRequest( expanded_input, expanded_output, vc,
+ cur_vc->GetPriority( ),
+ cur_vc->GetPriority( ) );
+ }
+ }
+ }
+
+ vc = ( vc + 1 ) % _vcs;
+ }
+ }
+ }
+
+ _sw_allocator->Allocate( );
+
+ // Winning flits cross the switch
+
+ _crossbar_pipe->WriteAll( 0 );
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ c = 0;
+
+ for ( int s = 0; s < _input_speedup; ++s ) {
+
+ expanded_input = s*_inputs + input;
+
+ if ( _switch_hold_in[expanded_input] != -1 ) {
+ expanded_output = _switch_hold_in[expanded_input];
+ vc = _switch_hold_vc[expanded_input];
+ cur_vc = &_vc[input][vc];
+
+ if ( cur_vc->Empty( ) ) { // Cancel held match if VC is empty
+ expanded_output = -1;
+ }
+ } else {
+ expanded_output = _sw_allocator->OutputAssigned( expanded_input );
+ }
+
+ if ( expanded_output >= 0 ) {
+ output = expanded_output % _outputs;
+
+ if ( _switch_hold_in[expanded_input] == -1 ) {
+ vc = _sw_allocator->ReadRequest( expanded_input, expanded_output );
+ cur_vc = &_vc[input][vc];
+ }
+
+ if ( _hold_switch_for_packet ) {
+ _switch_hold_in[expanded_input] = expanded_output;
+ _switch_hold_vc[expanded_input] = vc;
+ _switch_hold_out[expanded_output] = expanded_input;
+ }
+
+ assert( ( cur_vc->GetState( ) == VC::active ) &&
+ ( !cur_vc->Empty( ) ) &&
+ ( cur_vc->GetOutputPort( ) == ( expanded_output % _outputs ) ) );
+
+ dest_vc = &_next_vcs[cur_vc->GetOutputPort( )];
+
+ assert( !dest_vc->IsFullFor( cur_vc->GetOutputVC( ) ) );
+
+ // Forward flit to crossbar and send credit back
+ f = cur_vc->RemoveFlit( );
+
+ f->hops++;
+
+ if ( f->watch ) {
+ cout << "Forwarding flit through crossbar at " << _fullname << ":" << endl;
+ cout << *f;
+ }
+
+ if ( !c ) {
+ c = _NewCredit( _vcs );
+ }
+
+ c->vc[c->vc_cnt] = f->vc;
+ c->vc_cnt++;
+
+ f->vc = cur_vc->GetOutputVC( );
+ dest_vc->SendingFlit( f );
+
+ _crossbar_pipe->Write( f, expanded_output );
+
+ if ( f->tail ) {
+ cur_vc->SetState( VC::idle );
+
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_out[expanded_output] = -1;
+ }
+
+ _sw_rr_offset[expanded_input] = ( f->vc + 1 ) % _vcs;
+ }
+ }
+
+ _credit_pipe->Write( c, input );
+ }
+}
+
+void IQRouter::_OutputQueuing( )
+{
+ Flit *f;
+ Credit *c;
+ int expanded_output;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ for ( int t = 0; t < _output_speedup; ++t ) {
+ expanded_output = _outputs*t + output;
+ f = _crossbar_pipe->Read( expanded_output );
+
+ if ( f ) {
+ _output_buffer[output].push( make_pair(f,_iq_time) );
+ }
+ }
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ c = _credit_pipe->Read( input );
+
+ if ( c ) {
+ _in_cred_buffer[input].push( c );
+ }
+ }
+}
+
+void IQRouter::_SendFlits( )
+{
+ Flit *f;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+
+ f = NULL;
+
+ if ( !_output_buffer[output].empty( ) ) {
+ if ((_iq_time - _output_buffer[output].front().second) >= _output_extra_latency) {
+ f = _output_buffer[output].front( ).first;
+ _output_buffer[output].pop( );
+ }
+ }
+
+ *(*_output_channels)[output] = f;
+ }
+}
+
+void IQRouter::_SendCredits( )
+{
+ Credit *c;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_in_cred_buffer[input].empty( ) ) {
+ c = _in_cred_buffer[input].front( );
+ _in_cred_buffer[input].pop( );
+ } else {
+ c = 0;
+ }
+
+ *(*_input_credits)[input] = c;
+ }
+}
+
+void IQRouter::Display( ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ for ( int v = 0; v < _vcs; ++v ) {
+ _vc[input][v].Display( );
+ }
+ }
+}
diff --git a/src/intersim/iq_router.hpp b/src/intersim/iq_router.hpp new file mode 100644 index 0000000..47db1fa --- /dev/null +++ b/src/intersim/iq_router.hpp @@ -0,0 +1,75 @@ +#ifndef _IQ_ROUTER_HPP_
+#define _IQ_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "vc.hpp"
+#include "allocator.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "buffer_state.hpp"
+#include "pipefifo.hpp"
+
+class IQRouter : public Router {
+ int _vcs;
+ int _vc_size;
+
+ int _iq_time;
+ int _output_extra_latency;
+
+ VC **_vc;
+ BufferState *_next_vcs;
+
+ Allocator *_vc_allocator;
+ Allocator *_sw_allocator;
+
+ int *_sw_rr_offset;
+
+ tRoutingFunction _rf;
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+ PipelineFIFO<Credit> *_credit_pipe;
+
+ queue<Flit *> *_input_buffer;
+ queue<pair<Flit *,int> > *_output_buffer;
+
+ queue<Credit *> *_in_cred_buffer;
+ queue<Credit *> *_out_cred_buffer;
+
+ int _hold_switch_for_packet;
+ int *_switch_hold_in;
+ int *_switch_hold_out;
+ int *_switch_hold_vc;
+
+ void _ReceiveFlits( );
+ void _ReceiveCredits( );
+
+ void _InputQueuing( );
+ void _Route( );
+ void _VCAlloc( );
+ void _SWAlloc( );
+ void _OutputQueuing( );
+
+ void _SendFlits( );
+ void _SendCredits( );
+
+ void _AddVCRequests( VC* cur_vc, int input_index, bool watch = false );
+
+public:
+ IQRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs );
+
+ virtual ~IQRouter( );
+
+ virtual void ReadInputs( );
+ virtual void InternalStep( );
+ virtual void WriteOutputs( );
+
+ void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/islip.cpp b/src/intersim/islip.cpp new file mode 100644 index 0000000..1aafacc --- /dev/null +++ b/src/intersim/islip.cpp @@ -0,0 +1,185 @@ +#include "booksim.hpp"
+#include <iostream>
+
+#include "islip.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_ISLIP
+
+iSLIP_Sparse::iSLIP_Sparse( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+SparseAllocator( config, parent, name, inputs, outputs )
+{
+ _iSLIP_iter = config.GetInt( "alloc_iters" );
+
+ _grants = new int [_outputs];
+ _gptrs = new int [_outputs];
+ _aptrs = new int [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _aptrs[i] = 0;
+ }
+ for ( int j = 0; j < _outputs; ++j ) {
+ _gptrs[j] = 0;
+ }
+}
+
+iSLIP_Sparse::~iSLIP_Sparse( )
+{
+ delete [] _grants;
+ delete [] _gptrs;
+ delete [] _aptrs;
+}
+
+void iSLIP_Sparse::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ list<sRequest>::iterator p;
+ bool wrapped;
+
+ _ClearMatching( );
+
+ for ( int iter = 0; iter < _iSLIP_iter; ++iter ) {
+ // Grant phase
+
+ for ( output = 0; output < _outputs; ++output ) {
+ _grants[output] = -1;
+
+ // 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->port < input_offset ) ) {
+ p++;
+ }
+
+ wrapped = false;
+ while ( (!wrapped) || ( p->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->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->port < output_offset ) ) {
+ p++;
+ }
+
+ wrapped = false;
+ int flag ;
+ if ( p != _in_req[input].end( ) ) {
+ flag= (p->port < output_offset) ;
+ } else {
+ flag = true;
+ }
+ while ( (!wrapped) || (flag) ) {
+ 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->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++;
+ if ( p != _in_req[input].end( ) ) {
+ flag= (p->port < output_offset) ;
+ } else {
+ flag = true;
+ }
+ }
+ }
+ }
+
+#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/intersim/islip.hpp b/src/intersim/islip.hpp new file mode 100644 index 0000000..a7b5242 --- /dev/null +++ b/src/intersim/islip.hpp @@ -0,0 +1,22 @@ +#ifndef _ISLIP_HPP_
+#define _ISLIP_HPP_
+
+#include "allocator.hpp"
+
+class iSLIP_Sparse : public SparseAllocator {
+ int _iSLIP_iter;
+
+ int *_grants;
+ int *_gptrs;
+ int *_aptrs;
+
+public:
+ iSLIP_Sparse( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ ~iSLIP_Sparse( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim/kncube.cpp b/src/intersim/kncube.cpp new file mode 100644 index 0000000..f4e1c71 --- /dev/null +++ b/src/intersim/kncube.cpp @@ -0,0 +1,253 @@ +#include "booksim.hpp"
+#include <vector>
+#include <sstream>
+
+#include "kncube.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+
+KNCube::KNCube( const Configuration &config, bool mesh ) :
+Network( config )
+{
+ _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;
+
+ _sources = _size;
+ _dests = _size;
+}
+
+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;
+
+ for ( int node = 0; node < _size; ++node ) {
+
+ router_name << "router";
+
+ 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 );
+
+ router_name.seekp( 0, ios::beg );
+
+ for ( int dim = 0; dim < _n; ++dim ) {
+
+ 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
+ //
+
+ right_input = _LeftChannel( right_node, dim );
+ left_input = _RightChannel( left_node, dim );
+
+ _routers[node]->AddInputChannel( &_chan[right_input], &_chan_cred[right_input] );
+ _routers[node]->AddInputChannel( &_chan[left_input], &_chan_cred[left_input] );
+
+ right_output = _RightChannel( node, dim );
+ left_output = _LeftChannel( node, dim );
+
+ _routers[node]->AddOutputChannel( &_chan[right_output], &_chan_cred[right_output] );
+ _routers[node]->AddOutputChannel( &_chan[left_output], &_chan_cred[left_output] );
+ }
+
+ _routers[node]->AddInputChannel( &_inject[node], &_inject_cred[node] );
+ _routers[node]->AddOutputChannel( &_eject[node], &_eject_cred[node] );
+ }
+}
+
+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;
+}
+
+void KNCube::InsertRandomFaults( const Configuration &config )
+{
+ int num_fails;
+ unsigned long prev_seed;
+
+ int node, chan;
+ int i, j, t, n, c;
+ bool *fail_nodes;
+ bool available;
+
+ bool edge;
+
+ num_fails = config.GetInt( "link_failures" );
+
+ if ( num_fails ) {
+ prev_seed = RandomIntLong( );
+ RandomSeed( config.GetInt( "fail_seed" ) );
+
+ fail_nodes = new bool [_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;
+ }
+
+ delete [] fail_nodes;
+
+ RandomSeed( prev_seed );
+ }
+}
+
+double KNCube::Capacity( ) const
+{
+ if ( _mesh ) {
+ return(double)_k / 4.0;
+ } else {
+ return(double)_k / 8.0;
+ }
+}
+
diff --git a/src/intersim/kncube.hpp b/src/intersim/kncube.hpp new file mode 100644 index 0000000..5aba886 --- /dev/null +++ b/src/intersim/kncube.hpp @@ -0,0 +1,33 @@ +#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, bool mesh );
+
+ int GetN( ) const;
+ int GetK( ) const;
+
+ double Capacity( ) const;
+
+ void InsertRandomFaults( const Configuration &config );
+};
+
+#endif
diff --git a/src/intersim/loa.cpp b/src/intersim/loa.cpp new file mode 100644 index 0000000..c7501f3 --- /dev/null +++ b/src/intersim/loa.cpp @@ -0,0 +1,102 @@ +#include "booksim.hpp"
+#include <iostream>
+
+#include "loa.hpp"
+#include "random_utils.hpp"
+
+LOA::LOA( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int input_speedup,
+ int outputs, int output_speedup ) :
+DenseAllocator( config, parent, name, inputs, outputs )
+{
+ _req = new int [_inputs];
+ _counts = new int [_outputs];
+
+ _rptr = new int [_inputs];
+ _gptr = new int [_outputs];
+}
+
+LOA::~LOA( )
+{
+ delete [] _req;
+ delete [] _counts;
+ delete [] _rptr;
+ delete [] _gptr;
+}
+
+void LOA::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ int lonely;
+ int lonely_cnt;
+
+ // Clear matching
+
+ // Count phase --- the number of requests
+ // per output is counted
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _inmatch[i] = -1;
+ }
+ for ( int j = 0; j < _outputs; ++j ) {
+ _outmatch[j] = -1;
+ _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/intersim/loa.hpp b/src/intersim/loa.hpp new file mode 100644 index 0000000..1adb4f9 --- /dev/null +++ b/src/intersim/loa.hpp @@ -0,0 +1,23 @@ +#ifndef _LOA_HPP_
+#define _LOA_HPP_
+
+#include "allocator.hpp"
+
+class LOA : public DenseAllocator {
+ int *_counts;
+ int *_req;
+
+ int *_rptr;
+ int *_gptr;
+
+public:
+ LOA( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int input_speedup,
+ int outputs, int output_speedup );
+ ~LOA( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim/maxsize.cpp b/src/intersim/maxsize.cpp new file mode 100644 index 0000000..3d1349a --- /dev/null +++ b/src/intersim/maxsize.cpp @@ -0,0 +1,181 @@ +#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( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+DenseAllocator( config, parent, name, inputs, outputs )
+{
+ _from = new int [_outputs];
+ _s = new int [_inputs];
+ _ns = new int [_inputs];
+}
+
+MaxSizeMatch::~MaxSizeMatch( )
+{
+ delete [] _from;
+ delete [] _s;
+ delete [] _ns;
+}
+
+void MaxSizeMatch::Allocate( )
+{
+ // clear matching
+ for ( int i = 0; i < _inputs; ++i ) {
+ _inmatch[i] = -1;
+ }
+ for ( int j = 0; j < _outputs; ++j ) {
+ _outmatch[j] = -1;
+ }
+
+ // augment as many times as possible
+ // (this is an O(N^3) maximum-size matching algorithm)
+ while ( _ShortestAugmenting( ) );
+}
+
+
+bool MaxSizeMatch::_ShortestAugmenting( )
+{
+ int i, j, jn;
+ int slen, nslen;
+ int *t;
+
+ slen = 0;
+ for ( i = 0; i < _inputs; ++i ) {
+ if ( _inmatch[i] == -1 ) { // start with unmatched left nodes
+ _s[slen] = i;
+ slen++;
+ }
+ _from[i] = -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
+ 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/intersim/maxsize.hpp b/src/intersim/maxsize.hpp new file mode 100644 index 0000000..dcd4b39 --- /dev/null +++ b/src/intersim/maxsize.hpp @@ -0,0 +1,22 @@ +#ifndef _MAXSIZE_HPP_
+#define _MAXSIZE_HPP_
+
+#include "allocator.hpp"
+
+class MaxSizeMatch : public DenseAllocator {
+ int *_from; // array to hold breadth-first tree
+ int *_s; // stack of leaf nodes in tree
+ int *_ns; // next stack
+
+ bool _ShortestAugmenting( );
+
+public:
+ MaxSizeMatch( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int ouputs );
+ ~MaxSizeMatch( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim/misc_utils.cpp b/src/intersim/misc_utils.cpp new file mode 100644 index 0000000..6ba6a20 --- /dev/null +++ b/src/intersim/misc_utils.cpp @@ -0,0 +1,25 @@ +#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/intersim/misc_utils.hpp b/src/intersim/misc_utils.hpp new file mode 100644 index 0000000..856cbb7 --- /dev/null +++ b/src/intersim/misc_utils.hpp @@ -0,0 +1,7 @@ +#ifndef _MISC_UTILS_HPP_
+#define _MISC_UTILS_HPP_
+
+int log_two( int x );
+int powi( int x, int y );
+
+#endif
diff --git a/src/intersim/module.cpp b/src/intersim/module.cpp new file mode 100644 index 0000000..e0a2289 --- /dev/null +++ b/src/intersim/module.cpp @@ -0,0 +1,63 @@ +#include "booksim.hpp"
+#include <iostream>
+#include <stdlib.h>
+
+#include "module.hpp"
+
+Module::Module( )
+{
+}
+
+Module::Module( Module *parent, const string& name )
+{
+ SetName( parent, name );
+}
+
+void Module::_AddChild( Module *child )
+{
+ _children.push_back( child );
+}
+
+void Module::SetName( Module *parent, const string& name )
+{
+ _name = name;
+
+ if ( parent ) {
+ parent->_AddChild( this );
+ _fullname = parent->_fullname + "/" + name;
+ } else {
+ _fullname = name;
+ }
+}
+
+void Module::DisplayHierarchy( int level ) const
+{
+ vector<Module *>::const_iterator mod_iter;
+
+ for ( int l = 0; l < level; l++ ) {
+ cout << " ";
+ }
+
+ cout << _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( ) const
+{
+ cout << "Display method not implemented for " << _fullname << endl;
+}
diff --git a/src/intersim/module.hpp b/src/intersim/module.hpp new file mode 100644 index 0000000..5acf0a2 --- /dev/null +++ b/src/intersim/module.hpp @@ -0,0 +1,33 @@ +#ifndef _MODULE_HPP_
+#define _MODULE_HPP_
+
+#include "booksim.hpp"
+
+#include <string>
+#include <vector>
+
+class Module {
+protected:
+ string _name;
+ string _fullname;
+
+ vector<Module *> _children;
+
+ void _AddChild( Module *child );
+
+public:
+ Module( );
+ Module( Module *parent, const string& name );
+ virtual ~Module( ) {}
+
+ void SetName( Module *parent, const string& name );
+
+ void DisplayHierarchy( int level = 0 ) const;
+
+ void Error( const string& msg ) const;
+ void Debug( const string& msg ) const;
+
+ virtual void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/network.cpp b/src/intersim/network.cpp new file mode 100644 index 0000000..48c07b4 --- /dev/null +++ b/src/intersim/network.cpp @@ -0,0 +1,156 @@ +#include "booksim.hpp"
+#include "interconnect_interface.h"
+#include <assert.h>
+
+#include "network.hpp"
+
+int gK = 0;
+int gN = 0;
+int gNodes = 0;
+
+Network::Network( const Configuration &config ) :
+Module( 0, "network" )
+{
+ _size = -1;
+ _sources = -1;
+ _dests = -1;
+ _channels = -1;
+}
+
+Network::~Network( )
+{
+ for ( int r = 0; r < _size; ++r ) {
+ delete _routers[r];
+ }
+
+ delete [] _routers;
+
+ delete [] _inject;
+ delete [] _eject;
+ delete [] _chan;
+
+ delete [] _chan_use;
+
+ delete [] _inject_cred;
+ delete [] _eject_cred;
+ delete [] _chan_cred;
+}
+
+void Network::_Alloc( )
+{
+ assert( ( _size != -1 ) &&
+ ( _sources != -1 ) &&
+ ( _dests != -1 ) &&
+ ( _channels != -1 ) );
+
+ _routers = new Router * [_size];
+ gNodes = _sources;
+
+ _inject = new Flit * [_sources];
+ _eject = new Flit * [_dests];
+ _chan = new Flit * [_channels];
+
+ _chan_use = new int [_channels];
+
+ for ( int i = 0; i < _channels; ++i ) {
+ _chan_use[i] = 0;
+ }
+
+ _chan_use_cycles = 0;
+
+ _inject_cred = new Credit * [_sources];
+ _eject_cred = new Credit * [_dests];
+ _chan_cred = new Credit * [_channels];
+}
+
+int Network::NumSources( ) const
+{
+ return _sources;
+}
+
+int Network::NumDests( ) const
+{
+ return _dests;
+}
+
+void Network::ReadInputs( )
+{
+ for ( int r = 0; r < _size; ++r ) {
+ _routers[r]->ReadInputs( );
+ }
+}
+
+void Network::InternalStep( )
+{
+ for ( int r = 0; r < _size; ++r ) {
+ _routers[r]->InternalStep( );
+ }
+}
+
+void Network::WriteOutputs( )
+{
+ for ( int r = 0; r < _size; ++r ) {
+ _routers[r]->WriteOutputs( );
+ }
+
+ for ( int c = 0; c < _channels; ++c ) {
+ if ( _chan[c] ) {
+ _chan_use[c]++;
+ }
+ }
+ _chan_use_cycles++;
+}
+
+void Network::WriteFlit( Flit *f, int source )
+{
+ assert( ( source >= 0 ) && ( source < _sources ) );
+ _inject[source] = f;
+}
+
+Flit *Network::ReadFlit( int dest )
+{
+ assert( ( dest >= 0 ) && ( dest < _dests ) );
+ return _eject[dest];
+}
+
+void Network::WriteCredit( Credit *c, int dest )
+{
+ assert( ( dest >= 0 ) && ( dest < _dests ) );
+ _eject_cred[dest] = c;
+}
+
+Credit *Network::ReadCredit( int source )
+{
+ assert( ( source >= 0 ) && ( source < _sources ) );
+ return _inject_cred[source];
+}
+
+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;
+}
+
+void Network::Display( ) const
+{
+ for ( int r = 0; r < _size; ++r ) {
+ _routers[r]->Display( );
+ }
+// if (icnt_config.GetInt("blah") ) {
+ for ( int c = 0; c < _channels; ++c ) {
+ cout << "channel " << c << " used "
+ << 100.0 * (double)_chan_use[c] / (double)_chan_use_cycles
+ << "% of the time" << endl;
+ }
+ // }
+}
diff --git a/src/intersim/network.hpp b/src/intersim/network.hpp new file mode 100644 index 0000000..601ac7a --- /dev/null +++ b/src/intersim/network.hpp @@ -0,0 +1,72 @@ +#ifndef _NETWORK_HPP_
+#define _NETWORK_HPP_
+
+#include <vector>
+
+#include "module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "router.hpp"
+#include "module.hpp"
+
+#include "config_utils.hpp"
+
+extern int gN;
+extern int gK;
+
+extern int gNodes;
+
+class Network : public Module {
+protected:
+
+ int _size;
+ int _sources;
+ int _dests;
+ int _channels;
+
+ Router **_routers;
+
+ Flit **_inject;
+ Credit **_inject_cred;
+
+ Flit **_eject;
+ Credit **_eject_cred;
+
+ Flit **_chan;
+ Credit **_chan_cred;
+
+ int *_chan_use;
+ int _chan_use_cycles;
+
+ virtual void _ComputeSize( const Configuration &config ) = 0;
+ virtual void _BuildNet( const Configuration &config ) = 0;
+
+ void _Alloc( );
+
+public:
+ Network( const Configuration &config );
+ virtual ~Network( );
+
+ void WriteFlit( Flit *f, int source );
+ Flit *ReadFlit( int dest );
+
+ void WriteCredit( Credit *c, int dest );
+ Credit *ReadCredit( int source );
+
+ int NumSources( ) const;
+ int NumDests( ) const;
+
+ virtual void InsertRandomFaults( const Configuration &config );
+ void OutChannelFault( int r, int c, bool fault = true );
+
+ virtual double Capacity( ) const;
+
+ void ReadInputs( );
+ void InternalStep( );
+ void WriteOutputs( );
+
+ void Display( ) const;
+};
+
+#endif
+
diff --git a/src/intersim/outputset.cpp b/src/intersim/outputset.cpp new file mode 100644 index 0000000..b3970dd --- /dev/null +++ b/src/intersim/outputset.cpp @@ -0,0 +1,134 @@ +#include "booksim.hpp"
+#include <assert.h>
+
+#include "outputset.hpp"
+
+OutputSet::OutputSet( int num_outputs )
+{
+ _num_outputs = num_outputs;
+
+ _outputs = new list<sSetElement> [_num_outputs];
+}
+
+OutputSet::~OutputSet( )
+{
+ delete [] _outputs;
+}
+
+void OutputSet::Clear( )
+{
+ for ( int i = 0; i < _num_outputs; ++i ) {
+ _outputs[i].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 )
+{
+ assert( ( output_port >= 0 ) &&
+ ( output_port < _num_outputs ) &&
+ ( vc_start <= vc_end ) );
+
+ sSetElement s;
+
+ s.vc_start = vc_start;
+ s.vc_end = vc_end;
+ s.pri = pri;
+
+ _outputs[output_port].push_back( s );
+}
+
+int OutputSet::Size( ) const
+{
+ return _num_outputs;
+}
+
+bool OutputSet::OutputEmpty( int output_port ) const
+{
+ assert( ( output_port >= 0 ) &&
+ ( output_port < _num_outputs ) );
+
+ return _outputs[output_port].empty( );
+}
+
+int OutputSet::NumVCs( int output_port ) const
+{
+ assert( ( output_port >= 0 ) &&
+ ( output_port < _num_outputs ) );
+
+ int total = 0;
+
+ for ( list<sSetElement>::const_iterator i = _outputs[output_port].begin( );
+ i != _outputs[output_port].end( ); i++ ) {
+ total += i->vc_end - i->vc_start + 1;
+ }
+
+ return total;
+}
+
+int OutputSet::GetVC( int output_port, int vc_index, int *pri ) const
+{
+ assert( ( output_port >= 0 ) &&
+ ( output_port < _num_outputs ) );
+
+ int range;
+ int remaining = vc_index;
+ int vc = -1;
+
+ if ( pri ) {
+ *pri = -1;
+ }
+
+ for ( list<sSetElement>::const_iterator i = _outputs[output_port].begin( );
+ i != _outputs[output_port].end( ); i++ ) {
+
+ 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;
+ }
+ }
+
+ return vc;
+}
+
+bool OutputSet::GetPortVC( int *out_port, int *out_vc ) const
+{
+ bool single_output = false;
+ int used_outputs = 0;
+
+ for ( int output = 0; output < _num_outputs; ++output ) {
+
+ list<sSetElement>::const_iterator i = _outputs[output].begin( );
+
+ if ( i != _outputs[output].end( ) ) {
+ ++used_outputs;
+
+ if ( i->vc_start == i->vc_end ) {
+ *out_vc = i->vc_start;
+ *out_port = output;
+ single_output = true;
+ } else {
+ // multiple vc's selected
+ break;
+ }
+ }
+
+ if ( used_outputs > 1 ) {
+ // multiple outputs selected
+ single_output = false;
+ break;
+ }
+ }
+
+ return single_output;
+}
diff --git a/src/intersim/outputset.hpp b/src/intersim/outputset.hpp new file mode 100644 index 0000000..ad8d2ad --- /dev/null +++ b/src/intersim/outputset.hpp @@ -0,0 +1,36 @@ +#ifndef _OUTPUTSET_HPP_
+#define _OUTPUTSET_HPP_
+
+#include <queue>
+#include <list>
+
+class OutputSet {
+ int _num_outputs;
+
+ struct sSetElement {
+ int vc_start;
+ int vc_end;
+ int pri;
+ };
+
+ list<sSetElement> *_outputs;
+
+public:
+ OutputSet( int num_outputs );
+ ~OutputSet( );
+
+ 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 );
+
+ int Size( ) const;
+ bool OutputEmpty( int output_port ) const;
+ int NumVCs( int output_port ) const;
+
+ int GetVC( int output_port, int vc_index, int *pri = 0 ) const;
+ bool GetPortVC( int *out_port, int *out_vc ) const;
+};
+
+#endif
+
+
diff --git a/src/intersim/pim.cpp b/src/intersim/pim.cpp new file mode 100644 index 0000000..be5872c --- /dev/null +++ b/src/intersim/pim.cpp @@ -0,0 +1,98 @@ +#include "booksim.hpp"
+#include <iostream>
+
+#include "pim.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_PIM
+
+PIM::PIM( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+DenseAllocator( config, parent, name, inputs, outputs )
+{
+ _PIM_iter = config.GetInt( "alloc_iters" );
+
+ _grants = new int [_outputs];
+}
+
+PIM::~PIM( )
+{
+ delete [] _grants;
+}
+
+void PIM::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ _ClearMatching( );
+
+ for ( int iter = 0; iter < _PIM_iter; ++iter ) {
+ // Grant phase --- outputs randomly choose
+ // between one of their requests
+
+ for ( output = 0; output < _outputs; ++output ) {
+ _grants[output] = -1;
+
+ // 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/intersim/pim.hpp b/src/intersim/pim.hpp new file mode 100644 index 0000000..1ce5535 --- /dev/null +++ b/src/intersim/pim.hpp @@ -0,0 +1,20 @@ +#ifndef _PIM_HPP_
+#define _PIM_HPP_
+
+#include "allocator.hpp"
+
+class PIM : public DenseAllocator {
+ int _PIM_iter;
+
+ int *_grants;
+public:
+ PIM( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+
+ ~PIM( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim/pipefifo.hpp b/src/intersim/pipefifo.hpp new file mode 100644 index 0000000..8d434d8 --- /dev/null +++ b/src/intersim/pipefifo.hpp @@ -0,0 +1,76 @@ +#ifndef _PIPEFIFO_HPP_
+#define _PIPEFIFO_HPP_
+
+#include "module.hpp"
+
+template<class T> class PipelineFIFO : public Module {
+ int _lanes;
+ int _depth;
+
+ int _pipe_len;
+ int _pipe_ptr;
+
+ 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 = new T ** [_lanes];
+ for ( int l = 0; l < _lanes; ++l ) {
+ _data[l] = new T * [_pipe_len];
+
+ for ( int d = 0; d < _pipe_len; ++d ) {
+ _data[l][d] = 0;
+ }
+ }
+}
+
+template<class T> PipelineFIFO<T>::~PipelineFIFO( )
+{
+ for ( int l = 0; l < _lanes; ++l ) {
+ delete [] _data[l];
+ }
+ delete [] _data;
+}
+
+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/intersim/random_utils.cpp b/src/intersim/random_utils.cpp new file mode 100644 index 0000000..94a0ad5 --- /dev/null +++ b/src/intersim/random_utils.cpp @@ -0,0 +1,25 @@ +#include "booksim.hpp"
+#include "random_utils.hpp"
+
+void RandomSeed( long seed )
+{
+ ran_start( seed );
+ ranf_start( seed );
+}
+
+int RandomInt( int max )
+// Returns a random integer in the range [0,max]
+{
+ return( ran_next( ) % (max+1) );
+}
+
+unsigned long RandomIntLong( )
+{
+ return ran_next( );
+}
+
+float RandomFloat( float max )
+// Returns a random floating-point value in the rage [0,max]
+{
+ return( ranf_next( ) * max );
+}
diff --git a/src/intersim/random_utils.hpp b/src/intersim/random_utils.hpp new file mode 100644 index 0000000..290953d --- /dev/null +++ b/src/intersim/random_utils.hpp @@ -0,0 +1,21 @@ +#ifndef _RANDOM_UTILS_HPP_
+#define _RANDOM_UTILS_HPP_
+
+#include "rng.hpp"
+
+#ifdef USE_TWISTER
+extern unsigned long int_genrand( );
+extern void int_lsgenrand( unsigned long seed_array[] );
+extern void int_sgenrand( unsigned long seed );
+
+extern double float_genrand( );
+extern void float_lsgenrand( unsigned long seed_array[] );
+extern void float_sgenrand( unsigned long seed );
+#endif
+
+void RandomSeed( long seed );
+int RandomInt( int max ) ;
+float RandomFloat( float max = 1.0 );
+unsigned long RandomIntLong( );
+
+#endif
diff --git a/src/intersim/rng.cpp b/src/intersim/rng.cpp new file mode 100644 index 0000000..47ddda3 --- /dev/null +++ b/src/intersim/rng.cpp @@ -0,0 +1,111 @@ +/* This program by D E Knuth is in the public domain and freely copyable
+ * AS LONG AS YOU MAKE ABSOLUTELY NO CHANGES!
+ * 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[100]=-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/intersim/rng.hpp b/src/intersim/rng.hpp new file mode 100644 index 0000000..db09172 --- /dev/null +++ b/src/intersim/rng.hpp @@ -0,0 +1,10 @@ +#ifndef _RNG_HPP_
+#define _RNG_HPP_
+
+void ran_start(long seed);
+long ran_next( );
+
+void ranf_start(long seed);
+double ranf_next( );
+
+#endif
diff --git a/src/intersim/rng_double.cpp b/src/intersim/rng_double.cpp new file mode 100644 index 0000000..58a3c2c --- /dev/null +++ b/src/intersim/rng_double.cpp @@ -0,0 +1,115 @@ +/* This program by D E Knuth is in the public domain and freely copyable
+* AS LONG AS YOU MAKE ABSOLUTELY NO CHANGES!
+* 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[100]=-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/intersim/rng_double_wrapper.cpp b/src/intersim/rng_double_wrapper.cpp new file mode 100644 index 0000000..d54ca59 --- /dev/null +++ b/src/intersim/rng_double_wrapper.cpp @@ -0,0 +1,9 @@ +#include "rng.hpp"
+
+#define main rng_double_main
+#include "rng_double.cpp"
+
+double ranf_next( )
+{
+ return ranf_arr_next( );
+}
diff --git a/src/intersim/rng_wrapper.cpp b/src/intersim/rng_wrapper.cpp new file mode 100644 index 0000000..0bfc669 --- /dev/null +++ b/src/intersim/rng_wrapper.cpp @@ -0,0 +1,9 @@ +#include "rng.hpp"
+
+#define main rng_main
+#include "rng.cpp"
+
+long ran_next( )
+{
+ return ran_arr_next( );
+}
diff --git a/src/intersim/routefunc.cpp b/src/intersim/routefunc.cpp new file mode 100644 index 0000000..055baf8 --- /dev/null +++ b/src/intersim/routefunc.cpp @@ -0,0 +1,1045 @@ +#include "booksim.hpp"
+
+#include <map>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "routefunc.hpp"
+#include "kncube.hpp"
+#include "random_utils.hpp"
+
+map<string, tRoutingFunction> gRoutingFunctionMap;
+
+/* Global information used by routing functions */
+
+int gNumVCS;
+
+/* Add routing functions here */
+
+//=============================================================
+
+void singlerf( const Router *, const Flit *f, int, OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+ outputs->Add( f->dest, f->dest % gNumVCS ); // VOQing
+}
+
+//=============================================================
+
+int dor_next_mesh( int cur, int dest )
+{
+ int dim_left;
+ int out_port;
+
+ for ( dim_left = 0; dim_left < gN; ++dim_left ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ break;
+ }
+ cur /= gK; dest /= gK;
+ }
+
+ if ( dim_left < gN ) {
+ cur %= gK; dest %= gK;
+
+ if ( cur < dest ) {
+ out_port = 2*dim_left; // Right
+ } else {
+ out_port = 2*dim_left + 1; // Left
+ }
+ } else {
+ out_port = 2*gN; // Eject
+ }
+
+ return out_port;
+}
+
+//=============================================================
+
+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 ( 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;
+
+ outputs->Clear( );
+
+ if ( inject ) { // use any VC for injection
+ outputs->AddRange( 0, 0, gNumVCS - 1 );
+ } else {
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << 0 << "," << gNumVCS - 1 << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, 0, gNumVCS - 1 );
+ }
+}
+
+//=============================================================
+
+void dim_order_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int vcs_per_dest = gNumVCS / gNodes;
+
+ outputs->Clear( );
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << f->dest*vcs_per_dest << "," << (f->dest+1)*vcs_per_dest - 1
+ << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, f->dest*vcs_per_dest, (f->dest+1)*vcs_per_dest - 1 );
+}
+
+//=============================================================
+
+// 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 out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 1; // Phase 1
+ f->intm = rand_min_intr_mesh( f->src, f->dest );
+ }
+
+ if ( ( f->ph == 1 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 2; // Go to phase 2
+ }
+
+ if ( f->ph == 1 ) { // In phase 1
+ out_port = dor_next_mesh( r->GetID( ), f->intm );
+ vc_min = 0;
+ vc_max = gNumVCS/2 - 1;
+ } else { // In phase 2
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+ vc_min = gNumVCS/2;
+ vc_max = gNumVCS - 1;
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void romm_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int vcs_per_dest = gNumVCS / gNodes;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 1; // Phase 1
+ f->intm = rand_min_intr_mesh( f->src, f->dest );
+ }
+
+ if ( ( f->ph == 1 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 2; // Go to phase 2
+ }
+
+ if ( f->ph == 1 ) { // In phase 1
+ out_port = dor_next_mesh( r->GetID( ), f->intm );
+ } else { // In phase 2
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+ }
+
+ outputs->AddRange( out_port, f->dest*vcs_per_dest, (f->dest+1)*vcs_per_dest - 1 );
+}
+
+//=============================================================
+
+void min_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int cur, dest;
+ int in_vc;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ in_vc = gNumVCS - 1; // ignore the injection VC
+ } else {
+ in_vc = f->vc;
+ }
+
+ // DOR for the escape channel (VC 0), low priority
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+ outputs->AddRange( out_port, 0, 0, 0 );
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << 0 << "," << gNumVCS - 1 << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ if ( in_vc != 0 ) { // If not in the escape VC
+ // Minimal adaptive for all other channels
+ cur = r->GetID( ); 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
+ outputs->AddRange( 2*n, 1, gNumVCS - 1, 1 );
+ } else { // Left
+ outputs->AddRange( 2*n + 1, 1, gNumVCS - 1, 1 );
+ }
+ }
+ cur /= gK;
+ dest /= gK;
+ }
+ }
+}
+
+//=============================================================
+
+void planar_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int cur, dest;
+ int vc_mult;
+ int vc_min, vc_max;
+ int d1_min_c;
+ int in_vc;
+ int n;
+
+ bool increase;
+ bool fault;
+ bool atedge;
+
+ outputs->Clear( );
+
+ cur = r->GetID( );
+ dest = f->dest;
+ in_vc = f->vc;
+ vc_mult = gNumVCS / 3;
+
+ if ( cur != dest ) {
+
+ // 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.
+
+ for ( n = 0; n < gN; ++n ) {
+ if ( ( ( cur % gK ) != ( dest % gK ) ) &&
+ !( ( in_channel/2 == 0 ) &&
+ ( n == 0 ) &&
+ ( in_vc < 2*vc_mult ) ) ) {
+ break;
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+
+ assert( n < gN );
+
+ if ( f->watch ) {
+ cout << "PLANAR ADAPTIVE: flit " << f->id
+ << " in adaptive plane " << n << " at " << r->GetID( ) << endl;
+ }
+
+ // We're in adaptive plane n
+
+ // Can route productively in d_{i,2}
+ if ( ( cur % gK ) < ( dest % gK ) ) { // Increasing
+ increase = true;
+ if ( !r->IsFaultyOutput( 2*n ) ) {
+ outputs->AddRange( 2*n, 2*vc_mult, gNumVCS - 1 );
+ fault = false;
+
+ if ( f->watch ) {
+ cout << "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, 2*vc_mult, gNumVCS - 1 );
+ fault = false;
+
+ if ( f->watch ) {
+ cout << "PLANAR ADAPTIVE: decreasing in dimension " << n << endl;
+ }
+ } else {
+ fault = true;
+ }
+ }
+
+ n = ( n + 1 ) % gN;
+ cur /= gK;
+ dest /= gK;
+
+ if ( increase ) {
+ vc_min = 0;
+ vc_max = vc_mult - 1;
+ } else {
+ vc_min = vc_mult;
+ vc_max = 2*vc_mult - 1;
+ }
+
+ 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 ) {
+ cout << "PLANAR ADAPTIVE: avoiding 180 in dimension " << n << endl;
+ }
+ }
+
+ if ( d1_min_c != -1 ) {
+ if ( !r->IsFaultyOutput( d1_min_c ) ) {
+ outputs->AddRange( d1_min_c, vc_min, vc_max );
+ } 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!
+ 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, vc_min, vc_max );
+ } else if ( !atedge && !r->IsFaultyOutput( d1_min_c ^ 1 ) ) {
+ outputs->AddRange( d1_min_c ^ 1, vc_min, vc_max );
+ } 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, 0, gNumVCS - 1 );
+ }
+}
+
+//=============================================================
+
+void limited_adapt_mesh_old( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int in_vc;
+ int in_dim;
+
+ int min_port;
+
+ bool dor_dim;
+ bool equal;
+
+ int cur, dest;
+
+ outputs->Clear( );
+
+ if ( inject ) {
+ outputs->AddRange( 0, 0, gNumVCS - 1 );
+ f->ph = 0; // zero dimension reversals
+ } else {
+
+ cur = r->GetID( ); dest = f->dest;
+ if ( cur != dest ) {
+
+ if ( f->ph == 0 ) {
+ f->ph = 1;
+
+ in_vc = 0;
+ in_dim = 0;
+ } else {
+ in_vc = f->vc;
+ in_dim = in_channel/2;
+ }
+
+ // The first remaining is the DOR escape path
+ dor_dim = true;
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ if ( ( cur % gK ) < ( dest % gK ) ) {
+ min_port = 2*n; // Right
+ } else {
+ min_port = 2*n + 1; // Left
+ }
+
+ if ( dor_dim ) {
+ // Low priority escape path
+ outputs->AddRange( min_port, gNumVCS - 1, gNumVCS - 1, 0 );
+ dor_dim = false;
+ }
+
+ equal = false;
+ } else {
+ equal = true;
+ min_port = 2*n;
+ }
+
+ if ( in_vc < gNumVCS - 1 ) { // adaptive VC's left?
+ if ( n < in_dim ) {
+ // Productive (minimal) direction, with reversal
+ if ( in_vc == gNumVCS - 2 ) {
+ outputs->AddRange( min_port, in_vc + 1, in_vc + 1, equal ? 1 : 2 );
+ } else {
+ outputs->AddRange( min_port, in_vc + 1, gNumVCS - 2, equal ? 1 : 2 );
+ }
+
+ // Unproductive (non-minimal) direction, with reversal
+ if ( in_vc < gNumVCS - 2 ) {
+ if ( in_vc == gNumVCS - 3 ) {
+ outputs->AddRange( min_port ^ 0x1, in_vc + 1, in_vc + 1, 1 );
+ } else {
+ outputs->AddRange( min_port ^ 0x1, in_vc + 1, gNumVCS - 3, 1 );
+ }
+ }
+ } else if ( n == in_dim ) {
+ if ( !equal ) {
+ // Productive (minimal) direction, no reversal
+ outputs->AddRange( min_port, in_vc, gNumVCS - 2, 4 );
+ }
+ } else {
+ // Productive (minimal) direction, no reversal
+ outputs->AddRange( min_port, in_vc, gNumVCS - 2, equal ? 1 : 3 );
+ // Unproductive (non-minimal) direction, no reversal
+ if ( in_vc < gNumVCS - 2 ) {
+ outputs->AddRange( min_port ^ 0x1, in_vc, gNumVCS - 2, 1 );
+ }
+ }
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+ } else { // at destination
+ outputs->AddRange( 2*gN, 0, gNumVCS - 1 );
+ }
+ }
+}
+
+void limited_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int min_port;
+
+ int cur, dest;
+
+ outputs->Clear( );
+
+ if ( inject ) {
+ outputs->AddRange( 0, 0, gNumVCS - 2 );
+ f->dr = 0; // zero dimension reversals
+ } else {
+ cur = r->GetID( ); dest = f->dest;
+
+ if ( cur != dest ) {
+ if ( ( f->vc != gNumVCS - 1 ) &&
+ ( f->dr != gNumVCS - 2 ) ) {
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ 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, 0, gNumVCS - 2, 2 );
+
+ // Go in the non-productive direction with low priority
+ outputs->AddRange( min_port ^ 0x1, 0, gNumVCS - 2, 1 );
+ } else {
+ // Both directions are non-productive
+ outputs->AddRange( 2*n, 0, gNumVCS - 2, 1 );
+ outputs->AddRange( 2*n+1, 0, gNumVCS - 2, 1 );
+ }
+
+ cur /= gK;
+ dest /= gK;
+ }
+
+ } else {
+ outputs->AddRange( dor_next_mesh( cur, dest ),
+ gNumVCS - 1, gNumVCS - 1, 0 );
+ }
+
+ } else { // at destination
+ outputs->AddRange( 2*gN, 0, gNumVCS - 1 );
+ }
+ }
+}
+
+//=============================================================
+
+void valiant_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 1; // Phase 1
+ f->intm = RandomInt( gNodes - 1 );
+ }
+
+ if ( ( f->ph == 1 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 2; // Go to phase 2
+ }
+
+ if ( f->ph == 1 ) { // In phase 1
+ out_port = dor_next_mesh( r->GetID( ), f->intm );
+ vc_min = 0;
+ vc_max = gNumVCS/2 - 1;
+ } else { // In phase 2
+ out_port = dor_next_mesh( r->GetID( ), f->dest );
+ vc_min = gNumVCS/2;
+ vc_max = gNumVCS - 1;
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void valiant_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 1; // Phase 1
+ f->intm = RandomInt( gNodes - 1 );
+ }
+
+ if ( ( f->ph == 1 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 2; // Go to phase 2
+ in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2
+ }
+
+ if ( f->ph == 1 ) { // In phase 1
+ dor_next_torus( r->GetID( ), f->intm, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = 0;
+ vc_max = gNumVCS/4 - 1;
+ } else {
+ vc_min = gNumVCS/4;
+ vc_max = gNumVCS/2 - 1;
+ }
+ } else { // In phase 2
+ dor_next_torus( r->GetID( ), f->dest, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = gNumVCS/2;
+ vc_max = (3*gNumVCS)/4 - 1;
+ } else {
+ vc_min = (3*gNumVCS)/4;
+ vc_max = gNumVCS - 1;
+ }
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void valiant_ni_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ f->ph = 1; // Phase 1
+ f->intm = RandomInt( gNodes - 1 );
+ }
+
+ if ( ( f->ph == 1 ) && ( r->GetID( ) == f->intm ) ) {
+ f->ph = 2; // Go to phase 2
+ in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2
+ }
+
+ if ( f->ph == 1 ) { // In phase 1
+ dor_next_torus( r->GetID( ), f->intm, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = f->dest;
+ vc_max = f->dest;
+ } else {
+ vc_min = f->dest + gNodes;
+ vc_max = f->dest + gNodes;
+ }
+
+ } else { // In phase 2
+ dor_next_torus( r->GetID( ), f->dest, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = f->dest + 2*gNodes;
+ vc_max = f->dest + 2*gNodes;
+ } else {
+ vc_min = f->dest + 3*gNodes;
+ vc_max = f->dest + 3*gNodes;
+ }
+ }
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << vc_min << "," << vc_max
+ << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void dim_order_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int cur;
+ int dest;
+
+ int out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+ cur = r->GetID( );
+ dest = f->dest;
+
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = 0;
+ vc_max = gNumVCS/2 - 1;
+ } else {
+ vc_min = gNumVCS/2;
+ vc_max = gNumVCS - 1;
+ }
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << vc_min << "," << vc_max << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void dim_order_ni_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int cur;
+ int dest;
+
+ int out_port;
+ int vcs_per_dest = gNumVCS / gNodes;
+
+ outputs->Clear( );
+
+ cur = r->GetID( );
+ dest = f->dest;
+
+ outputs->Clear( );
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ring_par, false );
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << f->dest*vcs_per_dest << "," << (f->dest+1)*vcs_per_dest - 1
+ << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, f->dest*vcs_per_dest, (f->dest+1)*vcs_per_dest - 1 );
+}
+
+//=============================================================
+
+void dim_order_bal_torus( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ int cur;
+ int dest;
+
+ int out_port;
+ int vc_min, vc_max;
+
+ outputs->Clear( );
+
+ cur = r->GetID( );
+ dest = f->dest;
+
+ dor_next_torus( cur, dest, in_channel,
+ &out_port, &f->ring_par, true );
+
+ if ( f->ring_par == 0 ) {
+ vc_min = 0;
+ vc_max = gNumVCS/2 - 1;
+ } else {
+ vc_min = gNumVCS/2;
+ vc_max = gNumVCS - 1;
+ }
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << vc_min << "," << vc_max << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+ outputs->AddRange( out_port, vc_min, vc_max );
+}
+
+//=============================================================
+
+void min_adapt_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject )
+{
+ int cur, dest, dist2;
+ int in_vc;
+ int out_port;
+
+ outputs->Clear( );
+
+ if ( in_channel == 2*gN ) {
+ in_vc = gNumVCS - 1; // ignore the injection VC
+ } else {
+ in_vc = f->vc;
+ }
+
+ if ( in_vc > 1 ) { // If not in the escape VCs
+ // Minimal adaptive for all other channels
+ cur = r->GetID( ); dest = f->dest;
+
+ for ( int n = 0; n < gN; ++n ) {
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ dist2 = gK - 2 * ( ( ( dest % gK ) - ( cur % gK ) + gK ) % gK );
+
+ if ( dist2 > 0 ) { /*) ||
+ ( ( dist2 == 0 ) && ( RandomInt( 1 ) ) ) ) {*/
+ outputs->AddRange( 2*n, 3, 3, 1 ); // Right
+ } else {
+ outputs->AddRange( 2*n + 1, 3, 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->ring_par, false );
+ } else {
+ // DOR for the escape channel (VCs 0-1), low priority
+ dor_next_torus( r->GetID( ), f->dest, in_channel,
+ &out_port, &f->ring_par, false );
+ }
+
+ if ( f->ring_par == 0 ) {
+ outputs->AddRange( out_port, 0, 0, 0 );
+ } else {
+ outputs->AddRange( out_port, 1, 1, 0 );
+ }
+
+ if ( f->watch ) {
+ cout << "flit " << f->id << " (" << f << ") at " << r->GetID( ) << " destined to "
+ << f->dest << " using channel " << out_port << ", vc range = ["
+ << 0 << "," << gNumVCS - 1 << "] (in_channel is " << in_channel << ")" << endl;
+ }
+
+
+}
+
+//=============================================================
+
+void dest_tag( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject )
+{
+ outputs->Clear( );
+
+ int stage = ( r->GetID( ) * gK ) / gNodes;
+ int dest = f->dest;
+
+ while ( stage < ( gN - 1 ) ) {
+ dest /= gK;
+ ++stage;
+ }
+
+ int out_port = dest % gK;
+
+ outputs->AddRange( out_port, 0, gNumVCS - 1 );
+}
+
+//=============================================================
+
+void chaos_torus( const Router *r, const Flit *f,
+ int in_channel, OutputSet *outputs, bool inject )
+{
+ int cur, dest;
+ int dist2;
+
+ outputs->Clear( );
+
+ cur = r->GetID( ); dest = f->dest;
+
+ if ( cur != dest ) {
+ for ( int n = 0; n < gN; ++n ) {
+
+ if ( ( cur % gK ) != ( dest % gK ) ) {
+ 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 )
+{
+ int cur, dest;
+
+ outputs->Clear( );
+
+ cur = r->GetID( ); 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( )
+{
+ /* Register routing functions here */
+
+ gRoutingFunctionMap["single_single"] = &singlerf;
+
+ gRoutingFunctionMap["dim_order_mesh"] = &dim_order_mesh;
+ gRoutingFunctionMap["dim_order_ni_mesh"] = &dim_order_ni_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;
+
+ 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;
+
+ gRoutingFunctionMap["chaos_mesh"] = &chaos_mesh;
+ gRoutingFunctionMap["chaos_torus"] = &chaos_torus;
+}
+
+tRoutingFunction GetRoutingFunction( const Configuration& config )
+{
+ map<string, tRoutingFunction>::const_iterator match;
+ tRoutingFunction rf;
+
+ string fn, topo, fn_topo;
+
+ gNumVCS = config.GetInt( "num_vcs" );
+
+ config.GetStr( "topology", topo );
+
+ config.GetStr( "routing_function", fn, "none" );
+ fn_topo = fn + "_" + topo;
+ match = gRoutingFunctionMap.find( fn_topo );
+
+ if ( match != gRoutingFunctionMap.end( ) ) {
+ rf = match->second;
+ } else {
+ if ( fn == "none" ) {
+ cout << "Error: No routing function specified in configuration." << endl;
+ } else {
+ cout << "Error: Undefined routing function '" << fn << "' for the topology '"
+ << topo << "'." << endl;
+ }
+ exit(-1);
+ }
+
+ return rf;
+}
+
+
diff --git a/src/intersim/routefunc.hpp b/src/intersim/routefunc.hpp new file mode 100644 index 0000000..e82c105 --- /dev/null +++ b/src/intersim/routefunc.hpp @@ -0,0 +1,14 @@ +#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( );
+tRoutingFunction GetRoutingFunction( const Configuration& config );
+
+#endif
diff --git a/src/intersim/router.cpp b/src/intersim/router.cpp new file mode 100644 index 0000000..6a750a6 --- /dev/null +++ b/src/intersim/router.cpp @@ -0,0 +1,113 @@ +#include "booksim.hpp"
+
+#include <iostream>
+#include <assert.h>
+
+#include "router.hpp"
+#include "iq_router.hpp"
+#include "event_router.hpp"
+
+Router::Router( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs ) :
+Module( parent, name ),
+_id( id ),
+_inputs( inputs ),
+_outputs( outputs )
+{
+ _routing_delay = config.GetInt( "routing_delay" );
+ _vc_alloc_delay = config.GetInt( "vc_alloc_delay" );
+ _sw_alloc_delay = config.GetInt( "sw_alloc_delay" );
+ _st_prepare_delay = config.GetInt( "st_prepare_delay" );
+ _st_final_delay = config.GetInt( "st_final_delay" );
+ _credit_delay = config.GetInt( "credit_delay" );
+ _input_speedup = config.GetInt( "input_speedup" );
+ _output_speedup = config.GetInt( "output_speedup" );
+
+ _input_channels = new vector<Flit **>;
+ _input_credits = new vector<Credit **>;
+
+ _output_channels = new vector<Flit **>;
+ _output_credits = new vector<Credit **>;
+
+ _channel_faults = new vector<bool>;
+}
+
+Router::~Router( )
+{
+ delete _input_channels;
+ delete _input_credits;
+ delete _output_channels;
+ delete _output_credits;
+ delete _channel_faults;
+}
+
+Credit *Router::_NewCredit( int vcs )
+{
+ Credit *c;
+
+ c = new Credit( vcs );
+ return c;
+}
+
+void Router::_RetireCredit( Credit *c )
+{
+ delete c;
+}
+
+void Router::AddInputChannel( Flit **channel, Credit **backchannel )
+{
+ _input_channels->push_back( channel );
+ _input_credits->push_back( backchannel );
+}
+
+void Router::AddOutputChannel( Flit **channel, Credit **backchannel )
+{
+ _output_channels->push_back( channel );
+ _output_credits->push_back( backchannel );
+ _channel_faults->push_back( false );
+}
+
+int Router::GetID( ) const
+{
+ return _id;
+}
+
+void Router::OutChannelFault( int c, bool fault )
+{
+ assert( ( c >= 0 ) && ( c < (int)_channel_faults->size( ) ) );
+
+ (*_channel_faults)[c] = fault;
+}
+
+bool Router::IsFaultyOutput( int c ) const
+{
+ assert( ( c >= 0 ) && ( c < (int)_channel_faults->size( ) ) );
+
+ return(*_channel_faults)[c];
+}
+
+Router *Router::NewRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs )
+{
+ Router *r;
+ string type;
+
+ config.GetStr( "router", type );
+
+ 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 {
+ cout << "Unknown router type " << type << endl;
+ }
+
+ return r;
+}
+
+
+
+
+
diff --git a/src/intersim/router.hpp b/src/intersim/router.hpp new file mode 100644 index 0000000..d2dff13 --- /dev/null +++ b/src/intersim/router.hpp @@ -0,0 +1,63 @@ +#ifndef _ROUTER_HPP_
+#define _ROUTER_HPP_
+
+#include <string>
+#include <vector>
+
+#include "module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "config_utils.hpp"
+
+class Router : public Module {
+protected:
+ int _id;
+
+ int _inputs;
+ int _outputs;
+
+ int _input_speedup;
+ int _output_speedup;
+
+ int _routing_delay;
+ int _vc_alloc_delay;
+ int _sw_alloc_delay;
+ int _st_prepare_delay;
+ int _st_final_delay;
+
+ int _credit_delay;
+
+ vector<Flit **> *_input_channels;
+ vector<Credit **> *_input_credits;
+ vector<Flit **> *_output_channels;
+ vector<Credit **> *_output_credits;
+ vector<bool> *_channel_faults;
+
+ Credit *_NewCredit( int vcs = 1 );
+ void _RetireCredit( Credit *c );
+
+public:
+ Router( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs );
+
+ virtual ~Router( );
+
+ static Router *NewRouter( const Configuration& config,
+ Module *parent, string name, int id,
+ int inputs, int outputs );
+
+ void AddInputChannel( Flit **channel, Credit **backchannel );
+ void AddOutputChannel( Flit **channel, Credit **backchannel );
+
+ virtual void ReadInputs( ) = 0;
+ virtual void InternalStep( ) = 0;
+ virtual void WriteOutputs( ) = 0;
+
+ void OutChannelFault( int c, bool fault = true );
+ bool IsFaultyOutput( int c ) const;
+
+ int GetID( ) const;
+};
+
+#endif
diff --git a/src/intersim/selalloc.cpp b/src/intersim/selalloc.cpp new file mode 100644 index 0000000..53d31fe --- /dev/null +++ b/src/intersim/selalloc.cpp @@ -0,0 +1,207 @@ +#include "booksim.hpp"
+#include <iostream>
+
+#include "selalloc.hpp"
+#include "random_utils.hpp"
+
+//#define DEBUG_SELALLOC
+
+SelAlloc::SelAlloc( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+SparseAllocator( config, parent, name, inputs, outputs )
+{
+ _iter = config.GetInt( "alloc_iters" );
+
+ _grants = new int [_outputs];
+ _gptrs = new int [_outputs];
+ _aptrs = new int [_inputs];
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _aptrs[i] = 0;
+ }
+ for ( int j = 0; j < _outputs; ++j ) {
+ _gptrs[j] = 0;
+ }
+}
+
+SelAlloc::~SelAlloc( )
+{
+ delete [] _grants;
+ delete [] _aptrs;
+ delete [] _gptrs;
+}
+
+void SelAlloc::Allocate( )
+{
+ int input;
+ int output;
+
+ int input_offset;
+ int output_offset;
+
+ list<sRequest>::iterator p;
+ list<int>::iterator outer_iter;
+ bool wrapped;
+
+ int max_index;
+ int max_pri;
+
+ _ClearMatching( );
+
+ for ( int i = 0; i < _outputs; ++i ) {
+ _grants[i] = -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->port < input_offset ) ) {
+ p++;
+ }
+
+ max_index = -1;
+ max_pri = 0;
+
+ wrapped = false;
+ while ( (!wrapped) || ( p->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->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->out_pri > max_pri ) || ( max_index == -1 ) ) ) {
+ max_pri = p->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->port < output_offset ) ) {
+ p++;
+ }
+
+ max_index = -1;
+ max_pri = 0;
+
+ wrapped = false;
+ while ( (!wrapped) || ( p->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->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->in_pri > max_pri ) || ( max_index == -1 ) ) ) {
+ max_pri = p->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
+}
diff --git a/src/intersim/selalloc.hpp b/src/intersim/selalloc.hpp new file mode 100644 index 0000000..8e2fb84 --- /dev/null +++ b/src/intersim/selalloc.hpp @@ -0,0 +1,22 @@ +#ifndef _SELALLOC_HPP_
+#define _SELALLOC_HPP_
+
+#include "allocator.hpp"
+
+class SelAlloc : public SparseAllocator {
+ int _iter;
+
+ int *_grants;
+ int *_aptrs;
+ int *_gptrs;
+
+public:
+ SelAlloc( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ ~SelAlloc( );
+
+ void Allocate( );
+};
+
+#endif
diff --git a/src/intersim/singlenet.cpp b/src/intersim/singlenet.cpp new file mode 100644 index 0000000..ec68fb4 --- /dev/null +++ b/src/intersim/singlenet.cpp @@ -0,0 +1,43 @@ +#include "booksim.hpp"
+#include <vector>
+
+#include "singlenet.hpp"
+
+SingleNet::SingleNet( const Configuration &config ) :
+Network( config )
+{
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+void SingleNet::_ComputeSize( const Configuration &config )
+{
+ _sources = config.GetInt( "in_ports" );
+ _dests = config.GetInt( "out_ports" );
+
+ _size = 1;
+ _channels = 0;
+}
+
+void SingleNet::_BuildNet( const Configuration &config )
+{
+ int i;
+
+ _routers[0] = Router::NewRouter( config, this, "router", 0,
+ _sources, _dests );
+
+ for ( i = 0; i < _sources; ++i ) {
+ _routers[0]->AddInputChannel( &_inject[i], &_inject_cred[i] );
+ }
+
+ for ( i = 0; i < _dests; ++i ) {
+ _routers[0]->AddOutputChannel( &_eject[i], &_eject_cred[i] );
+ }
+}
+
+void SingleNet::Display( ) const
+{
+ _routers[0]->Display( );
+}
+
diff --git a/src/intersim/singlenet.hpp b/src/intersim/singlenet.hpp new file mode 100644 index 0000000..f664c1c --- /dev/null +++ b/src/intersim/singlenet.hpp @@ -0,0 +1,17 @@ +#ifndef _SINGLENET_HPP_
+#define _SINGLENET_HPP_
+
+#include "network.hpp"
+
+class SingleNet : public Network {
+
+ void _ComputeSize( const Configuration &config );
+ void _BuildNet( const Configuration &config );
+
+public:
+ SingleNet( const Configuration &config );
+
+ void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/stats.cpp b/src/intersim/stats.cpp new file mode 100644 index 0000000..50cecce --- /dev/null +++ b/src/intersim/stats.cpp @@ -0,0 +1,119 @@ +#include "booksim.hpp"
+#include <math.h>
+#include <stdio.h>
+#include <iostream>
+
+#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 )
+{
+ _hist = new int [_num_bins];
+
+ Clear( );
+}
+
+Stats::~Stats( )
+{
+ delete [] _hist;
+}
+
+void Stats::Clear( )
+{
+ _num_samples = 0;
+ _sample_sum = 0.0;
+
+ for ( int b = 0; b < _num_bins; ++b ) {
+ _hist[b] = 0;
+ }
+
+ _reset = true;
+}
+
+double Stats::Average( ) const
+{
+ return _sample_sum / (double)_num_samples;
+}
+
+double Stats::Min( ) const
+{
+ return _min;
+}
+
+double Stats::Max( ) const
+{
+ return _max;
+}
+
+int Stats::NumSamples( ) const
+{
+ return _num_samples;
+}
+
+void Stats::AddSample( double val )
+{
+ int b;
+
+ _num_samples++;
+ _sample_sum += val;
+
+ if ( _reset ) {
+ _reset = false;
+ _max = val;
+ _min = val;
+ } else {
+ if ( val > _max ) {
+ _max = val;
+ }
+ if ( val < _min ) {
+ _min = val;
+ }
+ }
+
+ b = (int)floor( val / _bin_size );
+
+ if ( b < 0 ) {
+ b = 0;
+ } else if ( b >= _num_bins ) {
+ b = _num_bins - 1;
+ }
+
+ _hist[b]++;
+}
+
+void Stats::AddSample( int val )
+{
+ AddSample( (double)val );
+}
+
+void Stats::Display( ) const
+{
+ int b;
+
+ if (_bin_size != 1.0 ) {
+ cout<<_fullname<<"_";
+ printf("bins = [ ");
+ for ( b = 0; b < _num_bins; ++b ) {
+ printf("%d ", b* (unsigned)_bin_size);
+ }
+ printf("];\n");
+ }
+
+ cout<<_fullname<<"_";
+ printf("freq = [ ");
+ for ( b = 0; b < _num_bins; ++b ) {
+ printf("%d ", (unsigned) _hist[b]);
+ }
+ printf("];\n");
+}
+
+bool Stats::NeverUsed() const
+{
+ if ( _reset ) {
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/src/intersim/stats.hpp b/src/intersim/stats.hpp new file mode 100644 index 0000000..7c2a398 --- /dev/null +++ b/src/intersim/stats.hpp @@ -0,0 +1,39 @@ +#ifndef _STATS_HPP_
+#define _STATS_HPP_
+
+#include "module.hpp"
+
+class Stats : public Module {
+ int _num_samples;
+ double _sample_sum;
+
+ bool _reset;
+ double _min;
+ double _max;
+
+ int _num_bins;
+ double _bin_size;
+
+ int *_hist;
+
+public:
+ Stats( Module *parent, const string &name,
+ double bin_size = 1.0, int num_bins = 10 );
+ ~Stats( );
+
+ void Clear( );
+
+ double Average( ) const;
+ double Max( ) const;
+ double Min( ) const;
+ int NumSamples( ) const;
+
+ void AddSample( double val );
+ void AddSample( int val );
+
+
+ void Display( ) const;
+ bool NeverUsed() const;
+};
+
+#endif
diff --git a/src/intersim/statwraper.cpp b/src/intersim/statwraper.cpp new file mode 100644 index 0000000..9590f6f --- /dev/null +++ b/src/intersim/statwraper.cpp @@ -0,0 +1,64 @@ +//a Wraper function for stats class +#include "stats.hpp" +#include <stdio.h> + +void* StatCreate (const char * name, double bin_size, int num_bins) { + Stats* newstat = new Stats(NULL,name,bin_size,num_bins); + newstat->Clear (); + return(void *) newstat; +} + +void StatClear(void * st) +{ + ((Stats *)st)->Clear(); +} + +void StatAddSample (void * st, int val) +{ + ((Stats *)st)->AddSample(val); +} + +double StatAverage(void * st) +{ + return((Stats *)st)->Average(); +} + +double StatMax(void * st) +{ + return((Stats *)st)->Max(); +} + +double StatMin(void * st) +{ + return((Stats *)st)->Min(); +} + +void StatDisp (void * st) +{ + printf ("Stats for "); + ((Stats *)st)->DisplayHierarchy(); + if (((Stats *)st)->NeverUsed()) { + printf (" was never updated!\n"); + } else { + printf("Min %f Max %f Average %f \n",((Stats *)st)->Min(),((Stats *)st)->Max(),StatAverage(st)); + ((Stats *)st)->Display(); + } +} + +void StatDumptofile (void * st, FILE *f) +{ + +} + +#if 0 +int main () +{ + void * mytest = StatCreate("Test",1,5); + StatAddSample(mytest,4); + StatAddSample(mytest,4);StatAddSample(mytest,4); + StatAddSample(mytest,2); + StatDisp(mytest); +} +#endif + + diff --git a/src/intersim/statwraper.h b/src/intersim/statwraper.h new file mode 100644 index 0000000..35ca6de --- /dev/null +++ b/src/intersim/statwraper.h @@ -0,0 +1,13 @@ +#ifndef STAT_WRAPER_H +#define STAT_WRAPER_H + +void* StatCreate (const char * name, double bin_size, int num_bins) ; +void StatClear(void * st); +void StatAddSample (void * st, int val); +double StatAverage(void * st) ; +double StatMax(void * st) ; +double StatMin(void * st) ; +void StatDisp (void * st); +void StatDumptofile (void * st, FILE f); + +#endif diff --git a/src/intersim/traffic.cpp b/src/intersim/traffic.cpp new file mode 100644 index 0000000..62bc2b4 --- /dev/null +++ b/src/intersim/traffic.cpp @@ -0,0 +1,303 @@ +#include "booksim.hpp"
+#include <map>
+#include <stdlib.h>
+
+#include "traffic.hpp"
+#include "network.hpp"
+#include "random_utils.hpp"
+#include "misc_utils.hpp"
+
+map<string, tTrafficFunction> gTrafficFunctionMap;
+
+int gResetTraffic = 0;
+int gStepTraffic = 0;
+
+void src_dest_bin( int source, int dest, int lg )
+{
+ int b, t;
+
+ cout << "from: ";
+ t = source;
+ for ( b = 0; b < lg; ++b ) {
+ cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
+ }
+
+ cout << " to ";
+ t = dest;
+ for ( b = 0; b < lg; ++b ) {
+ cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
+ }
+ cout << endl;
+}
+
+//=============================================================
+
+int uniform( int source, int total_nodes )
+{
+ return RandomInt( total_nodes - 1 );
+}
+
+//=============================================================
+
+int bitcomp( int source, int total_nodes )
+{
+ int lg = log_two( total_nodes );
+ int mask = total_nodes - 1;
+ int dest;
+
+ if ( ( 1 << lg ) != total_nodes ) {
+ cout << "Error: The 'bitcomp' traffic pattern requires the number of"
+ << " nodes to be a power of two!" << endl;
+ exit(-1);
+ }
+
+ dest = ( ~source ) & mask;
+
+ return dest;
+}
+
+//=============================================================
+
+int transpose( int source, int total_nodes )
+{
+ int lg = log_two( total_nodes );
+ int mask_lo = (1 << (lg/2)) - 1;
+ int mask_hi = mask_lo << (lg/2);
+ int dest;
+
+ if ( ( ( 1 << lg ) != total_nodes ) || ( lg & 0x1 ) ) {
+ cout << "Error: The 'transpose' traffic pattern requires the number of"
+ << " nodes to be an even power of two!" << endl;
+ exit(-1);
+ }
+
+ dest = ( ( source >> (lg/2) ) & mask_lo ) |
+ ( ( source << (lg/2) ) & mask_hi );
+
+ return dest;
+}
+
+//=============================================================
+
+int bitrev( int source, int total_nodes )
+{
+ int lg = log_two( total_nodes );
+ int dest;
+
+ if ( ( 1 << lg ) != total_nodes ) {
+ cout << "Error: The 'bitrev' traffic pattern requires the number of"
+ << " nodes to be a power of two!" << endl;
+ exit(-1);
+ }
+
+ // If you were fancy you could do this in O(log log total_nodes)
+ // instructions, but I'm not
+
+ dest = 0;
+ for ( int b = 0; b < lg; ++b ) {
+ dest |= ( ( source >> b ) & 0x1 ) << ( lg - b - 1 );
+ }
+
+ return dest;
+}
+
+//=============================================================
+
+int shuffle( int source, int total_nodes )
+{
+ int lg = log_two( total_nodes );
+ int dest;
+
+ if ( ( 1 << lg ) != total_nodes ) {
+ cout << "Error: The 'shuffle' traffic pattern requires the number of"
+ << " nodes to be a power of two!" << endl;
+ exit(-1);
+ }
+
+ dest = ( ( source << 1 ) & ( total_nodes - 1 ) ) |
+ ( ( source >> ( lg - 1 ) ) & 0x1 );
+
+ return dest;
+}
+
+//=============================================================
+
+int tornado( int source, int total_nodes )
+{
+ int offset = 1;
+ int dest = 0;
+
+ for ( int n = 0; n < gN; ++n ) {
+ dest += offset *
+ ( ( ( source / offset ) % gK + ( gK/2 - 1 ) ) % gK );
+ offset *= gK;
+ }
+
+ return dest;
+}
+
+//=============================================================
+
+int neighbor( int source, int total_nodes )
+{
+ int offset = 1;
+ int dest = 0;
+
+ for ( int n = 0; n < gN; ++n ) {
+ dest += offset *
+ ( ( ( source / offset ) % gK + 1 ) % gK );
+ offset *= gK;
+ }
+
+ return dest;
+}
+
+//=============================================================
+
+int *gPerm = 0;
+int gPermSeed;
+
+void GenerateRandomPerm( int total_nodes )
+{
+ int ind;
+ int i,j;
+ int cnt;
+ unsigned long prev_rand;
+
+ prev_rand = RandomIntLong( );
+ RandomSeed( gPermSeed );
+
+ if ( !gPerm ) {
+ gPerm = new int [total_nodes];
+ }
+
+ for ( i = 0; i < total_nodes; ++i ) {
+ gPerm[i] = -1;
+ }
+
+ for ( i = 0; i < total_nodes; ++i ) {
+ ind = RandomInt( total_nodes - 1 - i );
+
+ j = 0;
+ cnt = 0;
+ while ( ( cnt < ind ) ||
+ ( gPerm[j] != -1 ) ) {
+ if ( gPerm[j] == -1 ) {
+ ++cnt;
+ }
+ ++j;
+
+ if ( j >= total_nodes ) {
+ cout << "ERROR: GenerateRandomPerm( ) internal error" << endl;
+ exit(-1);
+ }
+ }
+
+ gPerm[j] = i;
+ }
+
+ RandomSeed( prev_rand );
+}
+
+int randperm( int source, int total_nodes )
+{
+ if ( gResetTraffic || !gPerm ) {
+ GenerateRandomPerm( total_nodes );
+ gResetTraffic = 0;
+ }
+
+ return gPerm[source];
+}
+
+//=============================================================
+
+int diagonal( int source, int total_nodes )
+{
+ int t = RandomInt( 2 );
+ int d;
+
+ // 2/3 of traffic goes from source->source
+ // 1/3 of traffic goes from source->(source+1)%total_nodes
+
+ if ( t == 0 ) {
+ d = ( source + 1 ) % total_nodes;
+ } else {
+ d = source;
+ }
+
+ return d;
+}
+
+//=============================================================
+
+int asymmetric( int source, int total_nodes )
+{
+ int d;
+ int half = total_nodes / 2;
+
+ d = ( source % half ) + RandomInt( 1 ) * half;
+
+ return d;
+}
+
+//=============================================================
+
+void InitializeTrafficMap( )
+{
+ /* Register Traffic functions here */
+
+ gTrafficFunctionMap["uniform"] = &uniform;
+
+ // "Bit" patterns
+
+ gTrafficFunctionMap["bitcomp"] = &bitcomp;
+ gTrafficFunctionMap["bitrev"] = &bitrev;
+ gTrafficFunctionMap["transpose"] = &transpose;
+ gTrafficFunctionMap["shuffle"] = &shuffle;
+
+ // "Digit" patterns
+
+ gTrafficFunctionMap["tornado"] = &tornado;
+ gTrafficFunctionMap["neighbor"] = &neighbor;
+
+ // Other patterns
+
+ gTrafficFunctionMap["randperm"] = &randperm;
+
+ gTrafficFunctionMap["diagonal"] = &diagonal;
+ gTrafficFunctionMap["asymmetric"] = &asymmetric;
+}
+
+void ResetTrafficFunction( )
+{
+ gResetTraffic++;
+}
+
+void StepTrafficFunction( )
+{
+ gStepTraffic++;
+}
+
+tTrafficFunction GetTrafficFunction( const Configuration& config )
+{
+ map<string, tTrafficFunction>::const_iterator match;
+ tTrafficFunction tf;
+
+ string fn;
+
+ config.GetStr( "traffic", fn, "none" );
+ match = gTrafficFunctionMap.find( fn );
+
+ if ( match != gTrafficFunctionMap.end( ) ) {
+ tf = match->second;
+ } else {
+ cout << "Error: Undefined traffic pattern '" << fn << "'." << endl;
+ exit(-1);
+ }
+
+ gPermSeed = config.GetInt( "perm_seed" );
+
+ return tf;
+}
+
+
diff --git a/src/intersim/traffic.hpp b/src/intersim/traffic.hpp new file mode 100644 index 0000000..c0a796c --- /dev/null +++ b/src/intersim/traffic.hpp @@ -0,0 +1,15 @@ +#ifndef _TRAFFIC_HPP_
+#define _TRAFFIC_HPP_
+
+#include "config_utils.hpp"
+
+typedef int (*tTrafficFunction)( int, int );
+
+void InitializeTrafficMap( );
+
+void ResetTraffic( );
+void StepTrafficFunctions( );
+
+tTrafficFunction GetTrafficFunction( const Configuration& config );
+
+#endif
diff --git a/src/intersim/trafficmanager.cpp b/src/intersim/trafficmanager.cpp new file mode 100644 index 0000000..3a633b8 --- /dev/null +++ b/src/intersim/trafficmanager.cpp @@ -0,0 +1,1249 @@ +#include "booksim.hpp"
+#include <sstream>
+#include <math.h>
+#include <assert.h>
+
+#include "trafficmanager.hpp"
+#include "random_utils.hpp"
+#include "interconnect_interface.h"
+
+//Turns on flip tracking!
+//#ifndef DEBUG
+#define DEBUG 0
+//#endif
+
+int MATLAB_OUTPUT = 0; // output data in MATLAB friendly format
+int DISPLAY_LAT_DIST = 1; // distribution of packet latencies
+int DISPLAY_HOP_DIST = 1; // distribution of hop counts
+int DISPLAY_PAIR_LATENCY = 0; // avg. latency for each s-d pair
+
+TrafficManager::TrafficManager( const Configuration &config, Network *net , int u_id)
+: Module( 0, "traffic_manager" )
+{
+ int s;
+ ostringstream tmp_name;
+ string sim_type, priority;
+
+ uid = u_id;
+ _net = net;
+ _cur_id = 0;
+
+ _sources = _net->NumSources( );
+ _dests = _net->NumDests( );
+
+ // ============ Message priorities ============
+
+ config.GetStr( "priority", priority );
+
+ _classes = 1;
+
+ if ( priority == "class" ) {
+ _classes = 2;
+ _pri_type = class_based;
+ } else if ( priority == "age" ) {
+ _pri_type = age_based;
+ } else if ( priority == "none" ) {
+ _pri_type = none;
+ } else {
+ Error( "Unknown priority " + priority );
+ }
+
+ // ============ Injection VC states ============
+
+ _buf_states = new BufferState * [_sources];
+
+ for ( s = 0; s < _sources; ++s ) {
+ tmp_name << "buf_state_" << s;
+ _buf_states[s] = new BufferState( config, this, tmp_name.str( ) );
+ tmp_name.seekp( 0, ios::beg );
+ }
+
+ // ============ Injection queues ============
+
+ _voqing = config.GetInt( "voq" );
+
+ if ( _voqing ) {
+ _use_lagging = false;
+ } else {
+ _use_lagging = true;
+ }
+
+ _time = 0;
+ _warmup_time = -1;
+ _drain_time = -1;
+ _empty_network = false;
+
+ _measured_in_flight = 0;
+ _total_in_flight = 0;
+
+ if ( _use_lagging ) {
+ _qtime = new int * [_sources];
+ _qdrained = new bool * [_sources];
+ }
+
+ if ( _voqing ) {
+ _voq = new list<Flit *> * [_sources];
+ _active_list = new list<int> [_sources];
+ _active_vc = new bool * [_sources];
+ }
+
+ _partial_packets = new list<Flit *> * [_sources];
+
+ for ( s = 0; s < _sources; ++s ) {
+ if ( _use_lagging ) {
+ _qtime[s] = new int [_classes];
+ _qdrained[s] = new bool [_classes];
+ }
+
+ if ( _voqing ) {
+ _voq[s] = new list<Flit *> [_dests];
+ _active_vc[s] = new bool [_dests];
+ }
+
+ _partial_packets[s] = new list<Flit *> [_classes];
+ }
+
+ _split_packets = config.GetInt( "split_packets" );
+
+ credit_return_queue = new queue<Flit *> [_sources];
+
+ // ============ Reorder queues ============
+
+ _reorder = config.GetInt( "reorder" ) ? true : false;
+
+ if ( _reorder ) {
+ _inject_sqn = new int * [_sources];
+ _rob_sqn = new int * [_sources];
+ _rob_sqn_max = new int * [_sources];
+ _rob = new priority_queue<Flit *, vector<Flit *>, flitp_compare> * [_sources];
+
+ for ( int i = 0; i < _sources; ++i ) {
+ _inject_sqn[i] = new int [_dests];
+ _rob_sqn[i] = new int [_dests];
+ _rob_sqn_max[i] = new int [_dests];
+ _rob[i] = new priority_queue<Flit *, vector<Flit *>, flitp_compare> [_dests];
+
+ for ( int j = 0; j < _dests; ++j ) {
+ _inject_sqn[i][j] = 0;
+ _rob_sqn[i][j] = 0;
+ _rob_sqn_max[i][j] = 0;
+ }
+ }
+
+ _rob_pri = new int [_dests];
+
+ for ( int i = 0; i < _dests; ++i ) {
+ _rob_pri[i] = 0;
+ }
+ }
+
+ // ============ Statistics ============
+
+ _latency_stats = new Stats * [_classes];
+ _overall_latency = new Stats * [_classes];
+
+ for ( int c = 0; c < _classes; ++c ) {
+ tmp_name << "latency_stat_" << c;
+ _latency_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 );
+ tmp_name.seekp( 0, ios::beg );
+
+ tmp_name << "overall_latency_stat_" << c;
+ _overall_latency[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 );
+ tmp_name.seekp( 0, ios::beg );
+ }
+
+ _pair_latency = new Stats * [_dests];
+ _accepted_packets = new Stats * [_dests];
+
+ for ( int i = 0; i < _dests; ++i ) {
+ tmp_name << "pair_stat_" << i;
+ _pair_latency[i] = new Stats( this, tmp_name.str( ), 1.0, 250 );
+ tmp_name.seekp( 0, ios::beg );
+
+ tmp_name << "accepted_stat_" << i;
+ _accepted_packets[i] = new Stats( this, tmp_name.str( ) );
+ tmp_name.seekp( 0, ios::beg );
+ }
+
+ _hop_stats = new Stats( this, "hop_stats", 1.0, 20 );;
+ _overall_accepted = new Stats( this, "overall_acceptance" );
+ _overall_accepted_min = new Stats( this, "overall_min_acceptance" );
+
+ if ( _reorder ) {
+ _rob_latency = new Stats( this, "rob_latency", 1.0, 1000 );
+ _rob_size = new Stats( this, "rob_size", 1.0, 250 );
+ }
+
+ _flit_timing = config.GetInt( "flit_timing" );
+
+ // ============ Simulation parameters ============
+
+ _load = config.GetFloat( "injection_rate" );
+ _packet_size = config.GetInt( "const_flits_per_packet" );
+
+ _total_sims = config.GetInt( "sim_count" );
+
+ _internal_speedup = config.GetFloat( "internal_speedup" );
+ _partial_internal_cycles = 0.0;
+
+ _traffic_function = NULL; // GetTrafficFunction( config ); // Not used by gpgpusim
+ _routing_function = GetRoutingFunction( config );
+ _injection_process = NULL; // GetInjectionProcess( config ); // Not used by gpgpusim
+
+ config.GetStr( "sim_type", sim_type );
+
+ if ( sim_type == "latency" ) {
+ _sim_mode = latency;
+ } else if ( sim_type == "throughput" ) {
+ _sim_mode = throughput;
+ } else {
+ Error( "Unknown sim_type " + sim_type );
+ }
+
+ _sample_period = config.GetInt( "sample_period" );
+ _max_samples = config.GetInt( "max_samples" );
+ _warmup_periods = config.GetInt( "warmup_periods" );
+ _latency_thres = config.GetFloat( "latency_thres" );
+ _include_queuing = config.GetInt( "include_queuing" );
+}
+
+TrafficManager::~TrafficManager( )
+{
+ for ( int s = 0; s < _sources; ++s ) {
+ if ( _use_lagging ) {
+ delete [] _qtime[s];
+ delete [] _qdrained[s];
+ }
+ if ( _voqing ) {
+ delete [] _voq[s];
+ delete [] _active_vc[s];
+ }
+ delete [] _partial_packets[s];
+ delete _buf_states[s];
+ }
+
+ if ( _use_lagging ) {
+ delete [] _qtime;
+ delete [] _qdrained;
+ }
+
+ if ( _voqing ) {
+ delete [] _voq;
+ delete [] _active_vc;
+ }
+
+ if ( _reorder ) {
+ for ( int i = 0; i < _sources; ++i ) {
+ delete [] _inject_sqn[i];
+ delete [] _rob_sqn[i];
+ delete [] _rob_sqn_max[i];
+ delete [] _rob[i];
+ }
+
+ delete [] _inject_sqn;
+ delete [] _rob_sqn;
+ delete [] _rob_sqn_max;
+ delete [] _rob;
+ delete [] _rob_pri;
+
+ delete _rob_latency;
+ delete _rob_size;
+ }
+
+ delete [] _buf_states;
+ delete [] _partial_packets;
+
+ for ( int c = 0; c < _classes; ++c ) {
+ delete _latency_stats[c];
+ delete _overall_latency[c];
+ }
+
+ delete [] _latency_stats;
+ delete [] _overall_latency;
+
+ delete _hop_stats;
+ delete _overall_accepted;
+ delete _overall_accepted_min;
+
+ for ( int i = 0; i < _dests; ++i ) {
+ delete _accepted_packets[i];
+ delete _pair_latency[i];
+ }
+
+ delete [] _accepted_packets;
+ delete [] _pair_latency;
+}
+
+Flit *TrafficManager::_NewFlit( )
+{
+ Flit *f;
+ f = new Flit;
+
+ f->id = _cur_id;
+ f->hops = 0;
+ f->watch = false;
+
+ // Add specific packet watches for debugging
+ if (DEBUG || f->id == -1 ) {
+ f->watch = true;
+ }
+
+ _in_flight[_cur_id] = true;
+ ++_cur_id;
+ return f;
+}
+
+void TrafficManager::_RetireFlit( Flit *f, int dest )
+{
+ static int sample_num = 0;
+
+ map<int, bool>::iterator match;
+
+ match = _in_flight.find( f->id );
+
+ if ( match != _in_flight.end( ) ) {
+ if ( f->watch ) {
+ cout << "Matched flit ID = " << f->id << endl;
+ }
+ _in_flight.erase( match );
+ } else {
+ cout << "Unmatched flit! ID = " << f->id << endl;
+ Error( "" );
+ }
+
+ if ( f->watch ) {
+ cout << "Ejecting flit " << f->id
+ << ", lat = " << _time - f->time
+ << ", src = " << f->src
+ << ", dest = " << f->dest << endl;
+ }
+
+ // Only record statistics once per packet (at true tails)
+ // unless flit-level timing is on
+ if ( f->tail || _flit_timing ) {
+ _total_in_flight--;
+ if ( _total_in_flight < 0 ) {
+ Error( "Total in flight count dropped below zero!" );
+ }
+
+ if ( ( _sim_state == warming_up ) || f->record ) {
+ if ( f->true_tail || _flit_timing ) {
+ _hop_stats->AddSample( f->hops );
+ assert( (_time - f->time)>0 );
+ switch ( _pri_type ) {
+ case class_based:
+ _latency_stats[f->pri]->AddSample( (_time - f->time) );
+ break;
+ case age_based: // fall through
+ case none:
+ _latency_stats[0]->AddSample( (_time - f->time) );
+ break;
+ }
+
+ if ( _reorder ) {
+ _rob_latency->AddSample( (_time - f->rob_time ));
+ }
+
+ if ( f->src == 0 ) {
+ _pair_latency[dest]->AddSample( (_time - f->time ) );
+ }
+ }
+
+ if ( f->record ) {
+
+ _measured_in_flight--;
+ if ( _measured_in_flight < 0 ) {
+ Error( "Measured in flight count dropped below zero!" );
+ }
+ }
+
+ ++sample_num;
+ }
+ }
+
+ delete f;
+}
+
+//never called in gpgpusim
+int TrafficManager::_IssuePacket( int source, int cl ) const
+{
+ float class_load;
+ if ( _pri_type == class_based ) {
+ if ( cl == 0 ) {
+ class_load = 0.9 * _load;
+ } else {
+ class_load = 0.1 * _load;
+ }
+ } else {
+ class_load = _load;
+ }
+ //gppgusim_injector ignores second parameter!
+ return _injection_process( source, class_load );
+}
+
+void TrafficManager::_GeneratePacket( int source, int psize /*# of flits*/ ,
+ int cl, int time, void* data, int dest )
+{
+ Flit *f;
+ bool record;
+ bool split_head;
+ bool split_tail;
+
+ if ( ( _sim_state == running ) ||
+ ( ( _sim_state == draining ) && ( time < _drain_time ) ) ) {
+ record = true;
+ } else {
+ record = false;
+ }
+
+ for ( int i = 0; i < psize; ++i ) {
+ f = _NewFlit( );
+
+ split_head = false;
+ split_tail = false;
+
+ if ( _split_packets > 0 ) {
+ if ( ( i % _split_packets ) == 0 ) {
+ split_head = true;
+ }
+
+ if ( ( i % _split_packets ) == ( _split_packets - 1 ) ) {
+ split_tail = true;
+ }
+ }
+
+ f->src = source;
+ f->time = time;
+ f->record = record;
+ f->data = data;
+ f->net_num = uid;
+ if ( ( i == 0 ) || ( split_head ) ) { // Head flit
+ f->head = true;
+ f->dest = dest;
+ } else {
+ f->head = false;
+ f->dest = -1;
+ }
+
+ f->true_tail = false;
+ if ( ( i == ( psize - 1 ) ) || ( split_tail ) ) { // Tail flit
+ f->tail = true;
+
+ if ( i == ( psize - 1 ) ) {
+ f->true_tail = true;
+ }
+ } else {
+ f->tail = false;
+ }
+
+ if ( _reorder ) {
+ f->sn = _inject_sqn[source][dest];
+ _inject_sqn[source][dest]++;
+ }
+
+ switch ( _pri_type ) {
+ case class_based:
+ f->pri = cl; break;
+ case age_based:
+ f->pri = -time; break;
+ case none:
+ f->pri = 0; break;
+ }
+
+ f->vc = -1;
+
+ if ( f->watch ) {
+ cout << "Generating flit at time " << time << endl;
+ cout << *f;
+ }
+
+ if ( f->tail || _flit_timing ) {
+ if ( record ) {
+ ++_measured_in_flight;
+ }
+ ++_total_in_flight;
+ }
+
+ if ( _flit_timing ) {
+ time++;
+ }
+
+ _partial_packets[source][cl].push_back( f );
+ }
+}
+
+void TrafficManager::_FirstStep( )
+{
+ // Ensure that all outputs are defined before starting simulation
+
+ _net->WriteOutputs( );
+
+ for ( int output = 0; output < _net->NumDests( ); ++output ) {
+ _net->WriteCredit( 0, output );
+ }
+}
+
+void TrafficManager::_ClassInject( )
+{
+ Flit *f, *nf;
+ Credit *cred;
+
+ // Receive credits and inject new traffic
+ for ( int input = 0; input < _net->NumSources( ); ++input ) {
+
+ cred = _net->ReadCredit( input );
+ if ( cred ) {
+ _buf_states[input]->ProcessCredit( cred );
+ delete cred;
+ }
+
+ bool write_flit = false;
+ int highest_class = 0;
+ bool generated;
+
+ for ( int c = 0; c < _classes; ++c ) {
+ // Potentially generate packets for any (input,class)
+ // that is currently empty
+ if ( _partial_packets[input][c].empty( ) ) {
+ generated = false;
+
+ if ( !_empty_network ) {
+ if ( ( _sim_state == draining ) &&
+ ( _qtime[input][c] > _drain_time ) ) {
+ _qdrained[input][c] = true;
+ }
+ }
+
+ if ( generated ) {
+ highest_class = c;
+ }
+
+ } else {
+ highest_class = c;
+ }
+ }
+
+ // Now, check partially issued packet to
+ // see if it can be issued
+ if ( !_partial_packets[input][highest_class].empty( ) ) {
+ f = _partial_packets[input][highest_class].front( );
+
+ if ( f->head && ( f->vc == -1 ) ) { // Find first available VC
+ f->vc = _buf_states[input]->FindAvailable( );
+
+ if ( f->vc != -1 ) {
+ _buf_states[input]->TakeBuffer( f->vc );
+ }
+ }
+
+ if ( f->vc != -1 ) {
+ if ( !_buf_states[input]->IsFullFor( f->vc ) ) {
+
+ _partial_packets[input][highest_class].pop_front( );
+ _buf_states[input]->SendingFlit( f );
+ time_vector_update_icnt_injected(f->data, input);
+ write_flit = true;
+
+ // Pass VC "back"
+ if ( !_partial_packets[input][highest_class].empty( ) && !f->tail ) {
+ nf = _partial_packets[input][highest_class].front( );
+ nf->vc = f->vc;
+ }
+ }
+ if ( f->watch ) {
+ cout << "Flit " << f->id << " written into injection port at time " << _time << endl;
+ }
+ } else {
+ if ( f->watch ) {
+ cout << "Flit " << f->id << " stalled at injection waiting for available VC at time " << _time << endl;
+ }
+ }
+ }
+
+ _net->WriteFlit( write_flit ? f : 0, input );
+ }
+}
+
+void TrafficManager::_VOQInject( )
+{
+ Flit *f;
+ Credit *cred;
+
+ int vc;
+ int dest;
+
+ for ( int input = 0; input < _net->NumSources( ); ++input ) {
+
+ // Receive credits
+ cred = _net->ReadCredit( input );
+ if ( cred ) {
+ _buf_states[input]->ProcessCredit( cred );
+
+ for ( int i = 0; i < cred->vc_cnt; i++ ) {
+ vc = cred->vc[i];
+
+ // If this credit enables a VC that has packets waiting,
+ // set the VC to active (append it to the active list)
+
+ if ( !_voq[input][vc].empty( ) && !_active_vc[input][vc] ) {
+ f = _voq[input][vc].front( );
+
+ if ( ( f->head && _buf_states[input]->IsAvailableFor( vc ) ) ||
+ ( !f->head && !_buf_states[input]->IsFullFor( vc ) ) ) {
+ _active_list[input].push_back( vc );
+ _active_vc[input][vc] = true;
+ }
+ }
+ }
+
+ delete cred;
+ }
+/*
+ if ( !_empty_network ) {
+ // Inject packets
+ psize = _IssuePacket( input, 0 );
+ } else {
+ psize = 0;
+ }
+*/
+ if ( !_partial_packets[input][0].empty( )/*was psize */) {
+ //_GeneratePacket( input, psize, 0, _time ); //already generated in interconnect_push
+ dest = -1;
+
+ bool wasempty = false;
+
+ // Move a generated packet to the appropriate VOQ
+ while ( !_partial_packets[input][0].empty( ) ) {
+ f = _partial_packets[input][0].front( );
+ _partial_packets[input][0].pop_front( );
+ time_vector_update_icnt_injected(f->data, input);
+
+ if ( f->head ) {
+ dest = f->dest;
+ wasempty = _voq[input][dest].empty( );
+ }
+
+ if ( dest == -1 ) {
+ Error( "Didn't see head flit in VOQ injection" );
+ }
+
+ f->dest = dest;
+ f->vc = dest;
+
+ _voq[input][dest].push_back( f );
+ }
+
+ // If this packet enables a VC,
+ // set the VC to active (append it to the active list)
+ if ( wasempty &&
+ ( !_active_vc[input][dest] ) &&
+ ( _buf_states[input]->IsAvailableFor( dest ) ) ) {
+ _active_list[input].push_back( dest );
+ _active_vc[input][dest] = true;
+ }
+ }
+
+ // Write packets to the network
+ if ( !_active_list[input].empty( ) ) {
+
+ dest = _active_list[input].front( );
+ _active_list[input].pop_front( );
+
+ if ( _voq[input][dest].empty( ) ) {
+ Error( "VOQ marked as active, but empty" );
+ }
+
+ f = _voq[input][dest].front( );
+ _voq[input][dest].pop_front( );
+
+ if ( f->head ) {
+ _buf_states[input]->TakeBuffer( dest );
+ }
+
+ _buf_states[input]->SendingFlit( f );
+ _net->WriteFlit( f, input );
+
+ // Inactivate VC if it can't accept any more flits or
+ // no more flits are available to be sent
+ if ( ( f->tail && _buf_states[input]->IsAvailableFor( dest ) ) ||
+ ( !f->tail && !_buf_states[input]->IsFullFor( dest ) ) ) {
+ _active_list[input].push_back( dest );
+ } else {
+ _active_vc[input][dest] = false;
+ }
+
+ } else {
+ _net->WriteFlit( 0, input );
+ }
+ }
+}
+
+Flit *TrafficManager::_ReadROB( int dest )
+{
+ int src;
+ Flit *f;
+
+ src = _rob_pri[dest];
+ f = 0;
+
+ for ( int i = 0; i < _sources; ++i ) {
+
+ if ( !_rob[src][dest].empty( ) ) {
+ f = _rob[src][dest].top( );
+
+ if ( f->sn == _rob_sqn[src][dest] ) {
+ _rob[src][dest].pop( );
+ _rob_sqn[src][dest]++;
+ _rob_pri[dest] = ( src + 1 ) % _sources;
+ break;
+ } else {
+ f = 0;
+ }
+ }
+
+ src = ( src + 1 ) % _sources;
+ }
+
+ return f;
+}
+
+void TrafficManager::_Step( )
+{
+ Flit *f;
+ Credit *cred;
+
+ // Inject traffic
+ if ( _voqing ) {
+ _VOQInject( );
+ } else {
+ _ClassInject( );
+ }
+
+ // Advance network
+
+ _net->ReadInputs( );
+
+ _partial_internal_cycles += _internal_speedup;
+ while ( _partial_internal_cycles >= 1.0 ) {
+ _net->InternalStep( );
+ _partial_internal_cycles -= 1.0;
+ }
+
+ _net->WriteOutputs( );
+
+ ++_time;
+
+ // Eject traffic and send credits
+ Flit *last_valid_flit; //= new Flit;
+ for ( int output = 0; output < _dests; ++output ) {
+ f = _net->ReadFlit( output );
+
+ if ( f ) {
+ if (1 || f->tail) {
+ write_out_buf(output, f); // it should have space!
+ if ( f->watch ) {
+ cout << "Sent flit " << f->id << " to output buffer " << output << endl;
+ cout << " Not sending the credit yet! " <<endl;
+ }
+ } else {
+ if ( f->watch ) {
+ cout << "ejected flit " << f->id << " at output " << output << endl;
+ cout << "sending credit for " << f->vc << endl;
+ }
+
+ if ( _reorder ) {
+ if ( f->watch ) {
+ cout << "adding flit " << f->id << " to reorder buffer" << endl;
+ cout << "flit's SN is " << f->sn << " buffer's SN is "
+ << _rob_sqn[f->src][f->dest] << endl;
+ }
+
+ if ( f->sn > _rob_sqn_max[f->src][f->dest] ) {
+ _rob_sqn_max[f->src][f->dest] = f->sn;
+ }
+
+ if ( f->head ) {
+ _rob_size->AddSample( f->sn - _rob_sqn[f->src][f->dest] );
+ }
+
+ f->rob_time = _time;
+ _rob[f->src][output].push( f );
+ } else {
+ _RetireFlit( f, output );
+ if ( !_empty_network ) {
+ _accepted_packets[output]->AddSample( 1 );
+ }
+ }
+ }
+ }
+ transfer2boundary_buf( output );
+ if (!credit_return_queue[output].empty()) {
+ last_valid_flit = credit_return_queue[output].front();
+ credit_return_queue[output].pop();
+ } else {
+ last_valid_flit=NULL;
+ }
+ if (last_valid_flit) {
+
+
+ cred = new Credit( 1 );
+ cred->vc[0] =last_valid_flit->vc;
+ cred->vc_cnt = 1;
+ cred->head = last_valid_flit->head;
+ cred->tail =last_valid_flit->tail;
+
+ _net->WriteCredit( cred, output );
+ if (last_valid_flit->watch) {
+ cout <<"WE WROTE A CREDIT for flit "<<last_valid_flit->id<<"To output "<<output<< endl;
+ }
+ _RetireFlit(last_valid_flit, output );
+ if ( !_empty_network ) {
+ _accepted_packets[output]->AddSample( 1 );
+ }
+ } else {
+ _net->WriteCredit( 0, output );
+
+ if ( !_reorder && !_empty_network) {
+ _accepted_packets[output]->AddSample( 0 );
+ }
+ }
+
+ if ( _reorder ) {
+ f = _ReadROB( output );
+
+ if ( f ) {
+ if ( f->watch ) {
+ cout << "flit " << f->id << " removed from ROB at output " << output << endl;
+ }
+
+ _RetireFlit( f, output );
+ if ( !_empty_network ) {
+ _accepted_packets[output]->AddSample( 1 );
+ }
+ } else {
+ if ( !_empty_network ) {
+ _accepted_packets[output]->AddSample( 0 );
+ }
+ }
+ }
+ }
+}
+
+bool TrafficManager::_PacketsOutstanding( ) const
+{
+ bool outstanding;
+
+ if ( _measured_in_flight == 0 ) {
+ outstanding = false;
+
+ if ( _use_lagging ) {
+ for ( int c = 0; c < _classes; ++c ) {
+ for ( int s = 0; s < _sources; ++s ) {
+ if ( !_qdrained[s][c] ) {
+#ifdef DEBUG_DRAIN
+ cout << "waiting on queue " << s << " class " << c;
+ cout << ", time = " << _time << " qtime = " << _qtime[s][c] << endl;
+#endif
+ outstanding = true;
+ break;
+ }
+ }
+ if ( outstanding ) {
+ break;
+ }
+ }
+ }
+ } else {
+#ifdef DEBUG_DRAIN
+ cout << "in flight = " << _measured_in_flight << endl;
+#endif
+ outstanding = true;
+ }
+
+ return outstanding;
+}
+
+void TrafficManager::_ClearStats( )
+{
+ for ( int c = 0; c < _classes; ++c ) {
+ _latency_stats[c]->Clear( );
+ }
+
+ for ( int i = 0; i < _dests; ++i ) {
+ _accepted_packets[i]->Clear( );
+ _pair_latency[i]->Clear( );
+ }
+
+ if ( _reorder ) {
+ _rob_latency->Clear( );
+ _rob_size->Clear( );
+ }
+}
+
+int TrafficManager::_ComputeAccepted( double *avg, double *min ) const
+{
+ int dmin;
+
+ *min = 1.0;
+ *avg = 0.0;
+
+ for ( int d = 0; d < _dests; ++d ) {
+ if ( _accepted_packets[d]->Average( ) < *min ) {
+ *min = _accepted_packets[d]->Average( );
+ dmin = d;
+ }
+ *avg += _accepted_packets[d]->Average( );
+ }
+
+ *avg /= (double)_dests;
+
+ return dmin;
+}
+
+void TrafficManager::_DisplayRemaining( ) const
+{
+ map<int, bool>::const_iterator iter;
+ int i;
+
+ cout << "Remaining flits (" << _measured_in_flight << " measurement packets) : ";
+ for ( iter = _in_flight.begin( ), i = 0;
+ ( iter != _in_flight.end( ) ) && ( i < 20 );
+ iter++, i++ ) {
+ cout << iter->first << " ";
+ }
+ cout << endl;
+}
+
+//special initilization each tiem a new GPU grid is started
+void TrafficManager::IcntInitPerGrid (int time)
+{ //some initialization parts of _SingleSim for gpgpgusim
+ _time = time ;
+ if ( _use_lagging ) {
+ for ( int s = 0; s < _sources; ++s ) {
+ for ( int c = 0; c < _classes; ++c ) {
+ _qtime[s][c] = _time; // Was Zero
+ _qdrained[s][c] = false;
+ }
+ }
+ }
+
+ if ( _voqing ) {
+ for ( int s = 0; s < _sources; ++s ) {
+ for ( int d = 0; d < _dests; ++d ) {
+ _active_vc[s][d] = false;
+ }
+ }
+ }
+ _sim_state = running;
+ _ClearStats( );
+}
+
+bool TrafficManager::_SingleSim( )
+{
+ int iter;
+ int total_phases;
+ int converged;
+ int max_outstanding;
+ int empty_steps;
+
+ double cur_latency;
+ double prev_latency;
+
+ double cur_accepted;
+ double prev_accepted;
+
+ double warmup_threshold;
+ double stopping_threshold;
+ double acc_stopping_threshold;
+
+ double min, avg;
+
+ bool clear_last;
+
+ _time = 0;
+
+ if ( _use_lagging ) {
+ for ( int s = 0; s < _sources; ++s ) {
+ for ( int c = 0; c < _classes; ++c ) {
+ _qtime[s][c] = 0;
+ _qdrained[s][c] = false;
+ }
+ }
+ }
+
+ if ( _voqing ) {
+ for ( int s = 0; s < _sources; ++s ) {
+ for ( int d = 0; d < _dests; ++d ) {
+ _active_vc[s][d] = false;
+ }
+ }
+ }
+
+ stopping_threshold = 0.01;
+ acc_stopping_threshold = 0.01;
+ warmup_threshold = 0.05;
+ iter = 0;
+ converged = 0;
+ max_outstanding = 0;
+ total_phases = 0;
+
+ // warm-up ...
+ // reset stats, all packets after warmup_time marked
+ // converge
+ // draing, wait until all packets finish
+
+ _sim_state = warming_up;
+ total_phases = 0;
+ prev_latency = 0;
+ prev_accepted = 0;
+
+ _ClearStats( );
+ clear_last = false;
+
+ while ( ( total_phases < _max_samples ) &&
+ ( ( _sim_state != running ) ||
+ ( converged < 3 ) ) ) {
+
+ if ( clear_last || ( ( _sim_state == warming_up ) && ( (total_phases & 0x1) == 0 ) ) ) {
+ clear_last = false;
+ _ClearStats( );
+ }
+
+ for ( iter = 0; iter < _sample_period; ++iter ) {
+ _Step( );
+ }
+
+ cout << "%=================================" << endl;
+
+ int dmin;
+
+ cur_latency = _latency_stats[0]->Average( );
+ dmin = _ComputeAccepted( &avg, &min );
+ cur_accepted = avg;
+
+ cout << "% Average latency = " << cur_latency << endl;
+
+ if ( _reorder ) {
+ cout << "% Reorder latency = " << _rob_latency->Average( ) << endl;
+ cout << "% Reorder size = " << _rob_size->Average( ) << endl;
+ }
+
+ cout << "% Accepted packets = " << min << " at node " << dmin << " (avg = " << avg << ")" << endl;
+
+ if ( MATLAB_OUTPUT ) {
+ cout << "lat(" << total_phases + 1 << ") = " << cur_latency << ";" << endl;
+ cout << "thru(" << total_phases + 1 << ",:) = [ ";
+ for ( int d = 0; d < _dests; ++d ) {
+ cout << _accepted_packets[d]->Average( ) << " ";
+ }
+ cout << "];" << endl;
+ }
+
+ // Fail safe
+ if ( ( _sim_mode == latency ) && ( cur_latency >_latency_thres ) ) {
+ cout << "Average latency is getting huge" << endl;
+ converged = 0;
+ _sim_state = warming_up;
+ break;
+ }
+
+ cout << "% latency change = " << fabs( ( cur_latency - prev_latency ) / cur_latency ) << endl;
+ cout << "% throughput change = " << fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) << endl;
+
+ if ( _sim_state == warming_up ) {
+
+ if ( _warmup_periods == 0 ) {
+ if ( _sim_mode == latency ) {
+ if ( ( fabs( ( cur_latency - prev_latency ) / cur_latency ) < warmup_threshold ) &&
+ ( fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) < warmup_threshold ) ) {
+ cout << "% Warmed up ..." << endl;
+ clear_last = true;
+ _sim_state = running;
+ }
+ } else {
+ if ( fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) < warmup_threshold ) {
+ cout << "% Warmed up ..." << endl;
+ clear_last = true;
+ _sim_state = running;
+ }
+ }
+ } else {
+ if ( total_phases + 1 >= _warmup_periods ) {
+ cout << "% Warmed up ..." << endl;
+ clear_last = true;
+ _sim_state = running;
+ }
+ }
+ } else if ( _sim_state == running ) {
+ if ( _sim_mode == latency ) {
+ if ( ( fabs( ( cur_latency - prev_latency ) / cur_latency ) < stopping_threshold ) &&
+ ( fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) < acc_stopping_threshold ) ) {
+ ++converged;
+ } else {
+ converged = 0;
+ }
+ } else {
+ if ( fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) > acc_stopping_threshold ) {
+ converged = 0;
+ }
+ }
+ }
+
+ prev_latency = cur_latency;
+ prev_accepted = cur_accepted;
+
+ ++total_phases;
+ }
+
+ if ( _sim_state == running ) {
+ ++converged;
+
+ if ( _sim_mode == latency ) {
+ cout << "% Draining all recorded packets ..." << endl;
+ _sim_state = draining;
+ _drain_time = _time;
+ empty_steps = 0;
+ while ( _PacketsOutstanding( ) ) {
+ _Step( );
+ ++empty_steps;
+
+ if ( empty_steps % 1000 == 0 ) {
+ _DisplayRemaining( );
+ }
+ }
+ }
+ } else {
+ cout << "Too many sample periods needed to converge" << endl;
+ }
+
+ // Empty any remaining packets
+ cout << "% Draining remaining packets ..." << endl;
+ _empty_network = true;
+ empty_steps = 0;
+ while ( _total_in_flight > 0 ) {
+ _Step( );
+ ++empty_steps;
+
+ if ( empty_steps % 1000 == 0 ) {
+ _DisplayRemaining( );
+ }
+ }
+ _empty_network = false;
+
+ return( converged > 0 );
+}
+
+void TrafficManager::SetDrainState( )
+{
+ _sim_state = draining;
+ _drain_time = _time;
+
+}
+
+void TrafficManager::ShowOveralStat( )
+{
+ int c;
+
+ for ( c = 0; c < _classes; ++c ) {
+ cout << "=======Traffic["<<uid<<"]class" << c << " ======" << endl;
+
+ cout << "Traffic["<<uid<<"]class" << c << "Overall average latency = " << _overall_latency[c]->Average( )
+ << " (" << _overall_latency[c]->NumSamples( ) << " samples)" << endl;
+
+ cout << "Traffic["<<uid<<"]class" << c << "Overall average accepted rate = " << _overall_accepted->Average( )
+ << " (" << _overall_accepted->NumSamples( ) << " samples)" << endl;
+
+ cout << "Traffic["<<uid<<"]class" << c << "Overall min accepted rate = " << _overall_accepted_min->Average( )
+ << " (" << _overall_accepted_min->NumSamples( ) << " samples)" << endl;
+
+ if ( DISPLAY_LAT_DIST ) {
+ _latency_stats[c]->Display( );
+ }
+ }
+
+ if ( _reorder ) {
+ cout << "Traffic["<<uid<<"]class" << c << "Overall average reorder latency = " << _rob_latency->Average( ) << endl;
+ cout << "Traffic["<<uid<<"]class" << c << "Overall average reorder size - " << _rob_size->Average( ) << endl;
+
+ if ( DISPLAY_LAT_DIST ) {
+ _rob_latency->Display( );
+ _rob_size->Display( );
+ }
+ }
+
+ if ( DISPLAY_HOP_DIST ) {
+ cout << "Traffic["<<uid<<"]class" << c << "Average hops = " << _hop_stats->Average( )
+ << " (" << _hop_stats->NumSamples( ) << " samples)" << endl;
+
+ _hop_stats->Display( );
+ }
+
+ if ( DISPLAY_PAIR_LATENCY ) {
+ for ( int i = 0; i < _dests; ++i ) {
+ cout << "Traffic["<<uid<<"]class" << c << " Average to " << i << " = " << _pair_latency[i]->Average( ) << "( "
+ << _pair_latency[i]->NumSamples( ) << " samples)" << endl;
+ _pair_latency[i]->Display( );
+ }
+ }
+}
+
+void TrafficManager::ShowStats()
+{
+ double min, avg;
+
+ static int total_phases;
+
+ double cur_latency;
+ static double prev_latency;
+
+ double cur_accepted;
+ static double prev_accepted;
+
+ //from step
+ cout << "%=================================" << endl;
+
+ cur_latency = _latency_stats[0]->Average( );
+ int dmin = _ComputeAccepted( &avg, &min );
+ cur_accepted = avg;
+
+ cout << "% Average latency = " << cur_latency << endl;
+
+ if ( _reorder ) {
+ cout << "% Reorder latency = " << _rob_latency->Average( ) << endl;
+ cout << "% Reorder size = " << _rob_size->Average( ) << endl;
+ }
+
+ cout << "% Accepted packets = " << min << " at node " << dmin << " (avg = " << avg << ")" << endl;
+
+ if ( MATLAB_OUTPUT ) {
+ cout << "lat(" << total_phases + 1 << ") = " << cur_latency << ";" << endl;
+ cout << "thru(" << total_phases + 1 << ",:) = [ ";
+ for ( int d = 0; d < _dests; ++d ) {
+ cout << _accepted_packets[d]->Average( ) << " ";
+ }
+ cout << "];" << endl;
+ }
+
+ cout << "% latency change = " << fabs( ( cur_latency - prev_latency ) / cur_latency ) << endl;
+ cout << "% throughput change = " << fabs( ( cur_accepted - prev_accepted ) / cur_accepted ) << endl;
+
+ prev_latency = cur_latency;
+ prev_accepted = cur_accepted;
+ total_phases++;
+
+
+ //from Run
+ //save last Grid's stats
+ for ( int c = 0; c < _classes; ++c ) {
+ _overall_latency[c]->AddSample( _latency_stats[c]->Average( ) );
+ }
+
+ //_ComputeAccepted( &avg, &min );
+ _overall_accepted->AddSample( avg );
+ _overall_accepted_min->AddSample( min );
+/* moved to interconnect_stats function in intreconnect_interface
+ cout << "%=================================" << endl;
+ cout << "Link utilizations:" << endl;
+ _net->Display();
+*/
+}
diff --git a/src/intersim/trafficmanager.hpp b/src/intersim/trafficmanager.hpp new file mode 100644 index 0000000..105d73c --- /dev/null +++ b/src/intersim/trafficmanager.hpp @@ -0,0 +1,173 @@ +#ifndef _TRAFFICMANAGER_HPP_
+#define _TRAFFICMANAGER_HPP_
+
+#include <list>
+#include <map>
+#include <queue>
+
+#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"
+
+class flitp_compare {
+public:
+ bool operator()( const Flit *a, const Flit *b ) const {
+ return( a->sn > b->sn );
+ }
+};
+
+class TrafficManager : public Module {
+public:
+ int _sources;
+ int _dests;
+
+ Network *_net;
+
+ // ============ Message priorities ============
+
+ enum ePriority {
+ class_based, age_based, none
+ };
+
+ ePriority _pri_type;
+ int _classes;
+
+ // ============ Injection VC states ============
+
+ BufferState **_buf_states;
+
+ // ============ Injection queues ============
+
+ int _voqing;
+ int **_qtime;
+ bool **_qdrained;
+ list<Flit *> **_partial_packets;
+
+ bool _use_lagging;
+
+ list<Flit *> **_voq;
+ list<int> *_active_list;
+ bool **_active_vc;
+
+ int _measured_in_flight;
+ int _total_in_flight;
+ map<int,bool> _in_flight;
+ bool _empty_network;
+
+ int _split_packets;
+
+ queue<Flit *> * credit_return_queue; //keeps flits that their corresponding credits are not sent yet
+ // ============ Reorder queues ============
+
+ bool _reorder;
+
+ int **_inject_sqn;
+ int **_rob_sqn;
+ int **_rob_sqn_max;
+ int *_rob_pri;
+
+ priority_queue<Flit *, vector<Flit *>, flitp_compare> **_rob;
+
+ // ============ Statistics ============
+
+ Stats **_latency_stats;
+ Stats **_overall_latency;
+ Stats *_rob_latency;
+ Stats *_rob_size;
+
+ Stats **_pair_latency;
+ Stats *_hop_stats;
+
+ Stats **_accepted_packets;
+ Stats *_overall_accepted;
+ Stats *_overall_accepted_min;
+
+ int **_latest_packet;
+
+ bool _flit_timing;
+
+ // ============ Simulation parameters ============
+
+ enum eSimState {
+ warming_up, running, draining, done
+ };
+ eSimState _sim_state;
+
+ enum eSimMode {
+ latency, throughput
+ };
+ eSimMode _sim_mode;
+
+ int _warmup_time;
+ int _drain_time;
+
+ float _load;
+ int _packet_size;
+
+ int _total_sims;
+ int _sample_period;
+ int _max_samples;
+ int _warmup_periods;
+
+ int _include_queuing;
+
+ double _latency_thres;
+
+ float _internal_speedup;
+ float _partial_internal_cycles;
+
+ int _cur_id;
+ int _time;
+
+ list<Flit *> _used_flits;
+ list<Flit *> _free_flits;
+
+ tTrafficFunction _traffic_function;
+ tRoutingFunction _routing_function;
+ tInjectionProcess _injection_process;
+
+ // ============ Internal methods ============
+
+ Flit *_NewFlit( );
+ void _RetireFlit( Flit *f, int dest );
+
+ void _FirstStep( );
+ void _Step( );
+
+ Flit *_ReadROB( int dest );
+
+ bool _PacketsOutstanding( ) const;
+
+ int _IssuePacket( int source, int cl ) const;
+ void _GeneratePacket( int source, int size, int cl, int time, void* data, int dest );
+
+ void _ClassInject( );
+ void _VOQInject( );
+
+ void _ClearStats( );
+
+ int _ComputeAccepted( double *avg, double *min ) const;
+
+ bool _SingleSim( );
+
+ void _DisplayRemaining( ) const;
+
+public:
+ int uid; // this traffic manger's ID useful when we have more than 1 traffic objects
+ TrafficManager( const Configuration &config, Network *net,int uid );
+ ~TrafficManager( );
+ void IcntInitPerGrid (int time);
+ void SetDrainState( );
+ void ShowStats();
+ void ShowOveralStat( );
+ void IcntInitPerGrid();
+};
+
+#endif
diff --git a/src/intersim/vc.cpp b/src/intersim/vc.cpp new file mode 100644 index 0000000..a1a4ff6 --- /dev/null +++ b/src/intersim/vc.cpp @@ -0,0 +1,175 @@ +#include "booksim.hpp"
+#include "vc.hpp"
+
+void VC::init( const Configuration& config, int outputs )
+{
+ _Init( config, outputs );
+}
+
+VC::VC( const Configuration& config, int outputs,
+ Module *parent, const string& name ) :
+Module( parent, name )
+{
+ _Init( config, outputs );
+}
+
+VC::~VC( )
+{
+}
+
+void VC::_Init( const Configuration& config, int outputs )
+{
+ _state = idle;
+ _state_time = 0;
+
+ _size = int( config.GetInt( "vc_buf_size" ) );
+
+ _route_set = new OutputSet( outputs );
+
+ _occupied_cnt = 0;
+
+ _total_cycles = 0;
+ _vc_alloc_cycles = 0;
+ _active_cycles = 0;
+ _idle_cycles = 0;
+
+ _pri = 0;
+
+ _watched = false;
+}
+
+bool VC::AddFlit( Flit *f )
+{
+ bool success = false;
+
+ if ( (int)_buffer.size( ) != _size ) {
+ _buffer.push( f );
+ success = true;
+ }
+
+ return success;
+}
+
+Flit *VC::FrontFlit( )
+{
+ Flit *f;
+
+ if ( !_buffer.empty( ) ) {
+ f = _buffer.front( );
+ } else {
+ f = 0;
+ }
+
+ return f;
+}
+
+Flit *VC::RemoveFlit( )
+{
+ Flit *f;
+
+ if ( !_buffer.empty( ) ) {
+ f = _buffer.front( );
+ _buffer.pop( );
+ } else {
+ f = 0;
+ }
+
+ return f;
+}
+
+bool VC::Empty( ) const
+{
+ return _buffer.empty( );
+}
+
+VC::eVCState VC::GetState( ) const
+{
+ return _state;
+}
+
+int VC::GetStateTime( ) const
+{
+ return _state_time;
+}
+
+void VC::SetState( eVCState s )
+{
+ _state = s;
+ _state_time = 0;
+
+ if ( s == active ) {
+ Flit *f;
+
+ f = FrontFlit( );
+ if ( f ) {
+ _pri = f->pri;
+ }
+
+ _occupied_cnt++;
+ }
+}
+
+const OutputSet *VC::GetRouteSet( ) const
+{
+ return _route_set;
+}
+
+void VC::SetOutput( int port, int vc )
+{
+ _out_port = port;
+ _out_vc = vc;
+}
+
+int VC::GetOutputPort( ) const
+{
+ return _out_port;
+}
+
+int VC::GetOutputVC( ) const
+{
+ return _out_vc;
+}
+
+int VC::GetPriority( ) const
+{
+ return _pri;
+}
+
+void VC::Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel )
+{
+ rf( router, f, in_channel, _route_set, false );
+}
+
+void VC::AdvanceTime( )
+{
+ _state_time++;
+
+ _total_cycles++;
+ switch ( _state ) {
+ case idle : _idle_cycles++; break;
+ case active : _active_cycles++; break;
+ case vc_alloc : _vc_alloc_cycles++; break;
+ case routing : break;
+ }
+}
+
+// ==== Debug functions ====
+
+void VC::SetWatch( bool watch )
+{
+ _watched = watch;
+}
+
+bool VC::IsWatched( ) const
+{
+ return _watched;
+}
+
+void VC::Display( ) const
+{
+ cout << _fullname << " : "
+ << "idle " << 100.0 * (double)_idle_cycles / (double)_total_cycles << "% "
+ << "vc_alloc " << 100.0 * (double)_vc_alloc_cycles / (double)_total_cycles << "% "
+ << "active " << 100.0 * (double)_active_cycles / (double)_total_cycles << "% "
+ << endl;
+}
diff --git a/src/intersim/vc.hpp b/src/intersim/vc.hpp new file mode 100644 index 0000000..ecb8c2d --- /dev/null +++ b/src/intersim/vc.hpp @@ -0,0 +1,79 @@ +#ifndef _VC_HPP_
+#define _VC_HPP_
+
+#include <queue>
+
+#include "flit.hpp"
+#include "outputset.hpp"
+#include "routefunc.hpp"
+#include "config_utils.hpp"
+
+class VCRouter;
+
+class VC : public Module {
+public:
+ enum eVCState {
+ idle, routing, vc_alloc, active
+ };
+
+private:
+ int _size;
+
+ queue<Flit *> _buffer;
+
+ eVCState _state;
+ int _state_time;
+
+ OutputSet *_route_set;
+ int _out_port, _out_vc;
+
+ int _occupied_cnt;
+ int _total_cycles;
+ int _vc_alloc_cycles;
+ int _active_cycles;
+ int _idle_cycles;
+
+ int _pri;
+
+ void _Init( const Configuration& config, int outputs );
+
+ bool _watched;
+
+public:
+ VC() : Module() {}
+ void init( const Configuration& config, int outputs );
+ VC( const Configuration& config, int outputs,
+ Module *parent, const string& name );
+ ~VC( );
+
+ bool AddFlit( Flit *f );
+ Flit *FrontFlit( );
+ Flit *RemoveFlit( );
+
+ bool Empty( ) const;
+
+ eVCState GetState( ) const;
+ int GetStateTime( ) const;
+ void SetState( eVCState s );
+
+ const OutputSet *GetRouteSet( ) const;
+
+ void SetOutput( int port, int vc );
+ int GetOutputPort( ) const;
+ int GetOutputVC( ) const;
+
+ int GetPriority( ) const;
+
+ void Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel );
+
+ void AdvanceTime( );
+
+ // ==== Debug functions ====
+
+ void SetWatch( bool watch = true );
+ bool IsWatched( ) const;
+
+ void Display( ) const;
+};
+
+#endif
diff --git a/src/intersim/wavefront.cpp b/src/intersim/wavefront.cpp new file mode 100644 index 0000000..c9fab7a --- /dev/null +++ b/src/intersim/wavefront.cpp @@ -0,0 +1,61 @@ +#include "booksim.hpp"
+#include <iostream>
+
+#include "wavefront.hpp"
+#include "random_utils.hpp"
+
+Wavefront::Wavefront( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs ) :
+DenseAllocator( config, parent, name, inputs, outputs )
+{
+ // We need a square wavefront allocator, so take the max dimension
+ _square = ( _inputs > _outputs ) ? _inputs : _outputs;
+
+ // The diagonal with priority
+ _pri = 0;
+}
+
+Wavefront::~Wavefront( )
+{
+}
+
+void Wavefront::Allocate( )
+{
+ int input;
+ int output;
+
+ // Clear matching
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ _inmatch[i] = -1;
+ }
+ for ( int j = 0; j < _outputs; ++j ) {
+ _outmatch[j] = -1;
+ }
+
+ // Loop through diagonals of request matrix
+
+ for ( int p = 0; p < _square; ++p ) {
+ output = ( _pri + p ) % _square;
+
+ // Step through the current diagonal
+ for ( input = 0; input < _inputs; ++input ) {
+ if ( ( output < _outputs ) &&
+ ( _inmatch[input] == -1 ) &&
+ ( _outmatch[output] == -1 ) &&
+ ( _request[input][output].label != -1 ) ) {
+ // Grant!
+ _inmatch[input] = output;
+ _outmatch[output] = input;
+ }
+
+ output = ( output + 1 ) % _square;
+ }
+ }
+
+ // Round-robin the priority diagonal
+ _pri = ( _pri + 1 ) % _square;
+}
+
+
diff --git a/src/intersim/wavefront.hpp b/src/intersim/wavefront.hpp new file mode 100644 index 0000000..d0c9ba6 --- /dev/null +++ b/src/intersim/wavefront.hpp @@ -0,0 +1,19 @@ +#ifndef _WAVEFRONT_HPP_
+#define _WAVEFRONT_HPP_
+
+#include "allocator.hpp"
+
+class Wavefront : public DenseAllocator {
+ int _square;
+ int _pri;
+
+public:
+ Wavefront( const Configuration &config,
+ Module *parent, const string& name,
+ int inputs, int outputs );
+ ~Wavefront( );
+
+ void Allocate( );
+};
+
+#endif
|
