summaryrefslogtreecommitdiff
path: root/src/intersim2/routers
diff options
context:
space:
mode:
authorDongdong Li <[email protected]>2013-08-08 00:15:58 -0800
committerAndrew Boktor <[email protected]>2014-08-14 13:50:58 -0700
commit7f49fe9feb174d34efc2a011bad79b38522a360b (patch)
treeab5b7b66e40315a81871acbf386722981020f866 /src/intersim2/routers
parent5f91e7435742bab74dfbeca18afc63e466498f36 (diff)
Intesim2 Integration
Details: See Review 80001 https://gpgpu-sim-code-review.appspot.com/80001/ [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 16747]
Diffstat (limited to 'src/intersim2/routers')
-rw-r--r--src/intersim2/routers/chaos_router.cpp673
-rw-r--r--src/intersim2/routers/chaos_router.hpp132
-rw-r--r--src/intersim2/routers/event_router.cpp890
-rw-r--r--src/intersim2/routers/event_router.hpp187
-rw-r--r--src/intersim2/routers/iq_router.cpp2385
-rw-r--r--src/intersim2/routers/iq_router.hpp183
-rw-r--r--src/intersim2/routers/router.cpp155
-rw-r--r--src/intersim2/routers/router.hpp202
8 files changed, 4807 insertions, 0 deletions
diff --git a/src/intersim2/routers/chaos_router.cpp b/src/intersim2/routers/chaos_router.cpp
new file mode 100644
index 0000000..10c6277
--- /dev/null
+++ b/src/intersim2/routers/chaos_router.cpp
@@ -0,0 +1,673 @@
+// $Id: chaos_router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "booksim.hpp"
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstdlib>
+
+#include "chaos_router.hpp"
+#include "random_utils.hpp"
+#include "globals.hpp"
+
+ChaosRouter::ChaosRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+ : Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ int i;
+
+ if ( inputs != outputs ) {
+ Error( "Chaos router must have equal number of input and output ports" );
+ }
+
+ _buffer_size = config.GetInt( "vc_buf_size" );
+ assert(_buffer_size >= config.GetInt( "const_flits_per_packet" ));
+
+ _multi_queue_size = config.GetInt( "multi_queue_size" );
+
+ _cur_channel = 0;
+ _read_stall = 0;
+
+ // Routing
+
+ string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ _input_route.resize(_inputs);
+
+ for ( i = 0; i < _inputs; ++i ) {
+ _input_route[i] = new OutputSet( );
+ }
+
+ _mq_route.resize(_multi_queue_size);
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ _mq_route[i] = new OutputSet( );
+ }
+
+ // Alloc pipelines (to simulate processing/transmission delays)
+
+ _crossbar_pipe =
+ new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs,
+ _crossbar_delay );
+
+ // Input and output queues
+
+ _input_frame.resize(_inputs);
+ _output_frame.resize(_outputs);
+ _multi_queue.resize(_multi_queue_size);
+
+ _credit_queue.resize(_inputs);
+
+ _input_state.resize(_inputs, empty);
+ _input_output_match.resize(_inputs, -1);
+ _input_mq_match.resize(_inputs, -1);
+
+ _output_matched.resize(_outputs, false);
+ _next_queue_cnt.resize(_outputs, 0);
+
+ _multi_match.resize(_multi_queue_size, -1);
+ _mq_age.resize(_multi_queue_size);
+ _mq_matched.resize(_multi_queue_size, false);
+ _multi_state.resize(_multi_queue_size, empty);
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ _multi_state[i] = empty;
+ _multi_match[i] = -1;
+ _mq_matched[i] = false;
+ }
+}
+
+ChaosRouter::~ChaosRouter( )
+{
+ int i;
+
+ delete _crossbar_pipe;
+
+ for ( i = 0; i < _inputs; ++i ) {
+ delete _input_route[i];
+ }
+
+ for ( i = 0; i < _multi_queue_size; ++i ) {
+ delete _mq_route[i];
+ }
+}
+
+void ChaosRouter::ReadInputs( )
+{
+ Flit *f;
+ Credit *c;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ f = _input_channels[input]->Receive();
+
+ if ( f ) {
+ _input_frame[input].push( f );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit arriving at " << FullName()
+ << " on channel " << input << endl
+ << *f;
+ }
+
+ switch( _input_state[input] ) {
+ case empty:
+ if ( f->head ) {
+ if ( f->tail ) {
+ _input_state[input] = full;
+ } else {
+ _input_state[input] = filling;
+ }
+ _rf( this, f, input, _input_route[input], false );
+ } else {
+ cout << *f;
+ Error( "Empty buffer received non-head flit!" );
+ }
+ break;
+
+ case filling:
+ if ( f->tail ) {
+ _input_state[input] = full;
+ } else if ( f->head ) {
+ Error( "Input buffer received another head before previous tail!" );
+ }
+ break;
+
+ case full:
+ Error( "Received flit while full!" );
+ break;
+
+ case leaving:
+ if ( f->head ) {
+ _input_state[input] = shared;
+
+ if ( f->tail ) {
+ Error( "Received single-flit packet in leaving state!" );
+ }
+ } else {
+ cout << *f;
+ Error( "Received non-head flit while packet leaving!" );
+ }
+ break;
+
+ case cut_through:
+ if ( f->tail ) {
+ _input_state[input] = leaving;
+ }
+ if ( f->head ) {
+ cout << *f;
+ Error( "Received head flit in cut through buffer!" );
+ }
+ break;
+
+ case shared:
+ if ( f->head ) {
+ Error( "Shared buffer received another head!" );
+ } else if ( f->tail ) {
+ cout << "Input " << input << endl;
+ cout << *f;
+ Error( "Shared buffer received another tail!" );
+ }
+ break;
+ }
+ }
+ }
+
+ // Process incoming credits
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = _output_credits[output]->Receive();
+
+ if ( c ) {
+ _next_queue_cnt[output]--;
+
+ if ( _next_queue_cnt[output] < 0 ) {
+ Error( "Next queue count fell below zero!" );
+ }
+
+ c->Free();
+ }
+ }
+}
+
+void ChaosRouter::_InternalStep( )
+{
+ _NextInterestingChannel( );
+ _OutputAdvance( );
+
+ _crossbar_pipe->Advance( );
+}
+
+void ChaosRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+bool ChaosRouter::_IsInjectionChan( int chan ) const
+{
+ return ( chan == _inputs - 1 );
+}
+
+bool ChaosRouter::_IsEjectionChan( int chan ) const
+{
+ return ( chan == _outputs - 1 );
+}
+
+bool ChaosRouter::_InputReady( int input ) const
+{
+ bool ready = false;
+
+ if ( ( _input_state[input] == filling ) ||
+ ( _input_state[input] == full ) ) {
+ ready = true;
+ }
+
+ return ready;
+}
+
+bool ChaosRouter::_OutputFull( int out ) const
+{
+ return ( _output_frame[out].size( ) >= (size_t)_buffer_size );
+}
+
+bool ChaosRouter::_OutputAvail( int out ) const
+{
+ return ( ( !_output_matched[out] ) && ( _output_frame[out].empty( ) ) );
+ //&& ( _next_queue_cnt[out] == 0 ) );
+ //return ( ( !_output_matched[out] ) && !_OutputFull( out ) );
+}
+
+bool ChaosRouter::_MultiQueueFull( int mq ) const
+{
+ return ( _multi_queue[mq].size( ) >= (size_t)_buffer_size );
+}
+
+int ChaosRouter::_InputForOutput( int output ) const
+{
+ // return an input that prefers this output
+
+ int input;
+ int offset = RandomInt( _inputs - 1 );
+ bool match = false;
+
+ for ( int i = 0; ( i < _inputs ) && ( !match ); ++i ) {
+ input = ( i + offset ) % _inputs;
+
+ if ( _InputReady( input ) &&
+ ( ! _input_route[input]->OutputEmpty( output ) ) ) {
+ match = true;
+ }
+ }
+
+ return match ? input : -1;
+}
+
+int ChaosRouter::_MultiQueueForOutput( int output ) const
+{
+ // return oldest multi queue that prefers the output,
+ // or if none prefer and the multi queue is full,
+ // return a random entry
+
+ int mq_oldest = -1;
+ int mq_age;
+
+ int m, r;
+
+ bool isfull = true;
+
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ if ( ( _multi_match[i] == -1 ) &&
+ ( ( _multi_state[i] == full ) ||
+ ( _multi_state[i] == filling ) ) ) {
+
+ if ( ( !_mq_route[i]->OutputEmpty( output ) ) &&
+ ( ( mq_oldest == -1 ) || ( _mq_age[i] > mq_age ) ) ) {
+ mq_oldest = i;
+ mq_age = _mq_age[i];
+ }
+ }
+
+ // deroute only if all queues contain head flits ...
+
+ if ( ( _multi_state[i] != full ) &&
+ ( _multi_state[i] != filling ) &&
+ ( _multi_state[i] != shared ) ) {
+ isfull = false;
+ }
+ }
+
+ // Don't deroute MQs to the ejection channel
+ if ( ( mq_oldest == -1 ) && isfull &&
+ ( !_IsEjectionChan( output ) ) ) {
+ r = RandomInt( _multi_queue_size - 1 );
+
+ // Find first routable multi-queue
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ m = ( i + r ) % _multi_queue_size;
+ if ( ( _multi_state[m] == filling ) ||
+ ( _multi_state[m] == full ) ) {
+ mq_oldest = m;
+ //cout << "DEROUTING at " << FullName() << endl;
+ break;
+ }
+ }
+
+ if ( mq_oldest == -1 ) {
+ cout << "write stall" << endl;
+ }
+ }
+
+ return mq_oldest;
+}
+
+int ChaosRouter::_FindAvailMultiQueue( ) const
+{
+ // return any empty multi queue slot
+
+ int avail = -1;
+
+ for ( int i = 0; i < _multi_queue_size; ++i ) {
+ if ( ( !_MultiQueueFull( i ) ) &&
+ ( !_mq_matched[i] ) ) {
+ avail = i;
+ break;
+ }
+ }
+
+ return avail;
+}
+
+void ChaosRouter::_NextInterestingChannel( )
+{
+ bool interesting;
+
+ int mq_index;
+ int in_index;
+ int mq_avail;
+
+ int c;
+
+ interesting = false;
+ mq_index = -1;
+ in_index = -1;
+
+ // A channel is interesting if
+ //
+ // ( output frame available and
+ // ( ( a multiqueue packet wants output channel ) or
+ // ( an input packet wants output channel ) or
+ // ( the multiqueue is full ) ) )
+ // or
+ // ( the packet at the input channel is stalled )
+
+ for ( c = 0; ( c < _inputs ) && ( !interesting ); ++c ) {
+ if ( _OutputAvail( _cur_channel ) ) {
+ mq_index = _MultiQueueForOutput( _cur_channel );
+ in_index = _InputForOutput( _cur_channel );
+
+ if ( ( mq_index != -1 ) || ( in_index != -1 ) ) {
+ interesting = true;
+ }
+ }
+
+ if ( _input_state[_cur_channel] == full ) {
+ interesting = true;
+ }
+
+ if ( !interesting ) {
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ }
+ }
+
+ if ( interesting ) {
+ //cout << _cur_channel << " is interesting at " << FullName() << endl;
+
+ if ( mq_index != -1 ) {
+ //cout << "Match for multi-queue " << mq_index << " at " << FullName()
+ // << ", output matched = " << _output_matched[_cur_channel] << endl;
+
+ _output_matched[_cur_channel] = true;
+ _multi_match[mq_index] = _cur_channel;
+ } else if ( in_index != -1 ) {
+ _output_matched[_cur_channel] = true;
+ _input_output_match[in_index] = _cur_channel;
+
+ //cout << "Match for input " << in_index << " at " << FullName() << endl;
+
+ if ( _input_state[in_index] == full ) {
+ _input_state[in_index] = leaving;
+ } else if ( _input_state[in_index] == filling ) {
+ _input_state[in_index] = cut_through;
+ } else {
+ Error( "Tried to route input through crossbar that was not full or filling!" );
+ }
+ }
+
+ // Any non-injection channel that is routable is
+ // directed to the multi-queue
+ if ( ( ( _input_state[_cur_channel] == filling ) ||
+ ( _input_state[_cur_channel] == full ) ) &&
+ ( !_IsInjectionChan( _cur_channel ) ) ) {
+ ++_read_stall;
+ } else {
+ // go to next channel for the next cycle
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ _read_stall = 0;
+ }
+ }
+
+ if ( _read_stall > 0 ) {
+ mq_avail = _FindAvailMultiQueue( );
+
+ if ( mq_avail != -1 ) {
+ if ( _input_state[_cur_channel] == full ) {
+ _input_state[_cur_channel] = leaving;
+ } else if ( _input_state[_cur_channel] == filling ) {
+ _input_state[_cur_channel] = cut_through;
+ } else {
+ cout << "Input " << _cur_channel << " state = "
+ << _input_state[_cur_channel] << endl;
+ Error( "Tried to route input throught multi-queue that was not full or filling!" );
+ }
+
+ _input_mq_match[_cur_channel] = mq_avail;
+ _mq_matched[mq_avail] = true;
+
+ // go to next channel for the next cycle
+ _cur_channel = ( _cur_channel + 1 ) % _inputs;
+ _read_stall = 0;
+ } else {
+ ++_read_stall;
+ //cout << "stalling at input " << _cur_channel << " (count = " << _read_stall << ")" << endl;
+ }
+ }
+}
+
+void ChaosRouter::_OutputAdvance( )
+{
+ Flit *f, *f2;
+ Credit *c;
+ bool advanced;
+ int mq;
+
+ _crossbar_pipe->WriteAll( 0 );
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ if ( ( ( _input_output_match[i] != -1 ) ||
+ ( _input_mq_match[i] != -1 ) ) &&
+ ( !_input_frame[i].empty( ) ) ) {
+
+ advanced = false;
+ f = _input_frame[i].front( );
+
+ /*if ( ! ) {
+
+ } else {
+ cout << "Input = " << i
+ << ", input_output_match = " << _input_output_match[i]
+ << ", input_mq_match = " << _input_mq_match[i] << endl;
+ Error( "Input queue empty, but matched!" );
+ }*/
+
+ if ( _input_output_match[i] != -1 ) {
+ if ( f->tail ) {
+ _output_matched[_input_output_match[i]] = false;
+ }
+
+ _crossbar_pipe->Write( f, _input_output_match[i] );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit traversing crossbar from input queue "
+ << i << " at "
+ << FullName() << endl
+ << *f;
+ }
+
+ advanced = true;
+
+ } else if ( !_MultiQueueFull( _input_mq_match[i] ) ) {
+
+ mq = _input_mq_match[i];
+
+ if ( f->head ) {
+ _rf( this, f, i, _mq_route[mq], false );
+ _mq_age[mq] = 0;
+
+ if ( _multi_state[mq] == empty ) {
+ _multi_state[mq] = filling;
+ } else if ( _multi_state[mq] == leaving ) {
+ _multi_state[mq] = shared;
+ } else {
+ Error( "Multi-queue received head while not empty or leaving!" );
+ }
+ }
+
+ if ( f->tail ) {
+ _mq_matched[mq] = false;
+
+ if ( _multi_state[mq] == filling ) {
+ _multi_state[mq] = full;
+ } else if ( _multi_state[mq] == cut_through ) {
+ _multi_state[mq] = leaving;
+ } else {
+ Error( "Multi-queue received tail while not filling or cutting-through!" );
+ }
+ }
+
+ _multi_queue[mq].push( f );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit stored in multiqueue at "
+ << FullName() << endl
+ << "State = " << _multi_state[mq] << endl
+ << *f;
+ }
+
+ advanced = true;
+ }
+
+ if ( advanced ) {
+ _input_frame[i].pop( );
+
+ if ( f->tail ) { // last in packet, update state
+ if ( _input_state[i] == leaving ) {
+ _input_state[i] = empty;
+ } else if ( _input_state[i] == shared ) {
+ _input_state[i] = filling;
+ f2 = _input_frame[i].front( );
+ // update routes
+ _rf( this, f2, i, _input_route[i], false );
+ }
+
+ _input_output_match[i] = -1;
+ _input_mq_match[i] = -1;
+ }
+
+ c = Credit::New( );
+ c->vc.insert(0);
+ _credit_queue[i].push( c );
+ }
+ }
+ }
+
+ for ( int m = 0; m < _multi_queue_size; ++m ) {
+ if ( _multi_match[m] != -1 ) {
+ if ( !_multi_queue[m].empty( ) ) {
+ f = _multi_queue[m].front( );
+ _multi_queue[m].pop( );
+ } else {
+ cout << "State = " << _multi_state[m] << endl;
+ Error( "Multi queue empty, but matched!" );
+ }
+
+ _crossbar_pipe->Write( f, _multi_match[m] );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Flit traversing crossbar from multiqueue slot "
+ << m << " at "
+ << FullName() << endl
+ << *f;
+ }
+
+ if ( f->head ) {
+ if ( _multi_state[m] == filling ) {
+ _multi_state[m] = cut_through;
+ } else if ( _multi_state[m] == full ) {
+ _multi_state[m] = leaving;
+ } else {
+ Error( "Multi-queue sent head while not filling or full!" );
+ }
+ }
+
+ if ( f->tail ) {
+ _output_matched[_multi_match[m]] = false;
+ _multi_match[m] = -1;
+
+ if ( _multi_state[m] == shared ) {
+ _multi_state[m] = filling;
+ } else if ( _multi_state[m] == leaving ) {
+ _multi_state[m] = empty;
+ } else {
+ cout << "State = " << _multi_state[m] << endl;
+ cout << *f;
+ Error( "Multi-queue sent tail while not leaving or shared!" );
+ }
+ }
+ }
+
+ _mq_age[m]++;
+ }
+}
+
+
+void ChaosRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ Flit *f = _crossbar_pipe->Read( output );
+
+ if ( f ) {
+ _output_frame[output].push( f );
+ f->hops++;
+ }
+
+ if ( ( _next_queue_cnt[output] < _buffer_size ) &&
+ ( !_output_frame[output].empty( ) ) ) {
+ _output_channels[output]->Send( _output_frame[output].front( ) );
+ _output_frame[output].pop( );
+ ++_next_queue_cnt[output];
+ }
+ }
+}
+
+void ChaosRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_credit_queue[input].empty( ) ) {
+ Credit *c = _credit_queue[input].front( );
+ _credit_queue[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+void ChaosRouter::Display( ostream & os ) const
+{
+}
diff --git a/src/intersim2/routers/chaos_router.hpp b/src/intersim2/routers/chaos_router.hpp
new file mode 100644
index 0000000..df843ff
--- /dev/null
+++ b/src/intersim2/routers/chaos_router.hpp
@@ -0,0 +1,132 @@
+// $Id: chaos_router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _CHAOS_ROUTER_HPP_
+#define _CHAOS_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "allocator.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "buffer_state.hpp"
+#include "pipefifo.hpp"
+#include "vc.hpp"
+
+class ChaosRouter : public Router {
+
+ tRoutingFunction _rf;
+
+ vector<OutputSet*> _input_route;
+ vector<OutputSet*> _mq_route;
+
+ enum eQState {
+ empty, // input avail
+ filling, // >**H ready to send
+ full, // T****H ready to send
+ leaving, // T***> input avail
+ cut_through, // >***>
+ shared // >**HT**>
+ };
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+
+ int _multi_queue_size;
+ int _buffer_size;
+
+ vector<queue<Flit *> > _input_frame;
+ vector<queue<Flit *> > _output_frame;
+ vector<queue<Flit *> > _multi_queue;
+
+ vector<int> _next_queue_cnt;
+
+ vector<queue<Credit *> > _credit_queue;
+
+ vector<eQState> _input_state;
+ vector<eQState> _multi_state;
+
+ vector<int> _input_output_match;
+ vector<int> _input_mq_match;
+ vector<int> _multi_match;
+
+ vector<int> _mq_age;
+
+ vector<bool> _output_matched;
+ vector<bool> _mq_matched;
+
+ int _cur_channel;
+ int _read_stall;
+
+ bool _IsInjectionChan( int chan ) const;
+ bool _IsEjectionChan( int chan ) const;
+
+ bool _InputReady( int input ) const;
+ bool _OutputFull( int out ) const;
+ bool _OutputAvail( int out ) const;
+ bool _MultiQueueFull( int mq ) const;
+
+ int _InputForOutput( int output ) const;
+ int _MultiQueueForOutput( int output ) const;
+ int _FindAvailMultiQueue( ) const;
+
+ void _NextInterestingChannel( );
+ void _OutputAdvance( );
+ void _SendFlits( );
+ void _SendCredits( );
+
+ virtual void _InternalStep( );
+
+public:
+ ChaosRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ virtual ~ChaosRouter( );
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ virtual int GetUsedCredit(int out) const {return 0;}
+ virtual int GetBufferOccupancy(int i) const {return 0;}
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const {return 0;}
+ virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;}
+#endif
+
+ virtual vector<int> UsedCredits() const { return vector<int>(); }
+ virtual vector<int> FreeCredits() const { return vector<int>(); }
+ virtual vector<int> MaxCredits() const { return vector<int>(); }
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/routers/event_router.cpp b/src/intersim2/routers/event_router.cpp
new file mode 100644
index 0000000..e3f9712
--- /dev/null
+++ b/src/intersim2/routers/event_router.cpp
@@ -0,0 +1,890 @@
+// $Id: event_router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <cstdlib>
+#include <cassert>
+
+#include "event_router.hpp"
+#include "stats.hpp"
+#include "globals.hpp"
+
+EventRouter::EventRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+ : Router( config,
+ parent, name,
+ id,
+ inputs, outputs )
+{
+ ostringstream module_name;
+
+ _vcs = config.GetInt( "num_vcs" );
+
+ // Cut-through mode --- packets are not broken
+ // up and input buffers are assumed to be
+ // expressed in units of maximum size packets.
+
+ _vct = config.GetInt( "vct" );
+
+ // Routing
+
+ string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ // Alloc VC's
+
+ _buf.resize(_inputs);
+ _active.resize(_inputs);
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ module_name << "buf_" << i;
+ _buf[i] = new Buffer( config, _outputs, this, module_name.str( ) );
+ module_name.seekp( 0, ios::beg );
+ _active[i].resize(_vcs, false);
+ }
+
+ // Alloc next VCs' state
+
+ _output_state.resize(_outputs);
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ module_name << "output" << o << "_vc_state";
+ _output_state[o] = new EventNextVCState(config, this, module_name.str());
+ module_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc arbiters
+
+ _arrival_arbiter.resize(_outputs);
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ module_name << "arrival_arb_output" << o;
+ _arrival_arbiter[o] =
+ new PriorityArbiter( config, this, module_name.str( ), _inputs );
+ module_name.seekp( 0, ios::beg );
+ }
+
+ _transport_arbiter.resize(_inputs);
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ module_name << "transport_arb_input" << i;
+ _transport_arbiter[i] =
+ new PriorityArbiter( config, this, module_name.str( ), _outputs );
+ module_name.seekp( 0, ios::beg );
+ }
+
+ // Alloc pipelines (to simulate processing/transmission delays)
+
+ _crossbar_pipe =
+ new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs,
+ _crossbar_delay );
+
+ _credit_pipe =
+ new PipelineFIFO<Credit>( this, "credit_pipeline", _inputs,
+ _credit_delay );
+
+ _arrival_pipe =
+ new PipelineFIFO<tArrivalEvent>( this, "arrival_pipeline", _inputs,
+ 0 /* FIX THIS EVENTUALLY */);
+
+ // Queues
+
+ _input_buffer.resize(_inputs);
+ _output_buffer.resize(_outputs);
+
+ _in_cred_buffer.resize(_inputs);
+ _out_cred_buffer.resize(_outputs);
+
+ _arrival_queue.resize(_inputs);
+ _transport_queue.resize(_outputs);
+
+ // Misc.
+
+ _transport_free.resize(_inputs, true);
+ _transport_match.resize(_inputs, -1);
+}
+
+EventRouter::~EventRouter( )
+{
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete _buf[i];
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ delete _output_state[o];
+ }
+
+ for ( int o = 0; o < _outputs; ++o ) {
+ delete _arrival_arbiter[o];
+ }
+
+ for ( int i = 0; i < _inputs; ++i ) {
+ delete _transport_arbiter[i];
+ }
+
+ delete _crossbar_pipe;
+ delete _credit_pipe;
+ delete _arrival_pipe;
+}
+
+void EventRouter::ReadInputs( )
+{
+ _ReceiveFlits( );
+ _ReceiveCredits( );
+}
+
+void EventRouter::_InternalStep( )
+{
+ // Receive incoming flits
+ _IncomingFlits( );
+
+ // The input pipe simulates routing delay
+ _arrival_pipe->Advance( );
+
+ // Clear output requests
+ for ( int output = 0; output < _outputs; ++output ) {
+ _arrival_arbiter[output]->Clear( );
+ }
+
+ // Check input arrival queues and generate
+ // requests for the outputs
+ for ( int input = 0; input < _inputs; ++input ) {
+ _ArrivalRequests( input );
+ }
+
+ // Arbitrate between requests at outputs
+ for ( int output = 0; output < _outputs; ++output ) {
+ _ArrivalArb( output );
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ _transport_arbiter[input]->Clear( );
+ }
+
+ _crossbar_pipe->WriteAll( 0 );
+ _credit_pipe->WriteAll( 0 );
+
+ // Generate transport events and their
+ // requests for the inputs
+ for ( int output = 0; output < _outputs; ++output ) {
+ _TransportRequests( output );
+ }
+
+ // Arbitrate between requests at inputs
+ for ( int input = 0; input < _inputs; ++input ) {
+ _TransportArb( input );
+ }
+
+ _crossbar_pipe->Advance( );
+ _credit_pipe->Advance( );
+
+ _OutputQueuing( );
+}
+
+void EventRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+void EventRouter::_ReceiveFlits( )
+{
+ Flit *f;
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ f = _input_channels[input]->Receive();
+
+ if ( f ) {
+ _input_buffer[input].push( f );
+ }
+ }
+}
+
+void EventRouter::_ReceiveCredits( )
+{
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ c = _output_credits[output]->Receive();
+
+ if ( c ) {
+ _out_cred_buffer[output].push( c );
+ }
+ }
+}
+
+void EventRouter::_ProcessWaiting( int output, int out_vc )
+{
+ // out_vc just sent the transport event for out_vc,
+ // check if any events are queued on that vc. if so,
+ // generate another transport event and set the
+ // owner of the vc, otherwise set the vc to idle.
+
+ int credits;
+
+ tTransportEvent *tevt;
+
+ EventNextVCState::tWaiting *w;
+
+ if ( _output_state[output]->IsWaiting( out_vc ) ) {
+
+ // State remains as busy, but the waiting VC takes over
+ w = _output_state[output]->PopWaiting( out_vc );
+
+ _output_state[output]->SetState( out_vc, EventNextVCState::busy );
+ _output_state[output]->SetInput( out_vc, w->input );
+ _output_state[output]->SetInputVC( out_vc, w->vc );
+
+ if ( w->watch ) {
+ cout << "Dequeuing waiting arrival event at " << FullName()
+ << " for flit " << w->id << endl;
+ }
+
+ credits = _output_state[output]->GetCredits( out_vc );
+
+ // Try to queue a transmit event for a waiting packet
+ if ( credits > 0 ) {
+ tevt = new tTransportEvent;
+ tevt->src_vc = w->vc;
+ tevt->dst_vc = out_vc;
+ tevt->input = w->input;
+ tevt->watch = w->watch; // just to have something here
+ tevt->id = w->id;
+
+ _transport_queue[output].push( tevt );
+
+ if ( tevt->watch ) {
+ cout << "Injecting transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+
+ credits--;
+ _output_state[output]->SetCredits( out_vc, credits );
+ _output_state[output]->SetPresence( out_vc, w->pres - 1 );
+
+ } else {
+ // No credits available, just store presence
+ _output_state[output]->SetPresence( out_vc, w->pres );
+ }
+
+ delete w;
+
+ } else {
+ // Tail sent, none waiting => VC is idle
+ _output_state[output]->SetState( out_vc, EventNextVCState::idle );
+ }
+}
+
+void EventRouter::_IncomingFlits( )
+{
+ Flit *f;
+ Buffer *cur_buf;
+
+ tArrivalEvent *aevt;
+
+ _arrival_pipe->WriteAll( 0 );
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_input_buffer[input].empty( ) ) {
+ f = _input_buffer[input].front( );
+ _input_buffer[input].pop( );
+
+ cur_buf = _buf[input];
+ int vc = f->vc;
+
+ cur_buf->AddFlit( vc, f );
+
+ // Head flit arriving at idle VC
+ if ( !_active[input][vc] ) {
+
+ if ( !f->head ) {
+ cout << "Non-head flit:" << endl;
+ cout << *f;
+ Error( "Received non-head flit at idle VC" );
+ }
+
+ const OutputSet *route_set;
+ int out_vc, out_port;
+
+ cur_buf->Route( vc, _rf, this, f, input );
+ route_set = cur_buf->GetRouteSet( vc );
+
+ if ( !route_set->GetPortVC( &out_port, &out_vc ) ) {
+ Error( "The event-driven router requires routing functions with a single (port,vc) output" );
+ }
+
+ cur_buf->SetOutput( vc, out_port, out_vc );
+ _active[input][vc] = true;
+ } else {
+ if ( f->head ) {
+ cout << *f;
+ Error( "Received head flit at non-idle VC." );
+ }
+ }
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Received flit at " << FullName() << ". Output port = "
+ << cur_buf->GetOutputPort( vc ) << ", output VC = "
+ << cur_buf->GetOutputVC( vc ) << endl
+ << *f;
+ }
+
+ // In cut-through mode, only head flits generate arrivals,
+ // otherwise all flits generate
+
+ if ( ( !_vct ) || ( _vct && f->head ) ) {
+ // Add the arrival event to a delay pipeline to
+ // account for routing/decoding time
+
+ aevt = new tArrivalEvent;
+
+ aevt->input = input;
+ aevt->output = cur_buf->GetOutputPort( vc );
+ aevt->src_vc = f->vc;
+ aevt->dst_vc = cur_buf->GetOutputVC( vc );
+ aevt->head = f->head;
+ aevt->tail = f->tail;
+
+ //if ( f->head && f->tail ) {
+ // Error( "Head/tail packets not supported." );
+ //}
+
+ aevt->watch = f->watch;
+ aevt->id = f->id;
+
+ _arrival_pipe->Write( aevt, input );
+
+ if ( aevt->watch ) {
+ cout << "Injected arrival event at " << FullName()
+ << " for flit " << aevt->id << endl;
+ }
+ }
+ }
+ }
+}
+
+void EventRouter::_ArrivalRequests( int input )
+{
+ tArrivalEvent *aevt;
+
+ aevt = _arrival_pipe->Read( input );
+ if ( aevt ) {
+ _arrival_queue[input].push( aevt );
+ }
+
+ if ( !_arrival_queue[input].empty( ) ) {
+ aevt = _arrival_queue[input].front( );
+ _arrival_arbiter[aevt->output]->AddRequest( input );
+ }
+}
+
+void EventRouter::_SendTransport( int input, int output, tArrivalEvent *aevt )
+{
+ // Try to send a transport event
+
+ tTransportEvent *tevt;
+
+ int credits;
+ int pres;
+
+ credits = _output_state[output]->GetCredits( aevt->dst_vc );
+
+ if ( credits > 0 ) {
+ // Take a credit and queue a transport event
+ credits--;
+ _output_state[output]->SetCredits( aevt->dst_vc, credits );
+
+ tevt = new tTransportEvent;
+ tevt->src_vc = aevt->src_vc;
+ tevt->dst_vc = aevt->dst_vc;
+ tevt->input = input;
+ tevt->watch = aevt->watch;
+ tevt->id = aevt->id;
+
+ _transport_queue[output].push( tevt );
+
+ if ( tevt->watch ) {
+ cout << "Injecting transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+ } else {
+ if ( aevt->watch ) {
+ cout << "No credits available at " << FullName()
+ << " for flit " << aevt->id << " storing presence." << endl;
+ }
+
+ // No credits available, just store presence
+ pres = _output_state[output]->GetPresence( aevt->dst_vc );
+ _output_state[output]->SetPresence( aevt->dst_vc, pres + 1 );
+ }
+}
+
+void EventRouter::_ArrivalArb( int output )
+{
+ tArrivalEvent *aevt;
+ tTransportEvent *tevt;
+ Credit *c;
+
+ EventNextVCState::tWaiting *w;
+
+ int input;
+ int credits;
+ int pres;
+
+ // Incoming credits can produce or enable
+ // transport events --- process them first
+
+ if ( !_out_cred_buffer[output].empty( ) ) {
+ c = _out_cred_buffer[output].front( );
+ _out_cred_buffer[output].pop( );
+
+ assert( c->vc.size() == 1 );
+ int vc = *c->vc.begin();
+
+ EventNextVCState::eNextVCState state =
+ _output_state[output]->GetState( vc );
+
+ credits = _output_state[output]->GetCredits( vc );
+ pres = _output_state[output]->GetPresence( vc );
+
+ if ( _vct ) {
+ // In cut-through mode, only head credits indicate a change in
+ // channel state.
+
+ if ( c->head ) {
+ credits++;
+ _output_state[output]->SetCredits( vc, credits );
+ _ProcessWaiting( output, vc );
+ }
+ } else {
+ credits++;
+ _output_state[output]->SetCredits( vc, credits );
+
+ if ( c->tail ) { // tail flit -- recycle VC
+ if ( state != EventNextVCState::busy ) {
+ Error( "Received tail credit at non-busy output VC" );
+ }
+
+ _ProcessWaiting( output, vc );
+ } else if ( ( state == EventNextVCState::busy ) && ( pres > 0 ) ) {
+ // Flit is present => generate transport event
+
+ tevt = new tTransportEvent;
+ tevt->input = _output_state[output]->GetInput( vc );
+ tevt->src_vc = _output_state[output]->GetInputVC( vc );
+ tevt->dst_vc = vc;
+ tevt->watch = false;
+ tevt->id = -1;
+
+ _transport_queue[output].push( tevt );
+
+ pres--;
+ credits--;
+ _output_state[output]->SetPresence( vc, pres );
+ _output_state[output]->SetCredits( vc, credits );
+ }
+ }
+
+ c->Free();
+ }
+
+ // Now process arrival events
+
+ _arrival_arbiter[output]->Arbitrate( );
+ input = _arrival_arbiter[output]->Match( );
+
+ if ( input != -1 ) {
+ // Winning arrival event gets access to output
+
+ aevt = _arrival_queue[input].front( );
+ _arrival_queue[input].pop( );
+
+ if ( aevt->watch ) {
+ cout << "Processing arrival event at " << FullName()
+ << " for flit " << aevt->id << endl;
+ }
+
+ EventNextVCState::eNextVCState state =
+ _output_state[output]->GetState( aevt->dst_vc );
+
+ if ( aevt->head ) { // Head flits
+ if ( state == EventNextVCState::idle ) {
+ // Allocate the output VC and queue a transport event
+ _output_state[output]->SetState( aevt->dst_vc, EventNextVCState::busy );
+ _output_state[output]->SetInput( aevt->dst_vc, input );
+ _output_state[output]->SetInputVC( aevt->dst_vc, aevt->src_vc );
+
+ _SendTransport( input, output, aevt );
+ } else {
+ // VC busy => queue a waiting event
+
+ w = new EventNextVCState::tWaiting;
+
+ w->input = input;
+ w->vc = aevt->src_vc;
+ w->id = aevt->id;
+ w->watch = aevt->watch;
+ w->pres = 1;
+
+ _output_state[output]->PushWaiting( aevt->dst_vc, w );
+ }
+ } else {
+ if ( _vct ) {
+ Error( "Received arrival event for non-head flit in cut-through mode" );
+ }
+
+ if ( state != EventNextVCState::busy ) {
+ cout << "flit id = " << aevt->id << endl;
+ Error( "Received a body flit at a non-busy output VC" );
+ }
+
+ if ( ( !_output_state[output]->IsInputWaiting( aevt->dst_vc, input, aevt->src_vc ) ) &&
+ ( input == _output_state[output]->GetInput( aevt->dst_vc ) ) &&
+ ( aevt->src_vc == _output_state[output]->GetInputVC( aevt->dst_vc ) ) ) {
+ // Body flit part of the current active VC => queue transport event
+ // (the weird IsInputWaiting call handles a body flit waiting in addition
+ // to a head flit)
+
+ _SendTransport( input, output, aevt );
+ } else {
+
+ // VC busy with a differnet transaction => update waiting event
+ _output_state[output]->IncrWaiting( aevt->dst_vc, input, aevt->src_vc );
+ }
+ }
+
+ delete aevt;
+ }
+}
+
+void EventRouter::_TransportRequests( int output )
+{
+ tTransportEvent *tevt;
+
+ if ( !_transport_queue[output].empty( ) ) {
+ tevt = _transport_queue[output].front( );
+ _transport_arbiter[tevt->input]->AddRequest( output );
+ }
+}
+
+void EventRouter::_TransportArb( int input )
+{
+ tTransportEvent *tevt;
+
+ int output;
+ Buffer *cur_buf;
+ Flit *f;
+ Credit *c;
+
+ if ( _transport_free[input] ) {
+ _transport_arbiter[input]->Arbitrate( );
+ output = _transport_arbiter[input]->Match( );
+ } else {
+ output = _transport_match[input];
+ }
+
+ if ( output != -1 ) {
+ // This completes the match from input to output =>
+ // one flit can be transferred
+
+ tevt = _transport_queue[output].front( );
+
+ if ( tevt->watch ) {
+ cout << "Processing transport event at " << FullName()
+ << " for flit " << tevt->id << endl;
+ }
+
+ cur_buf = _buf[input];
+ int vc = tevt->src_vc;
+
+ // Some sanity checking first
+
+ if ( !_active[input][vc] ) {
+ Error( "Non-active VC received grant." );
+ }
+
+ if ( cur_buf->Empty( vc ) ) {
+ return; //Error( "Empty VC received grant." );
+ }
+
+ if ( tevt->dst_vc != cur_buf->GetOutputVC( vc ) ) {
+ Error( "Transport event's VC does not match input's destination VC." );
+ }
+
+ f = cur_buf->RemoveFlit( vc );
+
+ if ( _vct ) {
+ if ( f->tail ) {
+ _transport_free[input] = true;
+ _transport_match[input] = -1;
+
+ _transport_queue[output].pop( );
+ delete tevt;
+
+ _active[input][vc] = false;
+ } else {
+ _transport_free[input] = false;
+ _transport_match[input] = output;
+ }
+ } else {
+ _transport_free[input] = true;
+ _transport_match[input] = -1;
+
+ _transport_queue[output].pop( );
+ delete tevt;
+
+ if ( f->tail ) {
+ _active[input][vc] = false;
+ }
+ }
+
+ c = Credit::New( );
+ c->vc.insert(f->vc);
+ c->head = f->head;
+ c->tail = f->tail;
+ c->id = f->id;
+ _credit_pipe->Write( c, input );
+
+ if ( f->watch && c->tail ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << FullName() << " sending tail credit back for flit " << f->id << endl;
+ }
+
+ // Update and forward the flit to the crossbar
+
+ f->hops++;
+ f->vc = cur_buf->GetOutputVC( vc );
+ _crossbar_pipe->Write( f, output );
+
+ if ( f->watch ) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Forwarding flit through crossbar at " << FullName() << ":" << endl
+ << *f;
+ }
+ }
+}
+
+void EventRouter::_OutputQueuing( )
+{
+ Flit *f;
+ Credit *c;
+
+ for ( int output = 0; output < _outputs; ++output ) {
+ f = _crossbar_pipe->Read( output );
+
+ if ( f ) {
+ _output_buffer[output].push( f );
+ }
+ }
+
+ for ( int input = 0; input < _inputs; ++input ) {
+ c = _credit_pipe->Read( input );
+
+ if ( c ) {
+ _in_cred_buffer[input].push( c );
+ }
+ }
+}
+
+void EventRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_output_buffer[output].empty( ) ) {
+ Flit *f = _output_buffer[output].front( );
+ _output_buffer[output].pop( );
+ _output_channels[output]->Send( f );
+ }
+ }
+}
+
+void EventRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_in_cred_buffer[input].empty( ) ) {
+ Credit *c = _in_cred_buffer[input].front( );
+ _in_cred_buffer[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+void EventRouter::Display( ostream & os ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ _buf[input]->Display( os );
+ }
+}
+
+EventNextVCState::EventNextVCState( const Configuration& config,
+ Module *parent, const string& name ) :
+ Module( parent, name )
+{
+ _buf_size = config.GetInt( "vc_buf_size" );
+ _vcs = config.GetInt( "num_vcs" );
+
+ _credits.resize(_vcs, _buf_size);
+ _presence.resize(_vcs, 0);
+ _input.resize(_vcs);
+ _inputVC.resize(_vcs);
+ _waiting.resize(_vcs);
+ _state.resize(_vcs, idle);
+}
+
+EventNextVCState::eNextVCState EventNextVCState::GetState( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _state[vc];
+}
+
+int EventNextVCState::GetPresence( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _presence[vc];
+}
+
+int EventNextVCState::GetCredits( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _credits[vc];
+}
+
+int EventNextVCState::GetInput( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _input[vc];
+}
+
+int EventNextVCState::GetInputVC( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return _inputVC[vc];
+}
+
+bool EventNextVCState::IsWaiting( int vc ) const
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ return !_waiting[vc].empty( );
+}
+
+void EventNextVCState::PushWaiting( int vc, tWaiting *w )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ if ( w->watch ) {
+ cout << FullName() << " pushing flit " << w->id
+ << " onto a waiting queue of length " << _waiting[vc].size( ) << endl;
+ }
+
+ _waiting[vc].push_back( w );
+}
+
+void EventNextVCState::IncrWaiting( int vc, int w_input, int w_vc )
+{
+ list<tWaiting *>::iterator match;
+
+ // search for match
+ for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) {
+ if ( ( (*match)->input == w_input ) &&
+ ( (*match)->vc == w_vc ) ) break;
+ }
+
+ if ( match != _waiting[vc].end( ) ) {
+ (*match)->pres++;
+ } else {
+ Error( "Did not find match in IncrWaiting" );
+ }
+}
+
+bool EventNextVCState::IsInputWaiting( int vc, int w_input, int w_vc ) const
+{
+ list<tWaiting *>::const_iterator match;
+ bool r;
+
+ // search for match
+ for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) {
+ if ( ( (*match)->input == w_input ) &&
+ ( (*match)->vc == w_vc ) ) break;
+ }
+
+ if ( match != _waiting[vc].end( ) ) {
+ r = true;
+ } else {
+ r = false;
+ }
+
+ return r;
+}
+
+EventNextVCState::tWaiting *EventNextVCState::PopWaiting( int vc )
+{
+ tWaiting *w;
+
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+
+ w = _waiting[vc].front( );
+ _waiting[vc].pop_front( );
+
+ return w;
+}
+
+void EventNextVCState::SetState( int vc, eNextVCState state )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _state[vc] = state;
+}
+
+void EventNextVCState::SetCredits( int vc, int value )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _credits[vc] = value;
+}
+
+void EventNextVCState::SetPresence( int vc, int value )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _presence[vc] = value;
+}
+
+void EventNextVCState::SetInput( int vc, int input )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _input[vc] = input;
+}
+
+void EventNextVCState::SetInputVC( int vc, int in_vc )
+{
+ assert( ( vc >= 0 ) && ( vc < _vcs ) );
+ _inputVC[vc] = in_vc;
+}
diff --git a/src/intersim2/routers/event_router.hpp b/src/intersim2/routers/event_router.hpp
new file mode 100644
index 0000000..2f2f170
--- /dev/null
+++ b/src/intersim2/routers/event_router.hpp
@@ -0,0 +1,187 @@
+// $Id: event_router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _EVENT_ROUTER_HPP_
+#define _EVENT_ROUTER_HPP_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "module.hpp"
+#include "router.hpp"
+#include "buffer.hpp"
+#include "vc.hpp"
+#include "prio_arb.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "pipefifo.hpp"
+
+class EventNextVCState : public Module {
+public:
+ enum eNextVCState { idle, busy, tail_pending };
+
+ struct tWaiting {
+ int input;
+ int vc;
+ int id;
+ int pres;
+ bool watch;
+ };
+
+private:
+ int _buf_size;
+ int _vcs;
+
+ vector<int> _credits;
+ vector<int> _presence;
+ vector<int> _input;
+ vector<int> _inputVC;
+
+ vector<list<tWaiting *> > _waiting;
+
+ vector<eNextVCState> _state;
+
+public:
+
+ EventNextVCState( const Configuration& config,
+ Module *parent, const string& name );
+
+ eNextVCState GetState( int vc ) const;
+ int GetPresence( int vc ) const;
+ int GetCredits( int vc ) const;
+ int GetInput( int vc ) const;
+ int GetInputVC( int vc ) const;
+
+ bool IsWaiting( int vc ) const;
+ bool IsInputWaiting( int vc, int w_input, int w_vc ) const;
+
+ void PushWaiting( int vc, tWaiting *w );
+ void IncrWaiting( int vc, int w_input, int w_vc );
+ tWaiting *PopWaiting( int vc );
+
+ void SetState( int vc, eNextVCState state );
+ void SetCredits( int vc, int value );
+ void SetPresence( int vc, int value );
+ void SetInput( int vc, int input );
+ void SetInputVC( int vc, int in_vc );
+};
+
+class EventRouter : public Router {
+ int _vcs;
+
+ int _vct;
+
+ vector<Buffer *> _buf;
+ vector<vector<bool> > _active;
+
+ tRoutingFunction _rf;
+
+ vector<EventNextVCState *> _output_state;
+
+ PipelineFIFO<Flit> *_crossbar_pipe;
+ PipelineFIFO<Credit> *_credit_pipe;
+
+ vector<queue<Flit *> > _input_buffer;
+ vector<queue<Flit *> > _output_buffer;
+
+ vector<queue<Credit *> > _in_cred_buffer;
+ vector<queue<Credit *> > _out_cred_buffer;
+
+ struct tArrivalEvent {
+ int input;
+ int output;
+ int src_vc;
+ int dst_vc;
+ bool head;
+ bool tail;
+
+ int id; // debug
+ bool watch; // debug
+ };
+
+ PipelineFIFO<tArrivalEvent> *_arrival_pipe;
+ vector<queue<tArrivalEvent *> > _arrival_queue;
+ vector<PriorityArbiter*> _arrival_arbiter;
+
+ struct tTransportEvent {
+ int input;
+ int src_vc;
+ int dst_vc;
+
+ int id; // debug
+ bool watch; // debug
+ };
+
+ vector<queue<tTransportEvent *> > _transport_queue;
+ vector<PriorityArbiter*> _transport_arbiter;
+
+ vector<bool> _transport_free;
+ vector<int> _transport_match;
+
+ void _ReceiveFlits( );
+ void _ReceiveCredits( );
+
+ void _IncomingFlits( );
+ void _ArrivalRequests( int input );
+ void _ArrivalArb( int output );
+ void _SendTransport( int input, int output, tArrivalEvent *aevt );
+ void _ProcessWaiting( int output, int out_vc );
+ void _TransportRequests( int output );
+ void _TransportArb( int input );
+ void _OutputQueuing( );
+
+ void _SendFlits( );
+ void _SendCredits( );
+
+ virtual void _InternalStep( );
+
+public:
+ EventRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+ virtual ~EventRouter( );
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ virtual int GetUsedCredit(int o) const {return 0;}
+ virtual int GetBufferOccupancy(int i) const {return 0;}
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const {return 0;}
+ virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;}
+#endif
+
+ virtual vector<int> UsedCredits() const { return vector<int>(); }
+ virtual vector<int> FreeCredits() const { return vector<int>(); }
+ virtual vector<int> MaxCredits() const { return vector<int>(); }
+
+ void Display( ostream & os = cout ) const;
+};
+
+#endif
diff --git a/src/intersim2/routers/iq_router.cpp b/src/intersim2/routers/iq_router.cpp
new file mode 100644
index 0000000..d97f485
--- /dev/null
+++ b/src/intersim2/routers/iq_router.cpp
@@ -0,0 +1,2385 @@
+// $Id: iq_router.cpp 5263 2012-09-20 23:40:33Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "iq_router.hpp"
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+#include <cassert>
+#include <limits>
+
+#include "globals.hpp"
+#include "random_utils.hpp"
+#include "vc.hpp"
+#include "routefunc.hpp"
+#include "outputset.hpp"
+#include "buffer.hpp"
+#include "buffer_state.hpp"
+#include "roundrobin_arb.hpp"
+#include "allocator.hpp"
+#include "switch_monitor.hpp"
+#include "buffer_monitor.hpp"
+
+IQRouter::IQRouter( Configuration const & config, Module *parent,
+ string const & name, int id, int inputs, int outputs )
+: Router( config, parent, name, id, inputs, outputs ), _active(false)
+{
+ _vcs = config.GetInt( "num_vcs" );
+
+ _vc_busy_when_full = (config.GetInt("vc_busy_when_full") > 0);
+ _vc_prioritize_empty = (config.GetInt("vc_prioritize_empty") > 0);
+ _vc_shuffle_requests = (config.GetInt("vc_shuffle_requests") > 0);
+
+ _speculative = (config.GetInt("speculative") > 0);
+ _spec_check_elig = (config.GetInt("spec_check_elig") > 0);
+ _spec_check_cred = (config.GetInt("spec_check_cred") > 0);
+ _spec_mask_by_reqs = (config.GetInt("spec_mask_by_reqs") > 0);
+
+ _routing_delay = config.GetInt( "routing_delay" );
+ _vc_alloc_delay = config.GetInt( "vc_alloc_delay" );
+ if(!_vc_alloc_delay) {
+ Error("VC allocator cannot have zero delay.");
+ }
+ _sw_alloc_delay = config.GetInt( "sw_alloc_delay" );
+ if(!_sw_alloc_delay) {
+ Error("Switch allocator cannot have zero delay.");
+ }
+
+ // Routing
+ string const rf = config.GetStr("routing_function") + "_" + config.GetStr("topology");
+ map<string, tRoutingFunction>::const_iterator rf_iter = gRoutingFunctionMap.find(rf);
+ if(rf_iter == gRoutingFunctionMap.end()) {
+ Error("Invalid routing function: " + rf);
+ }
+ _rf = rf_iter->second;
+
+ // Alloc VC's
+ _buf.resize(_inputs);
+ for ( int i = 0; i < _inputs; ++i ) {
+ ostringstream module_name;
+ module_name << "buf_" << i;
+ _buf[i] = new Buffer(config, _outputs, this, module_name.str( ) );
+ module_name.str("");
+ }
+
+ // Alloc next VCs' buffer state
+ _next_buf.resize(_outputs);
+ for (int j = 0; j < _outputs; ++j) {
+ ostringstream module_name;
+ module_name << "next_vc_o" << j;
+ _next_buf[j] = new BufferState( config, this, module_name.str( ) );
+ module_name.str("");
+ }
+
+ // Alloc allocators
+ string vc_alloc_type = config.GetStr( "vc_allocator" );
+ if(vc_alloc_type == "piggyback") {
+ if(!_speculative) {
+ Error("Piggyback VC allocation requires speculative switch allocation to be enabled.");
+ }
+ _vc_allocator = NULL;
+ _vc_rr_offset.resize(_outputs*_classes, -1);
+ } else {
+ _vc_allocator = Allocator::NewAllocator( this, "vc_allocator",
+ vc_alloc_type,
+ _vcs*_inputs,
+ _vcs*_outputs );
+
+ if ( !_vc_allocator ) {
+ Error("Unknown vc_allocator type: " + vc_alloc_type);
+ }
+ }
+
+ string sw_alloc_type = config.GetStr( "sw_allocator" );
+ _sw_allocator = Allocator::NewAllocator( this, "sw_allocator",
+ sw_alloc_type,
+ _inputs*_input_speedup,
+ _outputs*_output_speedup );
+
+ if ( !_sw_allocator ) {
+ Error("Unknown sw_allocator type: " + sw_alloc_type);
+ }
+
+ string spec_sw_alloc_type = config.GetStr( "spec_sw_allocator" );
+ if ( _speculative && ( spec_sw_alloc_type != "prio" ) ) {
+ _spec_sw_allocator = Allocator::NewAllocator( this, "spec_sw_allocator",
+ spec_sw_alloc_type,
+ _inputs*_input_speedup,
+ _outputs*_output_speedup );
+ if ( !_spec_sw_allocator ) {
+ Error("Unknown spec_sw_allocator type: " + spec_sw_alloc_type);
+ }
+ } else {
+ _spec_sw_allocator = NULL;
+ }
+
+ _sw_rr_offset.resize(_inputs*_input_speedup);
+ for(int i = 0; i < _inputs*_input_speedup; ++i)
+ _sw_rr_offset[i] = i % _input_speedup;
+
+ _noq = config.GetInt("noq") > 0;
+ if(_noq) {
+ if(_routing_delay) {
+ Error("NOQ requires lookahead routing to be enabled.");
+ }
+ if(_vcs < _outputs) {
+ Error("NOQ requires at least as many VCs as router outputs.");
+ }
+ }
+ _noq_next_output_port.resize(_inputs, vector<int>(_vcs, -1));
+ _noq_next_vc_start.resize(_inputs, vector<int>(_vcs, -1));
+ _noq_next_vc_end.resize(_inputs, vector<int>(_vcs, -1));
+
+ // Output queues
+ _output_buffer_size = config.GetInt("output_buffer_size");
+ _output_buffer.resize(_outputs);
+ _credit_buffer.resize(_inputs);
+
+ // Switch configuration (when held for multiple cycles)
+ _hold_switch_for_packet = (config.GetInt("hold_switch_for_packet") > 0);
+ _switch_hold_in.resize(_inputs*_input_speedup, -1);
+ _switch_hold_out.resize(_outputs*_output_speedup, -1);
+ _switch_hold_vc.resize(_inputs*_input_speedup, -1);
+
+ _bufferMonitor = new BufferMonitor(inputs, _classes);
+ _switchMonitor = new SwitchMonitor(inputs, outputs, _classes);
+
+#ifdef TRACK_FLOWS
+ for(int c = 0; c < _classes; ++c) {
+ _stored_flits[c].resize(_inputs, 0);
+ _active_packets[c].resize(_inputs, 0);
+ }
+ _outstanding_classes.resize(_outputs, vector<queue<int> >(_vcs));
+#endif
+}
+
+IQRouter::~IQRouter( )
+{
+
+ if(gPrintActivity) {
+ cout << Name() << ".bufferMonitor:" << endl ;
+ cout << *_bufferMonitor << endl ;
+
+ cout << Name() << ".switchMonitor:" << endl ;
+ cout << "Inputs=" << _inputs ;
+ cout << "Outputs=" << _outputs ;
+ cout << *_switchMonitor << endl ;
+ }
+
+ for(int i = 0; i < _inputs; ++i)
+ delete _buf[i];
+
+ for(int j = 0; j < _outputs; ++j)
+ delete _next_buf[j];
+
+ delete _vc_allocator;
+ delete _sw_allocator;
+ if(_spec_sw_allocator)
+ delete _spec_sw_allocator;
+
+ delete _bufferMonitor;
+ delete _switchMonitor;
+}
+
+void IQRouter::AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel)
+{
+ int alloc_delay = _speculative ? max(_vc_alloc_delay, _sw_alloc_delay) : (_vc_alloc_delay + _sw_alloc_delay);
+ int min_latency = 1 + _crossbar_delay + channel->GetLatency() + _routing_delay + alloc_delay + backchannel->GetLatency() + _credit_delay;
+ _next_buf[_output_channels.size()]->SetMinLatency(min_latency);
+ Router::AddOutputChannel(channel, backchannel);
+}
+
+void IQRouter::ReadInputs( )
+{
+ bool have_flits = _ReceiveFlits( );
+ bool have_credits = _ReceiveCredits( );
+ _active = _active || have_flits || have_credits;
+}
+
+void IQRouter::_InternalStep( )
+{
+ if(!_active) {
+ return;
+ }
+
+ _InputQueuing( );
+ bool activity = !_proc_credits.empty();
+
+ if(!_route_vcs.empty())
+ _RouteEvaluate( );
+ if(_vc_allocator) {
+ _vc_allocator->Clear();
+ if(!_vc_alloc_vcs.empty())
+ _VCAllocEvaluate( );
+ }
+ if(_hold_switch_for_packet) {
+ if(!_sw_hold_vcs.empty())
+ _SWHoldEvaluate( );
+ }
+ _sw_allocator->Clear();
+ if(_spec_sw_allocator)
+ _spec_sw_allocator->Clear();
+ if(!_sw_alloc_vcs.empty())
+ _SWAllocEvaluate( );
+ if(!_crossbar_flits.empty())
+ _SwitchEvaluate( );
+
+ if(!_route_vcs.empty()) {
+ _RouteUpdate( );
+ activity = activity || !_route_vcs.empty();
+ }
+ if(!_vc_alloc_vcs.empty()) {
+ _VCAllocUpdate( );
+ activity = activity || !_vc_alloc_vcs.empty();
+ }
+ if(_hold_switch_for_packet) {
+ if(!_sw_hold_vcs.empty()) {
+ _SWHoldUpdate( );
+ activity = activity || !_sw_hold_vcs.empty();
+ }
+ }
+ if(!_sw_alloc_vcs.empty()) {
+ _SWAllocUpdate( );
+ activity = activity || !_sw_alloc_vcs.empty();
+ }
+ if(!_crossbar_flits.empty()) {
+ _SwitchUpdate( );
+ activity = activity || !_crossbar_flits.empty();
+ }
+
+ _active = activity;
+
+ _OutputQueuing( );
+
+ _bufferMonitor->cycle( );
+ _switchMonitor->cycle( );
+}
+
+void IQRouter::WriteOutputs( )
+{
+ _SendFlits( );
+ _SendCredits( );
+}
+
+
+//------------------------------------------------------------------------------
+// read inputs
+//------------------------------------------------------------------------------
+
+bool IQRouter::_ReceiveFlits( )
+{
+ bool activity = false;
+ for(int input = 0; input < _inputs; ++input) {
+ Flit * const f = _input_channels[input]->Receive();
+ if(f) {
+
+#ifdef TRACK_FLOWS
+ ++_received_flits[f->cl][input];
+#endif
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Received flit " << f->id
+ << " from channel at input " << input
+ << "." << endl;
+ }
+ _in_queue_flits.insert(make_pair(input, f));
+ activity = true;
+ }
+ }
+ return activity;
+}
+
+bool IQRouter::_ReceiveCredits( )
+{
+ bool activity = false;
+ for(int output = 0; output < _outputs; ++output) {
+ Credit * const c = _output_credits[output]->Receive();
+ if(c) {
+ _proc_credits.push_back(make_pair(GetSimTime() + _credit_delay,
+ make_pair(c, output)));
+ activity = true;
+ }
+ }
+ return activity;
+}
+
+
+//------------------------------------------------------------------------------
+// input queuing
+//------------------------------------------------------------------------------
+
+void IQRouter::_InputQueuing( )
+{
+ for(map<int, Flit *>::const_iterator iter = _in_queue_flits.begin();
+ iter != _in_queue_flits.end();
+ ++iter) {
+
+ int const input = iter->first;
+ assert((input >= 0) && (input < _inputs));
+
+ Flit * const f = iter->second;
+ assert(f);
+
+ int const vc = f->vc;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Adding flit " << f->id
+ << " to VC " << vc
+ << " at input " << input
+ << " (state: " << VC::VCSTATE[cur_buf->GetState(vc)];
+ if(cur_buf->Empty(vc)) {
+ *gWatchOut << ", empty";
+ } else {
+ assert(cur_buf->FrontFlit(vc));
+ *gWatchOut << ", front: " << cur_buf->FrontFlit(vc)->id;
+ }
+ *gWatchOut << ")." << endl;
+ }
+ cur_buf->AddFlit(vc, f);
+
+#ifdef TRACK_FLOWS
+ ++_stored_flits[f->cl][input];
+ if(f->head) ++_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->write(input, f) ;
+
+ if(cur_buf->GetState(vc) == VC::idle) {
+ assert(cur_buf->FrontFlit(vc) == f);
+ assert(cur_buf->GetOccupancy(vc) == 1);
+ assert(f->head);
+ assert(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] != vc);
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, make_pair(input, vc)));
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &f->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, f);
+ }
+ }
+ } else if((cur_buf->GetState(vc) == VC::active) &&
+ (cur_buf->FrontFlit(vc) == f)) {
+ if(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] == vc) {
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ } else {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc),
+ -1)));
+ }
+ }
+ }
+ _in_queue_flits.clear();
+
+ while(!_proc_credits.empty()) {
+
+ pair<int, pair<Credit *, int> > const & item = _proc_credits.front();
+
+ int const time = item.first;
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ Credit * const c = item.second.first;
+ assert(c);
+
+ int const output = item.second.second;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+#ifdef TRACK_FLOWS
+ for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) {
+ int const vc = *iter;
+ assert(!_outstanding_classes[output][vc].empty());
+ int cl = _outstanding_classes[output][vc].front();
+ _outstanding_classes[output][vc].pop();
+ assert(_outstanding_credits[cl][output] > 0);
+ --_outstanding_credits[cl][output];
+ }
+#endif
+
+ dest_buf->ProcessCredit(c);
+ c->Free();
+ _proc_credits.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// routing
+//------------------------------------------------------------------------------
+
+void IQRouter::_RouteEvaluate( )
+{
+ assert(_routing_delay);
+
+ for(deque<pair<int, pair<int, int> > >::iterator iter = _route_vcs.begin();
+ iter != _route_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _routing_delay - 1;
+
+ int const input = iter->second.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::routing);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning routing for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+ }
+}
+
+void IQRouter::_RouteUpdate( )
+{
+ assert(_routing_delay);
+
+ while(!_route_vcs.empty()) {
+
+ pair<int, pair<int, int> > const & item = _route_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::routing);
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed routing for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ cur_buf->Route(vc, _rf, this, f, input);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1)));
+ }
+ // NOTE: No need to handle NOQ here, as it requires lookahead routing!
+ _route_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// VC allocation
+//------------------------------------------------------------------------------
+
+void IQRouter::_VCAllocEvaluate( )
+{
+ assert(_vc_allocator);
+
+ bool watched = false;
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning VC allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ int const out_priority = cur_buf->GetPriority(vc);
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ bool elig = false;
+ bool cred = false;
+ bool reserved = false;
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+
+ int const out_port = iset->output_port;
+ assert((out_port >= 0) && (out_port < _outputs));
+
+ BufferState const * const dest_buf = _next_buf[out_port];
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+
+ int in_priority = iset->pri;
+ if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) {
+ assert(in_priority >= 0);
+ in_priority += numeric_limits<int>::min();
+ }
+
+ // On the input input side, a VC might request several output VCs.
+ // These VCs can be prioritized by the routing function, and this is
+ // reflected in "in_priority". On the output side, if multiple VCs are
+ // requesting the same output VC, the priority of VCs is based on the
+ // actual packet priorities, which is reflected in "out_priority".
+
+ if(!dest_buf->IsAvailableFor(out_vc)) {
+ if(f->watch) {
+ int const use_input_and_vc = dest_buf->UsedBy(out_vc);
+ int const use_input = use_input_and_vc / _vcs;
+ int const use_vc = use_input_and_vc % _vcs;
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << out_vc
+ << " at output " << out_port
+ << " is in use by VC " << use_vc
+ << " at input " << use_input;
+ Flit * cf = _buf[use_input]->FrontFlit(use_vc);
+ if(cf) {
+ *gWatchOut << " (front flit: " << cf->id << ")";
+ } else {
+ *gWatchOut << " (empty)";
+ }
+ *gWatchOut << "." << endl;
+ }
+ } else {
+ elig = true;
+ if(_vc_busy_when_full && dest_buf->IsFullFor(out_vc)) {
+ if(f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << out_vc
+ << " at output " << out_port
+ << " is full." << endl;
+ reserved |= !dest_buf->IsFull();
+ } else {
+ cred = true;
+ if(f->watch){
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Requesting VC " << out_vc
+ << " at output " << out_port
+ << " (in_pri: " << in_priority
+ << ", out_pri: " << out_priority
+ << ")." << endl;
+ watched = true;
+ }
+ int const input_and_vc
+ = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ _vc_allocator->AddRequest(input_and_vc, out_port*_vcs + out_vc,
+ 0, in_priority, out_priority);
+ }
+ }
+ }
+ }
+ if(!elig) {
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_vc_busy_when_full && !cred) {
+ iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL;
+ }
+ }
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | ";
+ _vc_allocator->PrintRequests( gWatchOut );
+ }
+
+ _vc_allocator->Allocate();
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | ";
+ _vc_allocator->PrintGrants( gWatchOut );
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _vc_alloc_delay - 1;
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ if(iter->second.second < -1) {
+ continue;
+ }
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ int const input_and_vc
+ = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc);
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning VC " << match_vc
+ << " at output " << match_output
+ << " to VC " << vc
+ << " at input " << input
+ << "." << endl;
+ }
+
+ iter->second.second = output_and_vc;
+
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "VC allocation failed for VC " << vc
+ << " at input " << input
+ << "." << endl;
+ }
+
+ iter->second.second = STALL_BUFFER_CONFLICT;
+
+ }
+ }
+
+ if(_vc_alloc_delay <= 1) {
+ return;
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin();
+ iter != _vc_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ assert(time >= 0);
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ assert(iter->second.second != -1);
+
+ int const output_and_vc = iter->second.second;
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ BufferState const * const dest_buf = _next_buf[match_output];
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(!dest_buf->IsAvailableFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding previously generated grant for VC " << vc
+ << " at input " << input
+ << ": VC " << match_vc
+ << " at output " << match_output
+ << " is no longer available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_vc_busy_when_full && dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding previously generated grant for VC " << vc
+ << " at input " << input
+ << ": VC " << match_vc
+ << " at output " << match_output
+ << " has become full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+ }
+ }
+}
+
+void IQRouter::_VCAllocUpdate( )
+{
+ assert(_vc_allocator);
+
+ while(!_vc_alloc_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _vc_alloc_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(item.second.second != -1);
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::vc_alloc);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed VC allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const output_and_vc = item.second.second;
+
+ if(output_and_vc >= 0) {
+
+ int const match_output = output_and_vc / _vcs;
+ assert((match_output >= 0) && (match_output < _outputs));
+ int const match_vc = output_and_vc % _vcs;
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Acquiring assigned VC " << match_vc
+ << " at output " << match_output
+ << "." << endl;
+ }
+
+ BufferState * const dest_buf = _next_buf[match_output];
+ assert(dest_buf->IsAvailableFor(match_vc));
+
+ dest_buf->TakeBuffer(match_vc, input*_vcs + vc);
+
+ cur_buf->SetOutput(vc, match_output, match_vc);
+ cur_buf->SetState(vc, VC::active);
+ if(!_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " No output VC allocated." << endl;
+ }
+
+#ifdef TRACK_STALLS
+ assert((output_and_vc == STALL_BUFFER_BUSY) ||
+ (output_and_vc == STALL_BUFFER_CONFLICT));
+ if(output_and_vc == STALL_BUFFER_BUSY) {
+ ++_buffer_busy_stalls[f->cl];
+ } else if(output_and_vc == STALL_BUFFER_CONFLICT) {
+ ++_buffer_conflict_stalls[f->cl];
+ }
+#endif
+
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ _vc_alloc_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch holding
+//------------------------------------------------------------------------------
+
+void IQRouter::_SWHoldEvaluate( )
+{
+ assert(_hold_switch_for_packet);
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_hold_vcs.begin();
+ iter != _sw_hold_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime();
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::active);
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning held switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] == vc);
+
+ int const match_port = cur_buf->GetOutputPort(vc);
+ assert((match_port >= 0) && (match_port < _outputs));
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ int const expanded_output = match_port*_output_speedup + input%_output_speedup;
+ assert(_switch_hold_in[expanded_input] == expanded_output);
+
+ BufferState const * const dest_buf = _next_buf[match_port];
+
+ if(dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Unable to reuse held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << match_port
+ << "." << (expanded_output % _output_speedup)
+ << ": No credit available." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Reusing held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << match_port
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ iter->second.second = expanded_output;
+ }
+ }
+}
+
+void IQRouter::_SWHoldUpdate( )
+{
+ assert(_hold_switch_for_packet);
+
+ while(!_sw_hold_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _sw_hold_vcs.front();
+
+ int const time = item.first;
+ if(time < 0) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(item.second.second != -1);
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert(cur_buf->GetState(vc) == VC::active);
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed held switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] == vc);
+
+ int const expanded_output = item.second.second;
+
+ if(expanded_output >= 0 && ( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size))) {
+
+ assert(_switch_hold_in[expanded_input] == expanded_output);
+ assert(_switch_hold_out[expanded_output] == expanded_input);
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Scheduling switch connection from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+
+ cur_buf->RemoveFlit(vc);
+
+#ifdef TRACK_FLOWS
+ --_stored_flits[f->cl][input];
+ if(f->tail) --_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->read(input, f) ;
+
+ f->hops++;
+ f->vc = match_vc;
+
+ if(!_routing_delay && f->head) {
+ const FlitChannel * channel = _output_channels[output];
+ const Router * router = channel->GetSink();
+ if(router) {
+ if(_noq) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ int next_output_port = _noq_next_output_port[input][vc];
+ assert(next_output_port >= 0);
+ _noq_next_output_port[input][vc] = -1;
+ int next_vc_start = _noq_next_vc_start[input][vc];
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ _noq_next_vc_start[input][vc] = -1;
+ int next_vc_end = _noq_next_vc_end[input][vc];
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ _noq_next_vc_end[input][vc] = -1;
+ f->la_route_set.Clear();
+ f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end);
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << "." << endl;
+ }
+ int in_channel = channel->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[f->cl][output];
+ _outstanding_classes[output][f->vc].push(f->cl);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output))));
+
+ if(_out_queue_credits.count(input) == 0) {
+ _out_queue_credits.insert(make_pair(input, Credit::New()));
+ }
+ _out_queue_credits.find(input)->second->vc.insert(vc);
+
+ if(cur_buf->Empty(vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << output
+ << "." << (expanded_output % _output_speedup)
+ << ": No more flits." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[expanded_output] = -1;
+ if(f->tail) {
+ cur_buf->SetState(vc, VC::idle);
+ }
+ } else {
+ Flit * const nf = cur_buf->FrontFlit(vc);
+ assert(nf);
+ assert(nf->vc == vc);
+ if(f->tail) {
+ assert(nf->head);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << output
+ << "." << (expanded_output % _output_speedup)
+ << ": End of packet." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[expanded_output] = -1;
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, item.second.first));
+ } else {
+ if(nf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << nf->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &nf->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, nf);
+ }
+ }
+ } else {
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ }
+ } else {
+ //when internal speedup >1.0, the buffer stall stats may not be accruate
+ assert((expanded_output == STALL_BUFFER_FULL) ||
+ (expanded_output == STALL_BUFFER_RESERVED) || !( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size)));
+
+ int const held_expanded_output = _switch_hold_in[expanded_input];
+ assert(held_expanded_output >= 0);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Cancelling held connection from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to " << (held_expanded_output / _output_speedup)
+ << "." << (held_expanded_output % _output_speedup)
+ << ": Flit not sent." << endl;
+ }
+ _switch_hold_vc[expanded_input] = -1;
+ _switch_hold_in[expanded_input] = -1;
+ _switch_hold_out[held_expanded_output] = -1;
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ _sw_hold_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch allocation
+//------------------------------------------------------------------------------
+
+bool IQRouter::_SWAllocAddReq(int input, int vc, int output)
+{
+ assert(input >= 0 && input < _inputs);
+ assert(vc >= 0 && vc < _vcs);
+ assert(output >= 0 && output < _outputs);
+
+ // When input_speedup > 1, the virtual channel buffers are interleaved to
+ // create multiple input ports to the switch. Similarily, the output ports
+ // are interleaved based on their originating input when output_speedup > 1.
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ int const expanded_output = output * _output_speedup + input % _output_speedup;
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if((_switch_hold_in[expanded_input] < 0) &&
+ (_switch_hold_out[expanded_output] < 0)) {
+
+ Allocator * allocator = _sw_allocator;
+ int prio = cur_buf->GetPriority(vc);
+
+ if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+ if(_spec_sw_allocator) {
+ allocator = _spec_sw_allocator;
+ } else {
+ assert(prio >= 0);
+ prio += numeric_limits<int>::min();
+ }
+ }
+
+ Allocator::sRequest req;
+
+ if(allocator->ReadRequest(req, expanded_input, expanded_output)) {
+ if(RoundRobinArbiter::Supersedes(vc, prio, req.label, req.in_pri,
+ _sw_rr_offset[expanded_input], _vcs)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Replacing earlier request from VC " << req.label
+ << " for output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " with priority " << req.in_pri
+ << " (" << ((cur_buf->GetState(vc) == VC::active) ?
+ "non-spec" :
+ "spec")
+ << ", pri: " << prio
+ << ")." << endl;
+ }
+ allocator->RemoveRequest(expanded_input, expanded_output, req.label);
+ allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio);
+ return true;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " was already requested by VC " << req.label
+ << " with priority " << req.in_pri
+ << " (pri: " << prio
+ << ")." << endl;
+ }
+ return false;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Requesting output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " (" << ((cur_buf->GetState(vc) == VC::active) ?
+ "non-spec" :
+ "spec")
+ << ", pri: " << prio
+ << ")." << endl;
+ }
+ allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio);
+ return true;
+ }
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Ignoring output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to switch hold (";
+ if(_switch_hold_in[expanded_input] >= 0) {
+ *gWatchOut << "input: " << input
+ << "." << (expanded_input % _input_speedup);
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << ", ";
+ }
+ }
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << "output: " << output
+ << "." << (expanded_output % _output_speedup);
+ }
+ *gWatchOut << ")." << endl;
+ }
+ return false;
+}
+
+void IQRouter::_SWAllocEvaluate( )
+{
+ bool watched = false;
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ assert(iter->second.second == -1);
+
+ assert(_switch_hold_vc[input * _input_speedup + vc % _input_speedup] != vc);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ if(cur_buf->GetState(vc) == VC::active) {
+
+ int const dest_output = cur_buf->GetOutputPort(vc);
+ assert((dest_output >= 0) && (dest_output < _outputs));
+ int const dest_vc = cur_buf->GetOutputVC(vc);
+ assert((dest_vc >= 0) && (dest_vc < _vcs));
+
+ BufferState const * const dest_buf = _next_buf[dest_output];
+
+ if(dest_buf->IsFullFor(dest_vc) || ( _output_buffer_size!=-1 && _output_buffer[dest_output].size()>=(size_t)(_output_buffer_size))) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " VC " << dest_vc
+ << " at output " << dest_output
+ << " is full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ continue;
+ }
+ bool const requested = _SWAllocAddReq(input, vc, dest_output);
+ watched |= requested && f->watch;
+ continue;
+ }
+ assert(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc));
+ assert(f->head);
+
+ // The following models the speculative VC allocation aspects of the
+ // pipeline. An input VC with a request in for an egress virtual channel
+ // will also speculatively bid for the switch regardless of whether the VC
+ // allocation succeeds.
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+
+ int const dest_output = iset->output_port;
+ assert((dest_output >= 0) && (dest_output < _outputs));
+
+ // for lower levels of speculation, ignore credit availability and always
+ // issue requests for all output ports in route set
+
+ BufferState const * const dest_buf = _next_buf[dest_output];
+
+ bool elig = false;
+ bool cred = false;
+
+ if(_spec_check_elig) {
+
+ // for higher levels of speculation, check if at least one suitable VC
+ // is available at the current output
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int dest_vc = vc_start; dest_vc <= vc_end; ++dest_vc) {
+ assert((dest_vc >= 0) && (dest_vc < _vcs));
+
+ if(dest_buf->IsAvailableFor(dest_vc) && ( _output_buffer_size==-1 || _output_buffer[dest_output].size()<(size_t)(_output_buffer_size))) {
+ elig = true;
+ if(!_spec_check_cred || !dest_buf->IsFullFor(dest_vc)) {
+ cred = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if(_spec_check_elig && !elig) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Output " << dest_output
+ << " has no suitable VCs available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(_spec_check_cred && !cred) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " All suitable VCs at output " << dest_output
+ << " are full." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ } else {
+ bool const requested = _SWAllocAddReq(input, vc, dest_output);
+ watched |= requested && f->watch;
+ }
+ }
+ }
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | ";
+ _sw_allocator->PrintRequests(gWatchOut);
+ if(_spec_sw_allocator) {
+ *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | ";
+ _spec_sw_allocator->PrintRequests(gWatchOut);
+ }
+ }
+
+ _sw_allocator->Allocate();
+ if(_spec_sw_allocator)
+ _spec_sw_allocator->Allocate();
+
+ if(watched) {
+ *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | ";
+ _sw_allocator->PrintGrants(gWatchOut);
+ if(_spec_sw_allocator) {
+ *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | ";
+ _spec_sw_allocator->PrintGrants(gWatchOut);
+ }
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _sw_alloc_delay - 1;
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ if(iter->second.second < -1) {
+ continue;
+ }
+
+ assert(iter->second.second == -1);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+
+ int expanded_output = _sw_allocator->OutputAssigned(expanded_input);
+
+ if(expanded_output >= 0) {
+ assert((expanded_output % _output_speedup) == (input % _output_speedup));
+ int const granted_vc = _sw_allocator->ReadRequest(expanded_input, expanded_output);
+ if(granted_vc == vc) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " to VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << "." << endl;
+ }
+ _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs;
+ iter->second.second = expanded_output;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": Granted to VC " << granted_vc << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ }
+ } else if(_spec_sw_allocator) {
+ expanded_output = _spec_sw_allocator->OutputAssigned(expanded_input);
+ if(expanded_output >= 0) {
+ assert((expanded_output % _output_speedup) == (input % _output_speedup));
+ if(_spec_mask_by_reqs &&
+ _sw_allocator->OutputHasRequests(expanded_output)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding speculative grant for VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << " because output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " has non-speculative requests." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else if(!_spec_mask_by_reqs &&
+ (_sw_allocator->InputAssigned(expanded_output) >= 0)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding speculative grant for VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << " because output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " has a non-speculative grant." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else {
+ int const granted_vc = _spec_sw_allocator->ReadRequest(expanded_input,
+ expanded_output);
+ if(granted_vc == vc) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Assigning output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << " to VC " << vc
+ << " at input " << input
+ << "." << (vc % _input_speedup)
+ << "." << endl;
+ }
+ _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs;
+ iter->second.second = expanded_output;
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": Granted to VC " << granted_vc << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ }
+ }
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": No output granted." << endl;
+ }
+
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+
+ }
+ } else {
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Switch allocation failed for VC " << vc
+ << " at input " << input
+ << ": No output granted." << endl;
+ }
+
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+
+ }
+ }
+
+ if(!_speculative && (_sw_alloc_delay <= 1)) {
+ return;
+ }
+
+ for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin();
+ iter != _sw_alloc_vcs.end();
+ ++iter) {
+
+ int const time = iter->first;
+ assert(time >= 0);
+ if(GetSimTime() < time) {
+ break;
+ }
+
+ assert(iter->second.second != -1);
+
+ int const expanded_output = iter->second.second;
+
+ if(expanded_output >= 0) {
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState const * const dest_buf = _next_buf[output];
+
+ int const input = iter->second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ assert((input % _output_speedup) == (expanded_output % _output_speedup));
+ int const vc = iter->second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] != vc);
+
+ Buffer const * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit const * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if((_switch_hold_in[expanded_input] >= 0) ||
+ (_switch_hold_out[expanded_output] >= 0)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to conflict with held connection at ";
+ if(_switch_hold_in[expanded_input] >= 0) {
+ *gWatchOut << "input";
+ }
+ if((_switch_hold_in[expanded_input] >= 0) &&
+ (_switch_hold_out[expanded_output] >= 0)) {
+ *gWatchOut << " and ";
+ }
+ if(_switch_hold_out[expanded_output] >= 0) {
+ *gWatchOut << "output";
+ }
+ *gWatchOut << "." << endl;
+ }
+ iter->second.second = STALL_CROSSBAR_CONFLICT;
+ } else if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+
+ assert(f->head);
+
+ if(_vc_allocator) { // separate VC and switch allocators
+
+ int const input_and_vc =
+ _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc);
+ int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc);
+
+ if(output_and_vc < 0) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to misspeculation." << endl;
+ }
+ iter->second.second = -1; // stall is counted in VC allocation path!
+ } else if((output_and_vc / _vcs) != output) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to port mismatch between VC and switch allocator." << endl;
+ }
+ iter->second.second = STALL_BUFFER_CONFLICT; // count this case as if we had failed allocation
+ } else if(dest_buf->IsFullFor((output_and_vc % _vcs))) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to lack of credit." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+
+ } else { // VC allocation is piggybacked onto switch allocation
+
+ OutputSet const * const route_set = cur_buf->GetRouteSet(vc);
+ assert(route_set);
+
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ bool busy = true;
+ bool full = true;
+ bool reserved = false;
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+ if(iset->output_port == output) {
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+ if(dest_buf->IsAvailableFor(out_vc)) {
+ busy = false;
+ if(!dest_buf->IsFullFor(out_vc)) {
+ full = false;
+ break;
+ } else if(!dest_buf->IsFull()) {
+ reserved = true;
+ }
+ }
+ }
+ if(!full) {
+ break;
+ }
+ }
+ }
+
+ if(busy) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " because no suitable output VC for piggyback allocation is available." << endl;
+ }
+ iter->second.second = STALL_BUFFER_BUSY;
+ } else if(full) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " because all suitable output VCs for piggyback allocation are full." << endl;
+ }
+ iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL;
+ }
+
+ }
+
+ } else {
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ int const match_vc = cur_buf->GetOutputVC(vc);
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(dest_buf->IsFullFor(match_vc)) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Discarding grant from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << " due to lack of credit." << endl;
+ }
+ iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED;
+ }
+ }
+ }
+ }
+}
+
+void IQRouter::_SWAllocUpdate( )
+{
+ while(!_sw_alloc_vcs.empty()) {
+
+ pair<int, pair<pair<int, int>, int> > const & item = _sw_alloc_vcs.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ int const input = item.second.first.first;
+ assert((input >= 0) && (input < _inputs));
+ int const vc = item.second.first.second;
+ assert((vc >= 0) && (vc < _vcs));
+
+ Buffer * const cur_buf = _buf[input];
+ assert(!cur_buf->Empty(vc));
+ assert((cur_buf->GetState(vc) == VC::active) ||
+ (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)));
+
+ Flit * const f = cur_buf->FrontFlit(vc);
+ assert(f);
+ assert(f->vc == vc);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed switch allocation for VC " << vc
+ << " at input " << input
+ << " (front: " << f->id
+ << ")." << endl;
+ }
+
+ int const expanded_output = item.second.second;
+
+ if(expanded_output >= 0) {
+
+ int const expanded_input = input * _input_speedup + vc % _input_speedup;
+ assert(_switch_hold_vc[expanded_input] < 0);
+ assert(_switch_hold_in[expanded_input] < 0);
+ assert(_switch_hold_out[expanded_output] < 0);
+
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ BufferState * const dest_buf = _next_buf[output];
+
+ int match_vc;
+
+ if(!_vc_allocator && (cur_buf->GetState(vc) == VC::vc_alloc)) {
+
+ assert(f->head);
+
+ int const cl = f->cl;
+ assert((cl >= 0) && (cl < _classes));
+
+ int const vc_offset = _vc_rr_offset[output*_classes+cl];
+
+ match_vc = -1;
+ int match_prio = numeric_limits<int>::min();
+
+ const OutputSet * route_set = cur_buf->GetRouteSet(vc);
+ set<OutputSet::sSetElement> const setlist = route_set->GetSet();
+
+ assert(!_noq || (setlist.size() == 1));
+
+ for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin();
+ iset != setlist.end();
+ ++iset) {
+ if(iset->output_port == output) {
+
+ int vc_start;
+ int vc_end;
+
+ if(_noq && _noq_next_output_port[input][vc] >= 0) {
+ assert(!_routing_delay);
+ vc_start = _noq_next_vc_start[input][vc];
+ vc_end = _noq_next_vc_end[input][vc];
+ } else {
+ vc_start = iset->vc_start;
+ vc_end = iset->vc_end;
+ }
+ assert(vc_start >= 0 && vc_start < _vcs);
+ assert(vc_end >= 0 && vc_end < _vcs);
+ assert(vc_end >= vc_start);
+
+ for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) {
+ assert((out_vc >= 0) && (out_vc < _vcs));
+
+ int vc_prio = iset->pri;
+ if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) {
+ assert(vc_prio >= 0);
+ vc_prio += numeric_limits<int>::min();
+ }
+
+ // FIXME: This check should probably be performed in Evaluate(),
+ // not Update(), as the latter can cause the outcome to depend on
+ // the order of evaluation!
+ if(dest_buf->IsAvailableFor(out_vc) &&
+ !dest_buf->IsFullFor(out_vc) &&
+ ((match_vc < 0) ||
+ RoundRobinArbiter::Supersedes(out_vc, vc_prio,
+ match_vc, match_prio,
+ vc_offset, _vcs))) {
+ match_vc = out_vc;
+ match_prio = vc_prio;
+ }
+ }
+ }
+ }
+ assert(match_vc >= 0);
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Allocating VC " << match_vc
+ << " at output " << output
+ << " via piggyback VC allocation." << endl;
+ }
+
+ cur_buf->SetState(vc, VC::active);
+ cur_buf->SetOutput(vc, output, match_vc);
+ dest_buf->TakeBuffer(match_vc, input*_vcs + vc);
+
+ _vc_rr_offset[output*_classes+cl] = (match_vc + 1) % _vcs;
+
+ } else {
+
+ assert(cur_buf->GetOutputPort(vc) == output);
+
+ match_vc = cur_buf->GetOutputVC(vc);
+
+ }
+ assert((match_vc >= 0) && (match_vc < _vcs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " Scheduling switch connection from input " << input
+ << "." << (vc % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+
+ cur_buf->RemoveFlit(vc);
+
+#ifdef TRACK_FLOWS
+ --_stored_flits[f->cl][input];
+ if(f->tail) --_active_packets[f->cl][input];
+#endif
+
+ _bufferMonitor->read(input, f) ;
+
+ f->hops++;
+ f->vc = match_vc;
+
+ if(!_routing_delay && f->head) {
+ const FlitChannel * channel = _output_channels[output];
+ const Router * router = channel->GetSink();
+ if(router) {
+ if(_noq) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ int next_output_port = _noq_next_output_port[input][vc];
+ assert(next_output_port >= 0);
+ _noq_next_output_port[input][vc] = -1;
+ int next_vc_start = _noq_next_vc_start[input][vc];
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ _noq_next_vc_start[input][vc] = -1;
+ int next_vc_end = _noq_next_vc_end[input][vc];
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ _noq_next_vc_end[input][vc] = -1;
+ f->la_route_set.Clear();
+ f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end);
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Updating lookahead routing information for flit " << f->id
+ << "." << endl;
+ }
+ int in_channel = channel->GetSinkPort();
+ _rf(router, f, in_channel, &f->la_route_set, false);
+ }
+ } else {
+ f->la_route_set.Clear();
+ }
+ }
+
+#ifdef TRACK_FLOWS
+ ++_outstanding_credits[f->cl][output];
+ _outstanding_classes[output][f->vc].push(f->cl);
+#endif
+
+ dest_buf->SendingFlit(f);
+
+ _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output))));
+
+ if(_out_queue_credits.count(input) == 0) {
+ _out_queue_credits.insert(make_pair(input, Credit::New()));
+ }
+ _out_queue_credits.find(input)->second->vc.insert(vc);
+
+ if(cur_buf->Empty(vc)) {
+ if(f->tail) {
+ cur_buf->SetState(vc, VC::idle);
+ }
+ } else {
+ Flit * const nf = cur_buf->FrontFlit(vc);
+ assert(nf);
+ assert(nf->vc == vc);
+ if(f->tail) {
+ assert(nf->head);
+ if(_routing_delay) {
+ cur_buf->SetState(vc, VC::routing);
+ _route_vcs.push_back(make_pair(-1, item.second.first));
+ } else {
+ if(nf->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Using precomputed lookahead routing information for VC " << vc
+ << " at input " << input
+ << " (front: " << nf->id
+ << ")." << endl;
+ }
+ cur_buf->SetRouteSet(vc, &nf->la_route_set);
+ cur_buf->SetState(vc, VC::vc_alloc);
+ if(_speculative) {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_vc_allocator) {
+ _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ if(_noq) {
+ _UpdateNOQ(input, vc, nf);
+ }
+ }
+ } else {
+ if(_hold_switch_for_packet) {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Setting up switch hold for VC " << vc
+ << " at input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ _switch_hold_vc[expanded_input] = vc;
+ _switch_hold_in[expanded_input] = expanded_output;
+ _switch_hold_out[expanded_output] = expanded_input;
+ _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ } else {
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first,
+ -1)));
+ }
+ }
+ }
+ } else {
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << " No output port allocated." << endl;
+ }
+
+#ifdef TRACK_STALLS
+ assert((expanded_output == -1) || // for stalls that are accounted for in VC allocation path
+ (expanded_output == STALL_BUFFER_BUSY) ||
+ (expanded_output == STALL_BUFFER_CONFLICT) ||
+ (expanded_output == STALL_BUFFER_FULL) ||
+ (expanded_output == STALL_BUFFER_RESERVED) ||
+ (expanded_output == STALL_CROSSBAR_CONFLICT));
+ if(expanded_output == STALL_BUFFER_BUSY) {
+ ++_buffer_busy_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_CONFLICT) {
+ ++_buffer_conflict_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_FULL) {
+ ++_buffer_full_stalls[f->cl];
+ } else if(expanded_output == STALL_BUFFER_RESERVED) {
+ ++_buffer_reserved_stalls[f->cl];
+ } else if(expanded_output == STALL_CROSSBAR_CONFLICT) {
+ ++_crossbar_conflict_stalls[f->cl];
+ }
+#endif
+
+ _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1)));
+ }
+ _sw_alloc_vcs.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// switch traversal
+//------------------------------------------------------------------------------
+
+void IQRouter::_SwitchEvaluate( )
+{
+ for(deque<pair<int, pair<Flit *, pair<int, int> > > >::iterator iter = _crossbar_flits.begin();
+ iter != _crossbar_flits.end();
+ ++iter) {
+
+ int const time = iter->first;
+ if(time >= 0) {
+ break;
+ }
+ iter->first = GetSimTime() + _crossbar_delay - 1;
+
+ Flit const * const f = iter->second.first;
+ assert(f);
+
+ int const expanded_input = iter->second.second.first;
+ int const expanded_output = iter->second.second.second;
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Beginning crossbar traversal for flit " << f->id
+ << " from input " << (expanded_input / _input_speedup)
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << (expanded_output / _output_speedup)
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ }
+}
+
+void IQRouter::_SwitchUpdate( )
+{
+ while(!_crossbar_flits.empty()) {
+
+ pair<int, pair<Flit *, pair<int, int> > > const & item = _crossbar_flits.front();
+
+ int const time = item.first;
+ if((time < 0) || (GetSimTime() < time)) {
+ break;
+ }
+ assert(GetSimTime() == time);
+
+ Flit * const f = item.second.first;
+ assert(f);
+
+ int const expanded_input = item.second.second.first;
+ int const input = expanded_input / _input_speedup;
+ assert((input >= 0) && (input < _inputs));
+ int const expanded_output = item.second.second.second;
+ int const output = expanded_output / _output_speedup;
+ assert((output >= 0) && (output < _outputs));
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Completed crossbar traversal for flit " << f->id
+ << " from input " << input
+ << "." << (expanded_input % _input_speedup)
+ << " to output " << output
+ << "." << (expanded_output % _output_speedup)
+ << "." << endl;
+ }
+ _switchMonitor->traversal(input, output, f) ;
+
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Buffering flit " << f->id
+ << " at output " << output
+ << "." << endl;
+ }
+ _output_buffer[output].push(f);
+ //the output buffer size isn't precise due to flits in flight
+ //but there is a maximum bound based on output speed up and ST traversal
+ assert(_output_buffer[output].size()<=(size_t)_output_buffer_size+ _crossbar_delay* _output_speedup+( _output_speedup-1) ||_output_buffer_size==-1);
+ _crossbar_flits.pop_front();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// output queuing
+//------------------------------------------------------------------------------
+
+void IQRouter::_OutputQueuing( )
+{
+ for(map<int, Credit *>::const_iterator iter = _out_queue_credits.begin();
+ iter != _out_queue_credits.end();
+ ++iter) {
+
+ int const input = iter->first;
+ assert((input >= 0) && (input < _inputs));
+
+ Credit * const c = iter->second;
+ assert(c);
+ assert(!c->vc.empty());
+
+ _credit_buffer[input].push(c);
+ }
+ _out_queue_credits.clear();
+}
+
+//------------------------------------------------------------------------------
+// write outputs
+//------------------------------------------------------------------------------
+
+void IQRouter::_SendFlits( )
+{
+ for ( int output = 0; output < _outputs; ++output ) {
+ if ( !_output_buffer[output].empty( ) ) {
+ Flit * const f = _output_buffer[output].front( );
+ assert(f);
+ _output_buffer[output].pop( );
+
+#ifdef TRACK_FLOWS
+ ++_sent_flits[f->cl][output];
+#endif
+
+ if(f->watch)
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Sending flit " << f->id
+ << " to channel at output " << output
+ << "." << endl;
+ if(gTrace) {
+ cout << "Outport " << output << endl << "Stop Mark" << endl;
+ }
+ _output_channels[output]->Send( f );
+ }
+ }
+}
+
+void IQRouter::_SendCredits( )
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ if ( !_credit_buffer[input].empty( ) ) {
+ Credit * const c = _credit_buffer[input].front( );
+ assert(c);
+ _credit_buffer[input].pop( );
+ _input_credits[input]->Send( c );
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// misc.
+//------------------------------------------------------------------------------
+
+void IQRouter::Display( ostream & os ) const
+{
+ for ( int input = 0; input < _inputs; ++input ) {
+ _buf[input]->Display( os );
+ }
+}
+
+int IQRouter::GetUsedCredit(int o) const
+{
+ assert((o >= 0) && (o < _outputs));
+ BufferState const * const dest_buf = _next_buf[o];
+ return dest_buf->Occupancy();
+}
+
+int IQRouter::GetBufferOccupancy(int i) const {
+ assert(i >= 0 && i < _inputs);
+ return _buf[i]->GetOccupancy();
+}
+
+#ifdef TRACK_BUFFERS
+int IQRouter::GetUsedCreditForClass(int output, int cl) const
+{
+ assert((output >= 0) && (output < _outputs));
+ BufferState const * const dest_buf = _next_buf[output];
+ return dest_buf->OccupancyForClass(cl);
+}
+
+int IQRouter::GetBufferOccupancyForClass(int input, int cl) const
+{
+ assert((input >= 0) && (input < _inputs));
+ return _buf[input]->GetOccupancyForClass(cl);
+}
+#endif
+
+vector<int> IQRouter::UsedCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->OccupancyFor(v);
+ }
+ }
+ return result;
+}
+
+vector<int> IQRouter::FreeCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->AvailableFor(v);
+ }
+ }
+ return result;
+}
+
+vector<int> IQRouter::MaxCredits() const
+{
+ vector<int> result(_outputs*_vcs);
+ for(int o = 0; o < _outputs; ++o) {
+ for(int v = 0; v < _vcs; ++v) {
+ result[o*_vcs+v] = _next_buf[o]->LimitFor(v);
+ }
+ }
+ return result;
+}
+
+void IQRouter::_UpdateNOQ(int input, int vc, Flit const * f) {
+ assert(!_routing_delay);
+ assert(f);
+ assert(f->vc == vc);
+ assert(f->head);
+ set<OutputSet::sSetElement> sl = f->la_route_set.GetSet();
+ assert(sl.size() == 1);
+ int out_port = sl.begin()->output_port;
+ const FlitChannel * channel = _output_channels[out_port];
+ const Router * router = channel->GetSink();
+ if(router) {
+ int in_channel = channel->GetSinkPort();
+ OutputSet nos;
+ _rf(router, f, in_channel, &nos, false);
+ sl = nos.GetSet();
+ assert(sl.size() == 1);
+ OutputSet::sSetElement const & se = *sl.begin();
+ int next_output_port = se.output_port;
+ assert(next_output_port >= 0);
+ assert(_noq_next_output_port[input][vc] < 0);
+ _noq_next_output_port[input][vc] = next_output_port;
+ int next_vc_count = (se.vc_end - se.vc_start + 1) / router->NumOutputs();
+ int next_vc_start = se.vc_start + next_output_port * next_vc_count;
+ assert(next_vc_start >= 0 && next_vc_start < _vcs);
+ assert(_noq_next_vc_start[input][vc] < 0);
+ _noq_next_vc_start[input][vc] = next_vc_start;
+ int next_vc_end = se.vc_start + (next_output_port + 1) * next_vc_count - 1;
+ assert(next_vc_end >= 0 && next_vc_end < _vcs);
+ assert(_noq_next_vc_end[input][vc] < 0);
+ _noq_next_vc_end[input][vc] = next_vc_end;
+ assert(next_vc_start <= next_vc_end);
+ if(f->watch) {
+ *gWatchOut << GetSimTime() << " | " << FullName() << " | "
+ << "Computing lookahead routing information for flit " << f->id
+ << " (NOQ)." << endl;
+ }
+ }
+}
diff --git a/src/intersim2/routers/iq_router.hpp b/src/intersim2/routers/iq_router.hpp
new file mode 100644
index 0000000..b64502d
--- /dev/null
+++ b/src/intersim2/routers/iq_router.hpp
@@ -0,0 +1,183 @@
+// $Id: iq_router.hpp 5263 2012-09-20 23:40:33Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _IQ_ROUTER_HPP_
+#define _IQ_ROUTER_HPP_
+
+#include <string>
+#include <deque>
+#include <queue>
+#include <set>
+#include <map>
+
+#include "router.hpp"
+#include "routefunc.hpp"
+
+using namespace std;
+
+class VC;
+class Flit;
+class Credit;
+class Buffer;
+class BufferState;
+class Allocator;
+class SwitchMonitor;
+class BufferMonitor;
+
+class IQRouter : public Router {
+
+ int _vcs;
+
+ bool _vc_busy_when_full;
+ bool _vc_prioritize_empty;
+ bool _vc_shuffle_requests;
+
+ bool _speculative;
+ bool _spec_check_elig;
+ bool _spec_check_cred;
+ bool _spec_mask_by_reqs;
+
+ bool _active;
+
+ int _routing_delay;
+ int _vc_alloc_delay;
+ int _sw_alloc_delay;
+
+ map<int, Flit *> _in_queue_flits;
+
+ deque<pair<int, pair<Credit *, int> > > _proc_credits;
+
+ deque<pair<int, pair<int, int> > > _route_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _vc_alloc_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _sw_hold_vcs;
+ deque<pair<int, pair<pair<int, int>, int> > > _sw_alloc_vcs;
+
+ deque<pair<int, pair<Flit *, pair<int, int> > > > _crossbar_flits;
+
+ map<int, Credit *> _out_queue_credits;
+
+ vector<Buffer *> _buf;
+ vector<BufferState *> _next_buf;
+
+ Allocator *_vc_allocator;
+ Allocator *_sw_allocator;
+ Allocator *_spec_sw_allocator;
+
+ vector<int> _vc_rr_offset;
+ vector<int> _sw_rr_offset;
+
+ tRoutingFunction _rf;
+
+ int _output_buffer_size;
+ vector<queue<Flit *> > _output_buffer;
+
+ vector<queue<Credit *> > _credit_buffer;
+
+ bool _hold_switch_for_packet;
+ vector<int> _switch_hold_in;
+ vector<int> _switch_hold_out;
+ vector<int> _switch_hold_vc;
+
+ bool _noq;
+ vector<vector<int> > _noq_next_output_port;
+ vector<vector<int> > _noq_next_vc_start;
+ vector<vector<int> > _noq_next_vc_end;
+
+#ifdef TRACK_FLOWS
+ vector<vector<queue<int> > > _outstanding_classes;
+#endif
+
+ bool _ReceiveFlits( );
+ bool _ReceiveCredits( );
+
+ virtual void _InternalStep( );
+
+ bool _SWAllocAddReq(int input, int vc, int output);
+
+ void _InputQueuing( );
+
+ void _RouteEvaluate( );
+ void _VCAllocEvaluate( );
+ void _SWHoldEvaluate( );
+ void _SWAllocEvaluate( );
+ void _SwitchEvaluate( );
+
+ void _RouteUpdate( );
+ void _VCAllocUpdate( );
+ void _SWHoldUpdate( );
+ void _SWAllocUpdate( );
+ void _SwitchUpdate( );
+
+ void _OutputQueuing( );
+
+ void _SendFlits( );
+ void _SendCredits( );
+
+ void _UpdateNOQ(int input, int vc, Flit const * f);
+
+ // ----------------------------------------
+ //
+ // Router Power Modellingyes
+ //
+ // ----------------------------------------
+
+ SwitchMonitor * _switchMonitor ;
+ BufferMonitor * _bufferMonitor ;
+
+public:
+
+ IQRouter( Configuration const & config,
+ Module *parent, string const & name, int id,
+ int inputs, int outputs );
+
+ virtual ~IQRouter( );
+
+ virtual void AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel);
+
+ virtual void ReadInputs( );
+ virtual void WriteOutputs( );
+
+ void Display( ostream & os = cout ) const;
+
+ virtual int GetUsedCredit(int o) const;
+ virtual int GetBufferOccupancy(int i) const;
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const;
+ virtual int GetBufferOccupancyForClass(int input, int cl) const;
+#endif
+
+ virtual vector<int> UsedCredits() const;
+ virtual vector<int> FreeCredits() const;
+ virtual vector<int> MaxCredits() const;
+
+ SwitchMonitor const * const GetSwitchMonitor() const {return _switchMonitor;}
+ BufferMonitor const * const GetBufferMonitor() const {return _bufferMonitor;}
+
+};
+
+#endif
diff --git a/src/intersim2/routers/router.cpp b/src/intersim2/routers/router.cpp
new file mode 100644
index 0000000..cb6f078
--- /dev/null
+++ b/src/intersim2/routers/router.cpp
@@ -0,0 +1,155 @@
+// $Id: router.cpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*router.cpp
+ *
+ *The base class of either iq router or event router
+ *contains a list of channels and other router configuration variables
+ *
+ *The older version of the simulator uses an array of flits and credit to
+ *simulate the channels. Newer version ueses flitchannel and credit channel
+ *which can better model channel delay
+ *
+ *The older version of the simulator also uses vc_router and chaos router
+ *which are replaced by iq rotuer and event router in the present form
+ */
+
+#include "booksim.hpp"
+#include <iostream>
+#include <cassert>
+#include "router.hpp"
+
+//////////////////Sub router types//////////////////////
+#include "iq_router.hpp"
+#include "event_router.hpp"
+#include "chaos_router.hpp"
+///////////////////////////////////////////////////////
+
+int const Router::STALL_BUFFER_BUSY = -2;
+int const Router::STALL_BUFFER_CONFLICT = -3;
+int const Router::STALL_BUFFER_FULL = -4;
+int const Router::STALL_BUFFER_RESERVED = -5;
+int const Router::STALL_CROSSBAR_CONFLICT = -6;
+
+Router::Router( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs ) :
+TimedModule( parent, name ), _id( id ), _inputs( inputs ), _outputs( outputs ),
+ _partial_internal_cycles(0.0)
+{
+ _crossbar_delay = ( config.GetInt( "st_prepare_delay" ) +
+ config.GetInt( "st_final_delay" ) );
+ _credit_delay = config.GetInt( "credit_delay" );
+ _input_speedup = config.GetInt( "input_speedup" );
+ _output_speedup = config.GetInt( "output_speedup" );
+ _internal_speedup = config.GetFloat( "internal_speedup" );
+ _classes = config.GetInt( "classes" );
+
+#ifdef TRACK_FLOWS
+ _received_flits.resize(_classes, vector<int>(_inputs, 0));
+ _stored_flits.resize(_classes);
+ _sent_flits.resize(_classes, vector<int>(_outputs, 0));
+ _active_packets.resize(_classes);
+ _outstanding_credits.resize(_classes, vector<int>(_outputs, 0));
+#endif
+
+#ifdef TRACK_STALLS
+ _buffer_busy_stalls.resize(_classes, 0);
+ _buffer_conflict_stalls.resize(_classes, 0);
+ _buffer_full_stalls.resize(_classes, 0);
+ _buffer_reserved_stalls.resize(_classes, 0);
+ _crossbar_conflict_stalls.resize(_classes, 0);
+#endif
+
+}
+
+void Router::AddInputChannel( FlitChannel *channel, CreditChannel *backchannel )
+{
+ _input_channels.push_back( channel );
+ _input_credits.push_back( backchannel );
+ channel->SetSink( this, _input_channels.size() - 1 ) ;
+}
+
+void Router::AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel )
+{
+ _output_channels.push_back( channel );
+ _output_credits.push_back( backchannel );
+ _channel_faults.push_back( false );
+ channel->SetSource( this, _output_channels.size() - 1 ) ;
+}
+
+void Router::Evaluate( )
+{
+ _partial_internal_cycles += _internal_speedup;
+ while( _partial_internal_cycles >= 1.0 ) {
+ _InternalStep( );
+ _partial_internal_cycles -= 1.0;
+ }
+}
+
+void Router::OutChannelFault( int c, bool fault )
+{
+ assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) );
+
+ _channel_faults[c] = fault;
+}
+
+bool Router::IsFaultyOutput( int c ) const
+{
+ assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) );
+
+ return _channel_faults[c];
+}
+
+/*Router constructor*/
+Router *Router::NewRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs )
+{
+ const string type = config.GetStr( "router" );
+ Router *r = NULL;
+ if ( type == "iq" ) {
+ r = new IQRouter( config, parent, name, id, inputs, outputs );
+ } else if ( type == "event" ) {
+ r = new EventRouter( config, parent, name, id, inputs, outputs );
+ } else if ( type == "chaos" ) {
+ r = new ChaosRouter( config, parent, name, id, inputs, outputs );
+ } else {
+ cerr << "Unknown router type: " << type << endl;
+ }
+ /*For additional router, add another else if statement*/
+ /*Original booksim specifies the router using "flow_control"
+ *we now simply call these types.
+ */
+
+ return r;
+}
+
+
+
+
+
diff --git a/src/intersim2/routers/router.hpp b/src/intersim2/routers/router.hpp
new file mode 100644
index 0000000..1dff57f
--- /dev/null
+++ b/src/intersim2/routers/router.hpp
@@ -0,0 +1,202 @@
+// $Id: router.hpp 5188 2012-08-30 00:31:31Z dub $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _ROUTER_HPP_
+#define _ROUTER_HPP_
+
+#include <string>
+#include <vector>
+
+#include "timed_module.hpp"
+#include "flit.hpp"
+#include "credit.hpp"
+#include "flitchannel.hpp"
+#include "channel.hpp"
+#include "config_utils.hpp"
+
+typedef Channel<Credit> CreditChannel;
+
+class Router : public TimedModule {
+
+protected:
+
+ static int const STALL_BUFFER_BUSY;
+ static int const STALL_BUFFER_CONFLICT;
+ static int const STALL_BUFFER_FULL;
+ static int const STALL_BUFFER_RESERVED;
+ static int const STALL_CROSSBAR_CONFLICT;
+
+ int _id;
+
+ int _inputs;
+ int _outputs;
+
+ int _classes;
+
+ int _input_speedup;
+ int _output_speedup;
+
+ double _internal_speedup;
+ double _partial_internal_cycles;
+
+ int _crossbar_delay;
+ int _credit_delay;
+
+ vector<FlitChannel *> _input_channels;
+ vector<CreditChannel *> _input_credits;
+ vector<FlitChannel *> _output_channels;
+ vector<CreditChannel *> _output_credits;
+ vector<bool> _channel_faults;
+
+#ifdef TRACK_FLOWS
+ vector<vector<int> > _received_flits;
+ vector<vector<int> > _stored_flits;
+ vector<vector<int> > _sent_flits;
+ vector<vector<int> > _outstanding_credits;
+ vector<vector<int> > _active_packets;
+#endif
+
+#ifdef TRACK_STALLS
+ vector<int> _buffer_busy_stalls;
+ vector<int> _buffer_conflict_stalls;
+ vector<int> _buffer_full_stalls;
+ vector<int> _buffer_reserved_stalls;
+ vector<int> _crossbar_conflict_stalls;
+#endif
+
+ virtual void _InternalStep() = 0;
+
+public:
+ Router( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ static Router *NewRouter( const Configuration& config,
+ Module *parent, const string & name, int id,
+ int inputs, int outputs );
+
+ virtual void AddInputChannel( FlitChannel *channel, CreditChannel *backchannel );
+ virtual void AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel );
+
+ inline FlitChannel * GetInputChannel( int input ) const {
+ assert((input >= 0) && (input < _inputs));
+ return _input_channels[input];
+ }
+ inline FlitChannel * GetOutputChannel( int output ) const {
+ assert((output >= 0) && (output < _outputs));
+ return _output_channels[output];
+ }
+
+ virtual void ReadInputs( ) = 0;
+ virtual void Evaluate( );
+ virtual void WriteOutputs( ) = 0;
+
+ void OutChannelFault( int c, bool fault = true );
+ bool IsFaultyOutput( int c ) const;
+
+ inline int GetID( ) const {return _id;}
+
+
+ virtual int GetUsedCredit(int o) const = 0;
+ virtual int GetBufferOccupancy(int i) const = 0;
+
+#ifdef TRACK_BUFFERS
+ virtual int GetUsedCreditForClass(int output, int cl) const = 0;
+ virtual int GetBufferOccupancyForClass(int input, int cl) const = 0;
+#endif
+
+#ifdef TRACK_FLOWS
+ inline vector<int> const & GetReceivedFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _received_flits[c];
+ }
+ inline vector<int> const & GetStoredFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _stored_flits[c];
+ }
+ inline vector<int> const & GetSentFlits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _sent_flits[c];
+ }
+ inline vector<int> const & GetOutstandingCredits(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _outstanding_credits[c];
+ }
+
+ inline vector<int> const & GetActivePackets(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _active_packets[c];
+ }
+
+ inline void ResetFlowStats(int c) {
+ assert((c >= 0) && (c < _classes));
+ _received_flits[c].assign(_received_flits[c].size(), 0);
+ _sent_flits[c].assign(_sent_flits[c].size(), 0);
+ }
+#endif
+
+ virtual vector<int> UsedCredits() const = 0;
+ virtual vector<int> FreeCredits() const = 0;
+ virtual vector<int> MaxCredits() const = 0;
+
+#ifdef TRACK_STALLS
+ inline int GetBufferBusyStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_busy_stalls[c];
+ }
+ inline int GetBufferConflictStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_conflict_stalls[c];
+ }
+ inline int GetBufferFullStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_full_stalls[c];
+ }
+ inline int GetBufferReservedStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _buffer_reserved_stalls[c];
+ }
+ inline int GetCrossbarConflictStalls(int c) const {
+ assert((c >= 0) && (c < _classes));
+ return _crossbar_conflict_stalls[c];
+ }
+
+ inline void ResetStallStats(int c) {
+ assert((c >= 0) && (c < _classes));
+ _buffer_busy_stalls[c] = 0;
+ _buffer_conflict_stalls[c] = 0;
+ _buffer_full_stalls[c] = 0;
+ _buffer_reserved_stalls[c] = 0;
+ _crossbar_conflict_stalls[c] = 0;
+ }
+#endif
+
+ inline int NumInputs() const {return _inputs;}
+ inline int NumOutputs() const {return _outputs;}
+};
+
+#endif