Index: soft/giet_vm/applications/classif/main.c
===================================================================
--- soft/giet_vm/applications/classif/main.c	(revision 480)
+++ soft/giet_vm/applications/classif/main.c	(revision 488)
@@ -1,16 +1,30 @@
-/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
 // File   : main.c   (for classif application)
 // Date   : november 2014
 // author : Alain Greiner
-/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
 // This multi-threaded application takes a stream of Gigabit Ethernet packets,
 // and makes packet analysis and classification, based on the source MAC address.
-// It uses the NIC peripheral, and the distributed kernel chbuf filled by the CMA 
-// component to consume packets on the Gigabit Ethernet port. 
+// It uses the NIC peripheral, and the distributed kernel chbufs accessed by the CMA 
+// component to receive and send packets on the Gigabit Ethernet port. 
 //
 // This application is described as a TCG (Task and Communication Graph) containing
-// - one "load" task per cluster.
-// - from one to three "analyse" tasks per cluster.
-// In each cluster, the "load" task communicates with the local "analyse" tasks through 
+// (N+2) tasks per cluster:
+// - one "load" task
+// - N "analyse" tasks
+// - one "store" task
+// The 4 Kbytes containers are diributed (N+2 containers per cluster):
+// - one RX container (part of the kernel rx_chbuf), in the kernel heap.
+// - one TX container (part of the kernel tx-chbuf), in the kernel heap.
+// - N working containers (one per analysis task), in the user heap.
+// In each cluster, the "load", analysis" and "store" tasks communicates through
+// three local MWMR fifos: 
+// - fifo_l2a : tranfer a full container from "load" to "analyse" task.
+// - fifo_a2s : transfer a full container from "analyse" to "store" task.
+// - fifo_s2l : transfer an empty container from "store" to "load" task.
+// For each fifo, one item is a 32 bits word defining the index of an
+// available working container.
+// The pointers on the working containers, and the pointers on the MWMR fifos
+// are global arrays stored in cluster[0][0].
 // a local MWMR fifo containing NB_PROCS_MAX containers (one item = one container).
 // The MWMR fifo descriptors array is defined as a global variable in cluster[0][0]. 
@@ -20,25 +34,33 @@
 //   the barrier between all "load" tasks. Other "load" tasks are waiting on the
 //   global_sync synchronisation variable.
-// - In each cluster[x][y], the "load" task allocates the MWMR fifo descriptor and
-//   the data buffer in the local heap, and initializes the MWMR descriptor.
+// - In each cluster[x][y], the "load" task allocates the working containers
+//   and the MWMR fifos descriptors in the local heap.
 //   The "analyse" tasks are waiting on the sync[x][y] variables.
+//
+// Instrumentation results display is done by the "store" task in cluster[0][0]
+// when all "store" tasks completed the number of clusters specified by the
+// CONTAINERS_MAX parameter.
 //     
-// When initialisation is completed, all "load and "analyse" tasks loop on containers:
-// 1) The "load" task transfer containers from the kernel chbuf associated to the
-//    NIC_RX channel (in cluster[0][0]), to the local MWMR fifo (in cluster[x][y]),
-//    after an in termediate copy in a private stack buffer. 
-//    Each "load" task loads CONTAINERS_MAX containers before exit, and the
-//    task in cluster[0,0] displays the results stored in global counters filled
-//    by the "analyse" tasks when all "load" tasks reach the barrier.
+// When initialisation is completed, all tasks loop on containers:
+// 1) The "load" task get an empty working container from the fifo_s2l,
+//    transfer one container from the kernel rx_chbuf to this user container,
+//    and transfer ownership of this container to one "analysis" task by writing
+//    into the fifo_l2a.    
 //
-// 2) The "analyse" task transfer one container from the local MWMR fifo to a private
-//    local buffer. It analyse each packet contained in the container, compute the
-//    packet type, depending on the source MAC address, and increment the counters.
+// 2) The "analyse" task get one working container from the fifo_l2a, analyse
+//    each packet header, compute the packet type (depending on the SRC MAC address),
+//    increment the correspondint classification counter, and transpose the SRC
+//    and the DST MAC addresses fot TX tranmission.
 //
