source: branches/reconfiguration/modules/dspin_router/caba/source/src/dspin_router.cpp @ 854

Last change on this file since 854 was 854, checked in by cfuguet, 9 years ago

reconf: introducing reconf branch of the soclib/dspin_router component

  • For now, this branch contains an additional attribute allowing to disable the desired interfaces to simulate faulty channels.
File size: 22.8 KB
Line 
1/* -*- c++ -*-
2  *
3  * File : dspin_router.cpp
4  * Copyright (c) UPMC, Lip6
5  * Authors : Alain Greiner, Abbas Sheibanyrad, Ivan Miro, Zhen Zhang
6  *
7  * SOCLIB_LGPL_HEADER_BEGIN
8  *
9  * This file is part of SoCLib, GNU LGPLv2.1.
10  *
11  * SoCLib is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published
13  * by the Free Software Foundation; version 2.1 of the License.
14  *
15  * SoCLib is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with SoCLib; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  *
25  * SOCLIB_LGPL_HEADER_END
26  *
27  */
28
29    ///////////////////////////////////////////////////////////////////////////
30    // Implementation Note :
31    // The xfirst_route(), broadcast_route() and is_broadcast() functions
32    // defined below are used to decode the DSPIN first flit format:
33    // - In case of a non-broadcast packet :
34    //  |   X     |   Y     |---------------------------------------|BC |
35    //  | x_width | y_width |  flit_width - (x_width + y_width + 2) | 0 |
36    //
37    //  - In case of a broacast
38    //  |  XMIN   |  XMAX   |  YMIN   |  YMAX   |-------------------|BC |
39    //  |   5     |   5     |   5     |   5     | flit_width - 22   | 1 |
40    ///////////////////////////////////////////////////////////////////////////
41
42#include "../include/dspin_router.h"
43
44namespace soclib { namespace caba {
45
46using namespace soclib::common;
47using namespace soclib::caba;
48
49#define tmpl(x) template<int flit_width> x DspinRouter<flit_width>
50
51    ////////////////////////////////////////////////
52    //              constructor
53    ////////////////////////////////////////////////
54    tmpl(/**/)::DspinRouter( sc_module_name name,
55                             const size_t   x,
56                             const size_t   y,
57                             const size_t   x_width,
58                             const size_t   y_width,
59                             const size_t   in_fifo_depth,
60                             const size_t   out_fifo_depth,
61                             const bool     broadcast_supported )
62    : soclib::caba::BaseModule(name),
63
64      p_clk( "p_clk" ),
65      p_resetn( "p_resetn" ),
66      p_in( alloc_elems<DspinInput<flit_width> >("p_in", 5) ),
67      p_out( alloc_elems<DspinOutput<flit_width> >("p_out", 5) ),
68
69      r_alloc_out( alloc_elems<sc_signal<bool> >("r_alloc_out", 5)),
70      r_index_out( soclib::common::alloc_elems<sc_signal<size_t> >("r_index_out", 5)),
71      r_fsm_in( alloc_elems<sc_signal<int> >("r_fsm_in", 5)),
72      r_index_in( alloc_elems<sc_signal<size_t> >("r_index_in", 5)),
73
74      m_local_x( x ),
75      m_local_y( y ),
76      m_x_width( x_width ),
77      m_x_shift( flit_width - x_width ),
78      m_x_mask( (0x1 << x_width) - 1 ),
79      m_y_width( y_width ),
80      m_y_shift( flit_width - x_width - y_width ),
81      m_y_mask( (0x1 << y_width) - 1 ),
82      m_broadcast_supported( broadcast_supported ),
83      m_disable_mask( 0 )
84    {
85        std::cout << "  - Building DspinRouter : " << name << std::endl;
86
87        SC_METHOD (transition);
88        dont_initialize();
89        sensitive << p_clk.pos();
90
91        SC_METHOD (genMoore);
92        dont_initialize();
93        sensitive  << p_clk.neg();
94
95        r_fifo_in  = (GenericFifo<internal_flit_t>*)
96                     malloc(sizeof(GenericFifo<internal_flit_t>) * 5);
97
98        r_fifo_out = (GenericFifo<internal_flit_t>*)
99                     malloc(sizeof(GenericFifo<internal_flit_t>) * 5);
100
101        r_buf_in   = (internal_flit_t*)
102                     malloc(sizeof(internal_flit_t) * 5);
103
104        for( size_t i = 0 ; i < 5 ; i++ )
105        {
106            std::ostringstream stri;
107            stri << "r_in_fifo_" << i;
108            new(&r_fifo_in[i])
109                GenericFifo<internal_flit_t >(stri.str(), in_fifo_depth);
110
111            std::ostringstream stro;
112            stro << "r_out_fifo_" << i;
113            new(&r_fifo_out[i])
114                GenericFifo<internal_flit_t >(stro.str(), out_fifo_depth);
115        }
116    } //  end constructor
117
118    ///////////////////////////////////////////////////
119    tmpl(int)::xfirst_route( sc_uint<flit_width> data )
120    {
121        size_t xdest = (size_t)(data >> m_x_shift) & m_x_mask;
122        size_t ydest = (size_t)(data >> m_y_shift) & m_y_mask;
123        return (xdest < m_local_x ? REQ_WEST :
124               (xdest > m_local_x ? REQ_EAST :
125               (ydest < m_local_y ? REQ_SOUTH :
126               (ydest > m_local_y ? REQ_NORTH : REQ_LOCAL))));
127    }
128
129    //////////////////////////////////////////////////////////////////////////
130    tmpl(int)::broadcast_route(int step, int source, sc_uint<flit_width> data)
131    {
132        int    sel  = REQ_NOP;
133        size_t xmin = (data >> (flit_width - 5 )) & 0x1F;
134        size_t xmax = (data >> (flit_width - 10)) & 0x1F;
135        size_t ymin = (data >> (flit_width - 15)) & 0x1F;
136        size_t ymax = (data >> (flit_width - 20)) & 0x1F;
137
138        switch(source) {
139        case REQ_LOCAL :
140            if      ( step == 1 )   sel = REQ_NORTH;
141            else if ( step == 2 )   sel = REQ_SOUTH;
142            else if ( step == 3 )   sel = REQ_EAST;
143            else if ( step == 4 )   sel = REQ_WEST;
144        break;
145        case REQ_NORTH :
146            if      ( step == 1 )   sel = REQ_SOUTH;
147            else if ( step == 2 )   sel = REQ_LOCAL;
148            else if ( step == 3 )   sel = REQ_NOP;
149            else if ( step == 4 )   sel = REQ_NOP;
150        break;
151        case REQ_SOUTH :
152            if      ( step == 1 )   sel = REQ_NORTH;
153            else if ( step == 2 )   sel = REQ_LOCAL;
154            else if ( step == 3 )   sel = REQ_NOP;
155            else if ( step == 4 )   sel = REQ_NOP;
156        break;
157        case REQ_EAST :
158            if      ( step == 1 )   sel = REQ_WEST;
159            else if ( step == 2 )   sel = REQ_NORTH;
160            else if ( step == 3 )   sel = REQ_SOUTH;
161            else if ( step == 4 )   sel = REQ_LOCAL;
162        break;
163        case REQ_WEST :
164            if      ( step == 1 )   sel = REQ_EAST;
165            else if ( step == 2 )   sel = REQ_NORTH;
166            else if ( step == 3 )   sel = REQ_SOUTH;
167            else if ( step == 4 )   sel = REQ_LOCAL;
168        break;
169        }
170        if      ( (sel == REQ_NORTH) && !(m_local_y < ymax) )   sel = REQ_NOP;
171        else if ( (sel == REQ_SOUTH) && !(m_local_y > ymin) )   sel = REQ_NOP;
172        else if ( (sel == REQ_EAST ) && !(m_local_x < xmax) )   sel = REQ_NOP;
173        else if ( (sel == REQ_WEST ) && !(m_local_x > xmin) )   sel = REQ_NOP;
174
175        return sel;
176    }
177
178    /////////////////////////////////////////////////////////
179    tmpl(inline bool)::is_broadcast(sc_uint<flit_width> data)
180    {
181        return ( (data & 0x1) != 0);
182    }
183
184    /////////////////////////////////////////////////////////
185    tmpl(void)::set_disable_mask( int mask )
186    {
187        m_disable_mask = mask;
188    }
189
190    /////////////////////////
191    tmpl(void)::print_trace()
192    {
193        const char* port_name[] =
194        {
195            "N",
196            "S",
197            "E",
198            "W",
199            "L"
200        };
201
202        const char* infsm_str[] =
203        {
204            "IDLE",
205            "REQ",
206            "ALLOC",
207            "REQ_FIRST",
208            "ALLOC_FIRST",
209            "REQ_SECOND",
210            "ALLOC_SECOND",
211            "REQ_THIRD",
212            "ALLOC_THIRD",
213            "REQ_FOURTH",
214            "ALLOC_FOURTH"
215        };
216
217        std::cout << "DSPIN_ROUTER " << name();
218
219        for( size_t i = 0 ; i < 5 ; i++)  // loop on input ports
220        {
221            std::cout << " / infsm[" << port_name[i] << "] "
222                      << infsm_str[r_fsm_in[i].read()];
223        }
224
225        for ( size_t out=0 ; out<5 ; out++)  // loop on output ports
226        {
227            if ( r_alloc_out[out].read() )
228            {
229                int in = r_index_out[out];
230                std::cout << " / " << port_name[in] << " -> " << port_name[out] ;
231            }
232        }
233        std::cout << std::endl;
234    }
235
236    ////////////////////////
237    tmpl(void)::transition()
238    {
239        // Long wires connecting input and output ports
240        size_t              req_in[5];         // input ports  -> output ports
241        size_t              get_out[5];        // output ports -> input ports
242        bool                put_in[5];         // input ports  -> output ports
243        internal_flit_t     data_in[5];        // input ports  -> output ports
244
245        // control signals for the input fifos
246        bool                fifo_in_write[5];
247        bool                fifo_in_read[5];
248        internal_flit_t     fifo_in_wdata[5];
249
250        // control signals for the output fifos
251        bool                fifo_out_write[5];
252        bool                fifo_out_read[5];
253        internal_flit_t     fifo_out_wdata[5];
254
255        // Reset
256        if ( p_resetn == false )
257        {
258            for(size_t i = 0 ; i < 5 ; i++)
259            {
260                r_alloc_out[i] = false;
261                r_index_out[i] = 0;
262                r_index_in[i]  = 0;
263                r_fsm_in[i]    = INFSM_IDLE;
264                r_fifo_in[i].init();
265                r_fifo_out[i].init();
266            }
267            return;
268        }
269
270        // fifos signals default values
271        for(size_t i = 0 ; i < 5 ; i++)
272        {
273            fifo_in_read[i]        = false;
274
275            // do not write into the FIFO of disabled interfaces
276            fifo_in_write[i]       = p_in[i].write.read() &&
277                                     ((m_disable_mask & (1 << i)) == 0);
278
279            fifo_in_wdata[i].data  = p_in[i].data.read();
280            fifo_in_wdata[i].eop   = p_in[i].eop.read();
281
282            fifo_out_read[i]       = p_out[i].read.read();
283            fifo_out_write[i]      = false;
284        }
285
286        // loop on the output ports:
287        // compute get_out[j] depending on the output port state
288        // and combining fifo_out[j].wok and r_alloc_out[j]
289        for ( size_t j = 0 ; j < 5 ; j++ )
290        {
291            if( r_alloc_out[j].read() and (r_fifo_out[j].wok()) )
292            {
293                get_out[j] = r_index_out[j].read();
294            }
295            else
296            {
297                get_out[j] = 0xFFFFFFFF;
298            }
299        }
300
301        // loop on the input ports :
302        // The port state is defined by r_fsm_in[i], r_index_in[i] & r_buf_in[i]
303        // The req_in[i] computation implements the X-FIRST algorithm.
304        // data_in[i], put_in[i] and req_in[i] depend on the input port state.
305        // The fifo_in_read[i] is computed further...
306
307        for ( size_t i = 0 ; i < 5 ; i++ )
308        {
309            switch ( r_fsm_in[i].read() )
310            {
311                case INFSM_IDLE:    // no output port allocated
312                {
313                    put_in[i] = false;
314
315                    if ( r_fifo_in[i].rok() ) // packet available in input fifo
316                    {
317                        if ( is_broadcast( r_fifo_in[i].read().data ) and
318                             m_broadcast_supported )          // broadcast
319                        {
320                            fifo_in_read[i] = true;
321                            req_in[i]       = broadcast_route(1, i, r_fifo_in[i].read().data);
322                            r_buf_in[i]     = r_fifo_in[i].read();
323                            r_index_in[i]   = req_in[i];
324                            if( req_in[i] == REQ_NOP ) r_fsm_in[i] = INFSM_REQ_SECOND;
325                            else                       r_fsm_in[i] = INFSM_REQ_FIRST;
326                        }
327                        else                                  // unicast
328                        {
329                            req_in[i]       = xfirst_route(r_fifo_in[i].read().data);
330                            r_index_in[i]   = req_in[i];
331                            r_fsm_in[i]     = INFSM_REQ;
332                        }
333                    }
334                    else
335                    {
336                        req_in[i] = REQ_NOP;
337                    }
338                    break;
339                }
340                case INFSM_REQ:   // not a broadcast / waiting output port allocation
341                {
342                    data_in[i]      = r_fifo_in[i].read();
343                    put_in[i]       = r_fifo_in[i].rok();
344                    req_in[i]       = r_index_in[i];
345                    fifo_in_read[i] = (get_out[r_index_in[i].read()] == i);
346                    if ( get_out[r_index_in[i].read()] == i ) // first flit transfered
347                    {
348                        if ( r_fifo_in[i].read().eop ) r_fsm_in[i] = INFSM_IDLE;
349                        else                           r_fsm_in[i] = INFSM_ALLOC;
350                    }
351                    break;
352                }
353                case INFSM_ALLOC:   // not a broadcast / output port allocated
354                {
355                    data_in[i]      = r_fifo_in[i].read();
356                    put_in[i]       = r_fifo_in[i].rok();
357                    req_in[i]       = REQ_NOP;                 // no request
358                    fifo_in_read[i] = (get_out[r_index_in[i].read()] == i);
359                    if ( r_fifo_in[i].read().eop and
360                         r_fifo_in[i].rok() and
361                         (get_out[r_index_in[i].read()] == i) ) // last flit transfered
362                    {
363                        r_fsm_in[i] = INFSM_IDLE;
364                    }
365                    break;
366                }
367                case INFSM_REQ_FIRST: // broacast / waiting first output port allocation
368                {
369                    data_in[i]    = r_buf_in[i];
370                    put_in[i]     = true;
371                    req_in[i]     = broadcast_route(1, i, r_buf_in[i].data);
372                    r_index_in[i] = req_in[i];
373                    if ( req_in[i] == REQ_NOP )   // no transfer for this step
374                    {
375                        r_fsm_in[i] = INFSM_REQ_SECOND;
376                    }
377                    else
378                    {
379                        if( get_out[req_in[i]] == i )  // header flit transfered
380                        {
381                            r_fsm_in[i] = INFSM_ALLOC_FIRST;
382                        }
383                    }
384                    break;
385                }
386                case INFSM_ALLOC_FIRST:  // broadcast / first output port allocated
387                {
388                    data_in[i] = r_fifo_in[i].read();
389                    put_in[i]  = r_fifo_in[i].rok();
390                    req_in[i]  = REQ_NOP;
391                    if( (get_out[r_index_in[i].read()] == i)
392                         and r_fifo_in[i].rok() )                 // data flit transfered
393                    {
394                        if ( not r_fifo_in[i].read().eop )
395                        {
396                            std::cout << "ERROR in DSPIN_ROUTER " << name()
397                                      << " : broadcast packet must be 2 flits" << std::endl;
398                        }
399                        r_fsm_in[i] = INFSM_REQ_SECOND;
400                    }
401                    break;
402                }
403                case INFSM_REQ_SECOND: // broacast / waiting second output port allocation
404                {
405                    data_in[i]    = r_buf_in[i];
406                    put_in[i]     = true;
407                    req_in[i]     = broadcast_route(2, i, r_buf_in[i].data);
408                    r_index_in[i] = req_in[i];
409                    if ( req_in[i] == REQ_NOP )  // no transfer for this step
410                    {
411                        r_fsm_in[i] = INFSM_REQ_THIRD;
412                    }
413                    else
414                    {
415                        if( get_out[req_in[i]] == i ) // header flit transfered
416                        {
417                            r_fsm_in[i] = INFSM_ALLOC_SECOND;
418                        }
419                    }
420                    break;
421                }
422                case INFSM_ALLOC_SECOND:  // broadcast / second output port allocated
423                {
424                    data_in[i] = r_fifo_in[i].read();
425                    put_in[i]  = r_fifo_in[i].rok();
426                    req_in[i]  = REQ_NOP;
427                    if( (get_out[r_index_in[i].read()] == i )
428                         and r_fifo_in[i].rok() )               // data flit transfered
429                    {
430                        if ( not r_fifo_in[i].read().eop )
431                        {
432                            std::cout << "ERROR in DSPIN_ROUTER " << name()
433                                      << " : broadcast packet must be 2 flits" << std::endl;
434                        }
435                        r_fsm_in[i] = INFSM_REQ_THIRD;
436                    }
437                    break;
438                }
439                case INFSM_REQ_THIRD: // broacast / waiting third output port allocation
440                {
441                    data_in[i]    = r_buf_in[i];
442                    put_in[i]     = true;
443                    req_in[i]     = broadcast_route(3, i, r_buf_in[i].data);
444                    r_index_in[i] = req_in[i];
445                    if ( req_in[i] == REQ_NOP )  // no transfer for this step
446                    {
447                        r_fsm_in[i] = INFSM_REQ_FOURTH;
448                    }
449                    else
450                    {
451                        if( get_out[req_in[i]] == i ) // header flit transfered
452                        {
453                            r_fsm_in[i] = INFSM_ALLOC_THIRD;
454                        }
455                    }
456                    break;
457                }
458                case INFSM_ALLOC_THIRD:  // broadcast / third output port allocated
459                {
460                    data_in[i] = r_fifo_in[i].read();
461                    put_in[i]  = r_fifo_in[i].rok();
462                    req_in[i]  = REQ_NOP;
463                    if( (get_out[r_index_in[i].read()] == i )
464                         and r_fifo_in[i].rok() )               // data flit transfered
465                    {
466                        if ( not r_fifo_in[i].read().eop )
467                        {
468                            std::cout << "ERROR in DSPIN_ROUTER " << name()
469                                      << " : broadcast packet must be 2 flits" << std::endl;
470                        }
471                        r_fsm_in[i] = INFSM_REQ_FOURTH;
472                    }
473                    break;
474                }
475                case INFSM_REQ_FOURTH: // broacast / waiting fourth output port allocation
476                {
477                    data_in[i]    = r_buf_in[i];
478                    put_in[i]     = true;
479                    req_in[i]     = broadcast_route(4, i, r_buf_in[i].data);
480                    r_index_in[i] = req_in[i];
481                    if ( req_in[i] == REQ_NOP )  // no transfer for this step
482                    {
483                        fifo_in_read[i] = true;
484                        r_fsm_in[i]     = INFSM_IDLE;
485                    }
486                    else
487                    {
488                        if( get_out[req_in[i]] == i )  // header flit transfered
489                        {
490                            r_fsm_in[i] = INFSM_ALLOC_FOURTH;
491                        }
492                    }
493                    break;
494                }
495                case INFSM_ALLOC_FOURTH:  // broadcast / fourth output port allocated
496                {
497                    data_in[i] = r_fifo_in[i].read();
498                    put_in[i]  = r_fifo_in[i].rok();
499                    req_in[i]  = REQ_NOP;
500                    if( (get_out[r_index_in[i].read()] == i )
501                         and r_fifo_in[i].rok() )                 // data flit transfered
502                    {
503                        if ( not r_fifo_in[i].read().eop )
504                        {
505                            std::cout << "ERROR in DSPIN_ROUTER " << name()
506                                      << " : broadcast packet must be 2 flits" << std::endl;
507                        }
508                        fifo_in_read[i] = true;
509                        r_fsm_in[i]     = INFSM_IDLE;
510                    }
511                    break;
512                }
513            } // end switch
514        } // end for input ports
515
516        // loop on the output ports :
517        // The r_alloc_out[j] and r_index_out[j] computation
518        // implements the round-robin allocation policy.
519        // These two registers implement a 10 states FSM.
520        for( size_t j = 0 ; j < 5 ; j++ )
521        {
522            if( not r_alloc_out[j].read() )  // not allocated: possible new allocation
523            {
524                for( size_t k = r_index_out[j].read() + 1 ;
525                     k < (r_index_out[j] + 6) ; k++)
526                {
527                    size_t i = k % 5;
528
529                    if( req_in[i] == j )
530                    {
531                        r_alloc_out[j] = true;
532                        r_index_out[j] = i;
533                        break;
534                    }
535                } // end loop on input ports
536            }
537            else                            // allocated: possible desallocation
538            {
539                if ( data_in[r_index_out[j]].eop and
540                     r_fifo_out[j].wok() and
541                     put_in[r_index_out[j]] )
542                {
543                    r_alloc_out[j] = false;
544                }
545            }
546        } // end loop on output ports
547
548        // loop on the output ports :
549        // The fifo_out_write[j] and fifo_out_wdata[j] computation
550        // implements the output port mux.
551        for( size_t j = 0 ; j < 5 ; j++ )
552        {
553            if( r_alloc_out[j] )  // output port allocated
554            {
555                fifo_out_write[j] = put_in[r_index_out[j]] &&
556                                    ((m_disable_mask & (1 << j)) == 0);
557                fifo_out_wdata[j] = data_in[r_index_out[j]];
558            }
559        }  // end loop on the output ports
560
561        //  FIFOS update
562        for(size_t i = 0 ; i < 5 ; i++)
563        {
564            r_fifo_in[i].update(fifo_in_read[i],
565                                fifo_in_write[i],
566                                fifo_in_wdata[i]);
567            r_fifo_out[i].update(fifo_out_read[i],
568                                 fifo_out_write[i],
569                                 fifo_out_wdata[i]);
570        }
571    } // end transition
572
573    ////////////////////////////////
574    //      genMoore
575    ////////////////////////////////
576    tmpl(void)::genMoore()
577    {
578        for(size_t i = 0 ; i < 5 ; i++)
579        {
580            // input ports : READ signals
581            p_in[i].read = r_fifo_in[i].wok();
582
583            // output ports : DATA & WRITE signals
584            p_out[i].data  = r_fifo_out[i].read().data;
585            p_out[i].eop   = r_fifo_out[i].read().eop;
586            p_out[i].write = r_fifo_out[i].rok();
587        }
588    } // end genMoore
589
590}} // end namespace
591
592// Local Variables:
593// tab-width: 4
594// c-basic-offset: 4
595// c-file-offsets:((innamespace . 0)(inline-open . 0))
596// indent-tabs-mode: nil
597// End:
598
599// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
Note: See TracBrowser for help on using the repository browser.