-// It uses the he following hardware parameters, defined in the hard_config.h file:
+// 3) The "store" task transfer get a full working container from the fifo_a2s,
+//    transfer this user container content to the the kernel tx_chbuf,
+//    and transfer ownership of this empty container to the "load" task by writing
+//    into the fifo_s2l.   
+//
+// This application uses the following hardware parameters (hard_config.h file):
 // - X_SIZE       : number of clusters in a row
 // - Y_SIZE       : number of clusters in a column
 // - NB_PROCS_MAX : number of processors per cluster
-/////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
 
 #include "stdio.h"
@@ -49,27 +71,176 @@
 #include "hard_config.h"
 
-#define CONTAINERS_MAX   10
-
-///////////////////////////////////////////////////////////////////////////////////////////
+#define CONTAINERS_MAX  5
+#define VERBOSE_ANALYSE 1
+#define ANALYSIS_TASKS  (NB_PROCS_MAX - 2)
+
+/////////////////////////////////////////////////////////////////////////////////////////
 //    Global variables
-// The MWMR channels (descriptors and buffers) are distributed in the clusters, 
-// but the pointers array is stored in cluster[0][0]
-///////////////////////////////////////////////////////////////////////////////////////////
-
-mwmr_channel_t*  mwmr[X_SIZE][Y_SIZE];        // distributed MWMR fifos pointers
-
-unsigned int     local_sync[X_SIZE][Y_SIZE];  // distributed synchros "load" / "analyse"
-
-unsigned int     global_sync = 0;             // global synchro between "load" tasks
-
-unsigned int     count[16];                   // instrumentation counters
-
-giet_barrier_t   barrier;                     // barrier between "load" (instrumentation)
-
-unsigned int     nic_channel;                 // allocated NIC channel index
+// The MWMR channels (descriptors and buffers), as well as the working containers 
+// used by the "analysis" tasks are distributed in clusters.
+// But the pointers on these distributed structures are shared arrays
+// stored in cluster[0][0].
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// pointers on distributed temp[x][y][n] containers
+unsigned int*       container[X_SIZE][Y_SIZE][ANALYSIS_TASKS];  
+
+// pointers on distributed mwmr fifos containing : temp[x][y][l] container descriptors
+mwmr_channel_t*     mwmr_l2a[X_SIZE][Y_SIZE];  
+mwmr_channel_t*     mwmr_a2s[X_SIZE][Y_SIZE];
+mwmr_channel_t*     mwmr_s2l[X_SIZE][Y_SIZE]; 
+
+// local synchros signaling local MWMR fifos initialisation completion
+unsigned int        local_sync[X_SIZE][Y_SIZE];  
+
+// global synchro signaling global initialisation completion
+unsigned int        load_sync  = 0; 
+unsigned int        store_sync = 0; 
+
+// instrumentation counters
+unsigned int        counter[16];
+
+// distributed barriers (between "load" and "store" tasks)
+giet_sbt_barrier_t  rx_barrier;
+giet_sbt_barrier_t  tx_barrier;
+
+// NIC_RX and NIC_TX channel index
+unsigned int        nic_rx_channel;
+unsigned int        nic_tx_channel;
 
 /////////////////////////////////////////
 __attribute__ ((constructor)) void load()
 /////////////////////////////////////////
+{
+    // each "load" task get processor identifiers
+    unsigned int    x;
+    unsigned int    y;
+    unsigned int    l;
+    giet_proc_xyp( &x, &y, &l );
+
+    // "load" task[0][0] initialises barrier between load tasks,
+    // allocates the NIC & CMA RX channels, and start the NIC_CMA RX transfer.
+    // Other "load" tasks wait completion
+    if ( (x==0) && (y==0) )
+    {
+        giet_shr_printf("\n*** Task load on P[%d][%d][%d] starts at cycle %d\n",
+                        x , y , l , giet_proctime() );
+ 
+        sbt_barrier_init( &rx_barrier, X_SIZE*Y_SIZE , 1 );
+        nic_rx_channel = giet_nic_rx_alloc();
+        giet_nic_rx_start( nic_rx_channel );
+        load_sync = 1;
+    }
+    else
+    {
+        while ( load_sync == 0 ) asm volatile ("nop");
+    }    
+
+    // all load tasks allocate containers[x][y][n] (from local heap)
+    // and register pointers in the local stack
+    unsigned int   n;
+    unsigned int*  cont[ANALYSIS_TASKS]; 
+
+    for ( n = 0 ; n < ANALYSIS_TASKS ; n++ )
+    {
+        container[x][y][n] = malloc( 4096 );
+        cont[n]            = container[x][y][n];
+    }
+    
+    // all load tasks allocate data buffers for mwmr fifos (from local heap)
+    unsigned int*  data_l2a = malloc( ANALYSIS_TASKS<<2 );
+    unsigned int*  data_a2s = malloc( ANALYSIS_TASKS<<2 );
+    unsigned int*  data_s2l = malloc( ANALYSIS_TASKS<<2 );
+
+    // all load tasks allocate mwmr fifos descriptors (from local heap)
+    mwmr_l2a[x][y] = malloc( sizeof(mwmr_channel_t) );
+    mwmr_a2s[x][y] = malloc( sizeof(mwmr_channel_t) );
+    mwmr_s2l[x][y] = malloc( sizeof(mwmr_channel_t) );
+
+    // all "load" tasks register local pointers on mwmr fifos in local stack
+    mwmr_channel_t* fifo_l2a = mwmr_l2a[x][y];
+    mwmr_channel_t* fifo_a2s = mwmr_a2s[x][y];
+    mwmr_channel_t* fifo_s2l = mwmr_s2l[x][y];
+
+    // all "load" tasks initialise local mwmr fifos descriptors
+    // ( width = 4 bytes / depth = number of analysis tasks )
+    mwmr_init( fifo_l2a , data_l2a , 1 , ANALYSIS_TASKS );
+    mwmr_init( fifo_a2s , data_a2s , 1 , ANALYSIS_TASKS );
+    mwmr_init( fifo_s2l , data_s2l , 1 , ANALYSIS_TASKS );
+
+    
+    // all "load" tasks initialise local containers as empty in fifo_s2l
+    for ( n = 0 ; n < ANALYSIS_TASKS ; n++ ) mwmr_write( fifo_s2l , &n , 1 );
+
+    // each "load" task[x][y] signals mwmr fifos initialisation completion
+    // to other tasks in same cluster[x][y]
+    local_sync[x][y] = 1;
+
+    // "load" task[0][0] displays status
+    if ( (x==0) && (y==0) )
+    giet_shr_printf("\n*** Task load on P[%d,%d,%d] enters main loop at cycle %d\n"
+                    "      nic_rx_channel = %d / nic_tx_channel = %d\n"
+                    "      &mwmr_l2a  = %x / &data_l2a  = %x\n"
+                    "      &mwmr_a2s  = %x / &data_a2s  = %x\n"
+                    "      &mwmr_s2l  = %x / &data_s2l  = %x\n"
+                    "      &cont[0]   = %x\n"
+                    "      x_size = %d / y_size = %d / nprocs = %d\n",
+                    x , y , l , giet_proctime(), 
+                    nic_rx_channel , nic_tx_channel,
+                    (unsigned int)fifo_l2a, (unsigned int)data_l2a,
+                    (unsigned int)fifo_a2s, (unsigned int)data_a2s,
+                    (unsigned int)fifo_s2l, (unsigned int)data_s2l,
+                    (unsigned int)cont[0],
+                    X_SIZE, Y_SIZE, NB_PROCS_MAX );
+ 
+    /////////////////////////////////////////////////////////////
+    // All "load" tasks enter the main loop (on containers)
+    unsigned int count = 0;     // loaded containers count
+    unsigned int index;         // available container index
+    unsigned int* temp;         // pointer on available container
+
+    while ( count < CONTAINERS_MAX ) 
+    { 
+        // get one empty count index from fifo_s2l
+        mwmr_read( fifo_s2l , &index , 1 );
+        temp = cont[index];
+
+        // get one count from  kernel rx_chbuf
+        giet_nic_rx_move( nic_rx_channel, temp );
+
+        // get packets number
+        unsigned int npackets = temp[0] & 0x0000FFFF;
+        unsigned int nwords   = temp[0] >> 16;
+
+        if ( (x==X_SIZE-1) && (y==Y_SIZE-1) )
+        giet_shr_printf("\n*** Task load on P[%d,%d,%d] get container %d at cycle %d"
+                        " : %d packets / %d words\n",
+                        x, y, l, count, giet_proctime(), npackets, nwords );
+
+        // put the full count index to fifo_l2a
+        mwmr_write( fifo_l2a, &index , 1 );
+
+        count++;
+    }
+
+    // all "load" tasks synchronise before stats
+    sbt_barrier_wait( &rx_barrier );
+
+    // "load" task[0][0] stops the NIC_CMA RX transfer and displays stats
+    if ( (x==0) && (y==0) ) 
+    {
+        giet_nic_rx_stop( nic_rx_channel );
+        giet_nic_rx_stats( nic_rx_channel );
+    }
+
+    // all "load" task exit
+    giet_exit("Task completed");
+ 
+} // end load()
+
+
+//////////////////////////////////////////
+__attribute__ ((constructor)) void store()
+//////////////////////////////////////////
 {
     // get processor identifiers
@@ -79,57 +250,67 @@
     giet_proc_xyp( &x, &y, &l );
 
-    // local buffer to store one container in private stack
-    unsigned int  temp[1024];
-
-    // allocates data buffer for MWMR fifo in local heap
-    unsigned int*  data = malloc( NB_PROCS_MAX<<12 );
-
-    // allocates MWMR fifo descriptor in local heap
-    mwmr[x][y] = malloc( sizeof(mwmr_channel_t) );
-    mwmr_channel_t* fifo = mwmr[x][y];
-
-    // initialises local MWMR fifo : width = 4kbytes / depth = NB_PROCS_MAX
-    mwmr_init( fifo , data , 1024 , NB_PROCS_MAX );
-
-    // display for cluster[X_SIZE-1][Y_SIZE-1]
-    if ( (x==X_SIZE-1) && (y==Y_SIZE-1) )
-    giet_shr_printf("\n*** Task load starts on P[%d,%d,%d] at cycle %d\n"
-                    "      &mwmr  = %x / &data  = %x / &sync  = %x\n"
-                    "      x_size = %d / y_size = %d / nprocs = %d\n",
-                    x , y , l , giet_proctime() , 
-                    (unsigned int)fifo, (unsigned int)data, (unsigned int)(&local_sync[x][y]),
-                    X_SIZE, Y_SIZE, NB_PROCS_MAX ); 
-
-    // Task load on cluster[0,0] makes global initialisation:
-    // - NIC & CMA channels allocation & initialisation.
-    // - barrier for load tasks initialisation.
-    // Other load task wait completion.
-    if ( (x==0) && (y==0) )
-    {
-        // get NIC_RX channel 
-        nic_channel = giet_nic_rx_alloc();
-
-        // start CMA transfer
-        giet_nic_rx_start();
-
-        // barrier init
-        barrier_init( &barrier, X_SIZE * Y_SIZE );
-
-        global_sync = 1;
+
+    // "store" task[0][0] initialises the barrier between all "store" tasks,
+    // allocates NIC & CMA TX channels, and starts the NIC_CMA TX transfer.
+    // Other "store" tasks wait completion.
+    if ( (x==0) && (y==0) )
+    {
+        giet_shr_printf("\n*** Task store on P[%d][%d][%d] starts at cycle %d\n",
+                        x , y , l , giet_proctime() );
+ 
+        sbt_barrier_init( &tx_barrier , X_SIZE*Y_SIZE , 1 );
+        nic_tx_channel = giet_nic_tx_alloc();
+        giet_nic_tx_start( nic_tx_channel );
+        store_sync = 1;
     }
     else
     {
-        while ( global_sync == 0 ) asm volatile ("nop");
+        while ( store_sync == 0 ) asm volatile ("nop");
     }    
 
-    // "load" task signals MWMR initialisation to "analyse" tasks
-    local_sync[x][y] = 1;
-
-    // main loop (on containers)
-    unsigned int container = 0;
-    while ( container < CONTAINERS_MAX ) 
+    // all "store" tasks wait mwmr channels initialisation
+    while ( local_sync[x][y] == 0 ) asm volatile ("nop");
+
+    // all "store" tasks register pointers on working containers in local stack
+    unsigned int   n;
+    unsigned int*  cont[ANALYSIS_TASKS]; 
+    for ( n = 0 ; n < ANALYSIS_TASKS ; n++ )
+    {
+        cont[n] = container[x][y][n];
+    }
+    
+    // all "store" tasks register pointers on mwmr fifos in local stack
+    mwmr_channel_t* fifo_l2a = mwmr_l2a[x][y];
+    mwmr_channel_t* fifo_a2s = mwmr_a2s[x][y];
+    mwmr_channel_t* fifo_s2l = mwmr_s2l[x][y];
+
+    // "store" task[0][0] displays status
+    if ( (x==0) && (y==0) )
+    giet_shr_printf("\n*** Task store on P[%d,%d,%d] enters main loop at cycle %d\n"
+                    "      &mwmr_l2a  = %x\n"
+                    "      &mwmr_a2s  = %x\n"
+                    "      &mwmr_s2l  = %x\n"
+                    "      &cont[0]   = %x\n",
+                    x , y , l , giet_proctime(), 
+                    (unsigned int)fifo_l2a,
+                    (unsigned int)fifo_a2s,
+                    (unsigned int)fifo_s2l,
+                    (unsigned int)cont[0] );
+
+
+    /////////////////////////////////////////////////////////////
+    // all "store" tasks enter the main loop (on containers)
+    unsigned int count = 0;     // stored containers count
+    unsigned int index;         // empty container index
+    unsigned int* temp;         // pointer on empty container
+
+    while ( count < CONTAINERS_MAX ) 
     { 
-        // get one container from kernel chbuf
-        giet_nic_rx_move( nic_channel, temp );
+        // get one working container index from fifo_a2s
+        mwmr_read( fifo_a2s , &index , 1 );
+        temp = cont[index];
+
+        // put one container to  kernel tx_chbuf
+        giet_nic_tx_move( nic_tx_channel, temp );
 
         // get packets number
@@ -138,21 +319,21 @@
 
         if ( (x==X_SIZE-1) && (y==Y_SIZE-1) )
-        giet_shr_printf("\nTask load on P[%d,%d,%d] get container %d at cycle %d"
+        giet_shr_printf("\n*** Task store on P[%d,%d,%d] get container %d at cycle %d"
                         " : %d packets / %d words\n",
-                        x, y, l, container, giet_proctime(), npackets, nwords );
-
-        // put container to MWMR channel
-        mwmr_write( fifo, temp, 1 );
-
-        container++;
-    }
-
-    // all load tasks synchronise before result display
-    barrier_wait( &barrier );
-
-    // Task load in cluster[0,0] stops NIC and displays results 
-    if ( (x==0) && (y==0) )
-    {
-        giet_nic_rx_stop();
+                        x, y, l, count, giet_proctime(), npackets, nwords );
+
+        // put the working container index to fifo_s2l
+        mwmr_write( fifo_s2l, &index , 1 );
+
+        count++;
+    }
+
+    // all "store" tasks synchronise before result display
+    sbt_barrier_wait( &tx_barrier );
+
+    // "store" task[0,0] stops NIC_CMA TX transfer and displays results 
+    if ( (x==0) && (y==0) )
+    {
+        giet_nic_tx_stop( nic_tx_channel );
 
         giet_shr_printf("\n@@@@ Classification Results @@@\n"
@@ -172,20 +353,23 @@
                         " - TYPE D : %d packets\n"
                         " - TYPE E : %d packets\n"
-                        " - TYPE F : %d packets\n",
-                        count[0x0], count[0x1], count[0x2], count[0x3],
-                        count[0x4], count[0x5], count[0x6], count[0x7],
-                        count[0x8], count[0x9], count[0xA], count[0xB],
-                        count[0xC], count[0xD], count[0xE], count[0xF] );
-
-        giet_nic_rx_stats();
-
-    }
-
-    // all load tasks synchronise before exit
-    barrier_wait( &barrier );
-
+                        " - TYPE F : %d packets\n"
+                        "    TOTAL = %d packets\n",
+                        counter[0x0], counter[0x1], counter[0x2], counter[0x3],
+                        counter[0x4], counter[0x5], counter[0x6], counter[0x7],
+                        counter[0x8], counter[0x9], counter[0xA], counter[0xB],
+                        counter[0xC], counter[0xD], counter[0xE], counter[0xF],
+                        counter[0x0]+ counter[0x1]+ counter[0x2]+ counter[0x3]+
+                        counter[0x4]+ counter[0x5]+ counter[0x6]+ counter[0x7]+
+                        counter[0x8]+ counter[0x9]+ counter[0xA]+ counter[0xB]+
+                        counter[0xC]+ counter[0xD]+ counter[0xE]+ counter[0xF] );
+
+        giet_nic_tx_stats( nic_tx_channel );
+    }
+
+    // all "store" task exit
     giet_exit("Task completed");
- 
-} // end load()
+
+} // end store()
+
 
 ////////////////////////////////////////////
@@ -199,43 +383,79 @@
     giet_proc_xyp( &x, &y, &l );
 
-    // local buffer to store one container
-    unsigned int  temp[1024];
-
-    // wait MWMR channel initialisation (done by task load)
+    if ( (x==0) && (y==0) )
+    {
+        giet_shr_printf("\n*** Task analyse on P[%d][%d][%d] starts at cycle %d\n",
+                        x , y , l , giet_proctime() );
+    }
+ 
+    // all "analyse" tasks wait mwmr channels initialisation
     while ( local_sync[x][y] == 0 ) asm volatile ("nop");
 
-    // get pointer on MWMR channel descriptor 
-    mwmr_channel_t* fifo = mwmr[x][y];
-
-    // display status for cluster[X_SIZE-1][Y_SIZE-1]
-    if ( (x==X_SIZE-1) && (y==Y_SIZE-1) )
-    giet_shr_printf("\n*** Task analyse starts on P[%d,%d,%d] at cycle %d\n"
-                    "       &mwmr = %x / &sync = %x\n",
+    // all "analyse" tasks register pointers on working containers in local stack
+    unsigned int   n;
+    unsigned int*  cont[ANALYSIS_TASKS]; 
+    for ( n = 0 ; n < ANALYSIS_TASKS ; n++ )
+    {
+        cont[n] = container[x][y][n];
+    }
+
+    // all "analyse" tasks register pointers on mwmr fifos in local stack
+    mwmr_channel_t* fifo_l2a = mwmr_l2a[x][y];
+    mwmr_channel_t* fifo_a2s = mwmr_a2s[x][y];
+
+    // "analyse" task[0][0] display status
+    if ( (x==0) && (y==0) )
+    giet_shr_printf("\n*** Task analyse on P[%d,%d,%d] enters main loop at cycle %d\n"
+                    "       &mwmr_l2a = %x\n"
+                    "       &mwmr_a2s = %x\n"
+                    "       &cont[0]  = %x\n",
                     x, y, l, giet_proctime(), 
-                    (unsigned int)fifo, (unsigned int)(&local_sync[x][y]) );
-    
-    // main loop (on containers)
-    unsigned int nwords;     // number of words in container
-    unsigned int npackets;   // number of packets in container
-    unsigned int length;     // number of bytes in current packet
-    unsigned int word;       // current packet first word in container
-    unsigned int type;       // current packet type
-    unsigned int p;          // current packet index
+                    (unsigned int)fifo_l2a,
+                    (unsigned int)fifo_a2s,
+                    (unsigned int)cont[0] );
+      
+    /////////////////////////////////////////////////////////////
+    // all "analyse" tasks enter the main loop (on containers)
+    unsigned int  index;           // available container index
+    unsigned int* temp;            // pointer on available container
+    unsigned int  nwords;          // number of words in container
+    unsigned int  npackets;        // number of packets in container
+    unsigned int  length;          // number of bytes in current packet
+    unsigned int  first;           // current packet first word in container
+    unsigned int  type;            // current packet type
+    unsigned int  p;               // current packet index
+
+#if VERBOSE_ANALYSE
+    unsigned int       verbose_len[10]; // save length for all packets in one container
+    unsigned long long verbose_dst[10]; // save length for all packets in one container
+    unsigned long long verbose_src[10]; // save length for all packets in one container
+#endif
+
     while ( 1 )
     { 
-        // get one container from MWMR fifo
-        mwmr_read( fifo, temp, 1 );
-
-        // get packets number
+
+#if VERBOSE_ANALYSE 
+            for( p = 0 ; p < 10 ; p++ )
+            {
+                verbose_len[p] = 0;
+                verbose_dst[p] = 0;
+                verbose_src[p] = 0;
+            }
+#endif
+        // get one working container index from fifo_l2a
+        mwmr_read( fifo_l2a , &index , 1 );
+        temp = cont[index];
+
+        // get packets number and words number
         npackets = temp[0] & 0x0000FFFF;
         nwords   = temp[0] >> 16;
 
-        if ( (x==X_SIZE-1) && (y==Y_SIZE-1) )
-        giet_shr_printf("\nTask analyse on P[%d,%d,%d] get container at cycle %d"
+        if ( (x==0) && (y==0) )
+        giet_shr_printf("\n*** Task analyse on P[%d,%d,%d] get container at cycle %d"
                         " : %d packets / %d words\n",
 						x, y, l, giet_proctime(), npackets, nwords );
 
         // initialize word index in container
-        word = 34;
+        first = 34;
 
         // loop on packets
@@ -246,14 +466,66 @@
             else                   length = temp[1+(p>>1)] & 0x0000FFFF;
 
-            // get packet type (source mac address)
-            type = (temp[word+1] & 0x0000000F);
-
-            // increment counter
-            atomic_increment( &count[type], 1 );
-
-            // update word index 
-            if ( length & 0x3 ) word += (length>>2)+1;
-            else                word += (length>>2);
+            // compute packet DST and SRC MAC addresses
+            unsigned int word0 = temp[first];
+            unsigned int word1 = temp[first + 1];
+            unsigned int word2 = temp[first + 2];
+
+            unsigned long long dst = ((unsigned long long)(word1 & 0xFFFF0000)>>16) |
+                                     (((unsigned long long)word0)<<16);
+            unsigned long long src = ((unsigned long long)(word1 & 0x0000FFFF)<<32) |
+                                     ((unsigned long long)word2);
+#if VERBOSE_ANALYSE 
+            if ( p < 10 )
+            {
+                verbose_len[p] = length;
+                verbose_dst[p] = dst;
+                verbose_src[p] = src;
+            }
+#endif
+            // compute type from SRC MAC address and increment counter
+            type = word1 & 0x0000000F;
+            atomic_increment( &counter[type], 1 );
+
+            // exchange SRC & DST MAC addresses for TX
+            temp[first]     = ((word1 & 0x0000FFFF)<<16) | ((word2 & 0xFFFF0000)>>16);
+            temp[first + 1] = ((word2 & 0x0000FFFF)<<16) | ((word0 & 0xFFFF0000)>>16);
+            temp[first + 2] = ((word0 & 0x0000FFFF)<<16) | ((word1 & 0xFFFF0000)>>16);
+
+            // update first word index 
+            if ( length & 0x3 ) first += (length>>2)+1;
+            else                first += (length>>2);
         }
+        
+#if VERBOSE_ANALYSE 
+        if ( (x==0) && (y==0) )
+        giet_shr_printf("\n*** Task analyse on P[%d,%d,%d] completes at cycle %d\n"
+                        "   - Packet 0 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 1 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 2 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 3 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 4 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 5 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 6 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 7 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 8 : plen = %d / dst_mac = %l / src_mac = %l\n"
+                        "   - Packet 9 : plen = %d / dst_mac = %l / src_mac = %l\n",
+                        x , y , l , giet_proctime() , 
+                        verbose_len[0] , verbose_dst[0] , verbose_src[0] ,
+                        verbose_len[1] , verbose_dst[1] , verbose_src[1] ,
+                        verbose_len[2] , verbose_dst[2] , verbose_src[2] ,
+                        verbose_len[3] , verbose_dst[3] , verbose_src[3] ,
+                        verbose_len[4] , verbose_dst[4] , verbose_src[4] ,
+                        verbose_len[5] , verbose_dst[5] , verbose_src[5] ,
+                        verbose_len[6] , verbose_dst[6] , verbose_src[6] ,
+                        verbose_len[7] , verbose_dst[7] , verbose_src[7] ,
+                        verbose_len[8] , verbose_dst[8] , verbose_src[8] ,
+                        verbose_len[9] , verbose_dst[9] , verbose_src[9] );
+#endif
+            
+        // pseudo-random delay
+        for( p = 0 ; p < (giet_rand()>>4) ; p++ ) asm volatile ("nop");
+
+        // put the working container index to fifo_a2s
+        mwmr_write( fifo_a2s , &index , 1 );
     }
 } // end analyse()
