Index: soft/giet_vm/applications/gameoflife/gameoflife.c
===================================================================
--- soft/giet_vm/applications/gameoflife/main.c	(revision 669)
+++ soft/giet_vm/applications/gameoflife/gameoflife.c	(revision 708)
@@ -4,13 +4,22 @@
 // Authors :  Alexandre Joannou <alexandre.joannou@lip6.fr> november 2013
 //            Alain Greiner <alain.greiner@lip6.fr> february 2015
-//
+//////////////////////////////////////////////////////////////////////////////////
 // This multi-threaded application is an emulation of the Game of Life automaton.
 // The world size is defined by the HEIGHT and WIDTH parameters.
-// There is one task per processor.
-// Each task compute HEIGHT/nbprocs lines.
-// Task running on processor P(0,0,0) initialises the barrier, the TTY terminal,
-// and the chained buffer DMA controler.
 //
-// The number of processors must be a power of 2 not larger than HEIGHT.
+// There is at most one thread per processor in the platform.
+// - If the number of processors is larger than the number of lines,
+//   the number of threads is equal to the number of lines, and
+//   each thread process one single line. 
+// - if the number of processors is not larger than the number of lines,
+//   the number of threads is equal to the number of processors, and
+//   each thread process HEIGHT/nthreads (or HEIGHT/nthreads + 1) lines.
+// 
+// Thread running on processor P(0,0,0) execute the main() function,
+// that initialises the barrier, the TTY terminal, the CMA controler,
+// and launch the other threads, before calling the execute function.
+// Other threads are just running the execute() function.
+// 
+// The total number of processors cannot be larger than 1024 = 16 * 16 * 4
 //////////////////////////////////////////////////////////////////////////////////
 
@@ -20,16 +29,24 @@
 #include "mapping_info.h"
 #include "hard_config.h"
-
-#define WIDTH           128
-#define HEIGHT          128
-#define NB_ITERATION    1000000000
-
-#define PRINTF(...) ({ if ( proc_id==0) { giet_tty_printf(__VA_ARGS__); } })
+#include "malloc.h"
+
+#define WIDTH           FBUF_X_SIZE
+#define HEIGHT          FBUF_Y_SIZE
+
+#define VERBOSE         1
 
 typedef unsigned char uint8_t;
 
-uint8_t WORLD[2][HEIGHT][WIDTH] __attribute__((aligned(64)));
-
-uint8_t DISPLAY[2][HEIGHT][WIDTH] __attribute__((aligned(64)));
+typedef struct
+{
+    unsigned int    index;    // index of first line to be processed
+    unsigned int    lines;    // number of lines to be processed 
+}   arguments_t;
+
+arguments_t   args[1024];     // at most 1024 threads 
+
+uint8_t world[2][HEIGHT][WIDTH] __attribute__((aligned(64)));
+
+uint8_t display[2][HEIGHT][WIDTH] __attribute__((aligned(64)));
 
 unsigned int status0[16];
@@ -37,6 +54,4 @@
 
 giet_sqt_barrier_t barrier;
-
-volatile unsigned int init_ok;
 
 ////////////////////////////////////
@@ -50,5 +65,5 @@
       for(x = 0 ; x < WIDTH ; x++) 
       {
-         WORLD[phase][y][x] = (giet_rand() >> (x % 8)) & 0x1;
+         world[phase][y][x] = (giet_rand() >> (x % 8)) & 0x1;
       }
    }
@@ -62,12 +77,12 @@
    uint8_t nb = 0;
 
-   nb += WORLD[phase][(y - 1) % HEIGHT][(x - 1) % WIDTH];
-   nb += WORLD[phase][ y              ][(x - 1) % WIDTH];
-   nb += WORLD[phase][(y + 1) % HEIGHT][(x - 1) % WIDTH];
-   nb += WORLD[phase][(y - 1) % HEIGHT][ x             ];
-   nb += WORLD[phase][(y + 1) % HEIGHT][ x             ];
-   nb += WORLD[phase][(y - 1) % HEIGHT][(x + 1) % WIDTH];
-   nb += WORLD[phase][ y              ][(x + 1) % WIDTH];
-   nb += WORLD[phase][(y + 1) % HEIGHT][(x + 1) % WIDTH];
+   nb += world[phase][(y - 1) % HEIGHT][(x - 1) % WIDTH];
+   nb += world[phase][ y              ][(x - 1) % WIDTH];
+   nb += world[phase][(y + 1) % HEIGHT][(x - 1) % WIDTH];
+   nb += world[phase][(y - 1) % HEIGHT][ x             ];
+   nb += world[phase][(y + 1) % HEIGHT][ x             ];
+   nb += world[phase][(y - 1) % HEIGHT][(x + 1) % WIDTH];
+   nb += world[phase][ y              ][(x + 1) % WIDTH];
+   nb += world[phase][(y + 1) % HEIGHT][(x + 1) % WIDTH];
 
    return nb;
@@ -81,5 +96,5 @@
    uint8_t nb_neighbours_alive = number_of_alive_neighbour( phase, x , y );
 
-   if (WORLD[phase][y][x] == 1) 
+   if (world[phase][y][x] == 1) 
    {
       if (nb_neighbours_alive == 2 || nb_neighbours_alive == 3)  return 1;
@@ -88,5 +103,5 @@
    {
       if (nb_neighbours_alive == 3) return 1;
-      else                          return WORLD[phase][y][x];
+      else                          return world[phase][y][x];
    }
    return 0;
@@ -103,5 +118,5 @@
       for(x = 0; x < WIDTH ; x++) 
       {
-         WORLD[phase][y][x] = compute_cell( 1 - phase , x , y );  
+         world[phase][y][x] = compute_cell( 1 - phase , x , y );  
       }
    }
@@ -118,8 +133,78 @@
       for(x = 0; x < WIDTH ; x++) 
       {
-         DISPLAY[phase][y][x] = WORLD[phase][y][x]*255;  
-      }
-   }
-}
+         display[phase][y][x] = world[phase][y][x]*255;  
+      }
+   }
+}
+
+
+
+///////////////////////////////////////////////////////////////
+__attribute__((constructor)) void execute( arguments_t* pargs )
+///////////////////////////////////////////////////////////////
+{
+   unsigned int nb_lines      = pargs->lines;
+   unsigned int base_line     = pargs->index;
+
+   ///////////// parallel world  initialization 
+
+   // All processors initialize world[0]
+   init_world( 0 , base_line , nb_lines );
+
+   // copy world[0] to display[0]
+   copy_world( 0 , base_line , nb_lines );
+
+   // synchronise with other procs
+   sqt_barrier_wait( &barrier );
+
+   // main() makes display[0]
+   if ( base_line == 0 ) giet_fbf_cma_display ( 0 );
+
+   //////////// evolution : 2 steps per iteration 
+
+   unsigned int i = 0;
+   while( 1 )
+   {
+      // compute world[1] from world[0]
+      compute_new_gen( 1 , base_line , nb_lines );
+
+      // copy world[1] to display[1]
+      copy_world( 1 , base_line , nb_lines );
+
+      // synchronise with other procs
+      sqt_barrier_wait( &barrier );
+
+      // main makes display[1]
+      if ( base_line == 0 ) giet_fbf_cma_display ( 1 );
+   
+#if VERBOSE
+      if ( base_line == 0 ) giet_tty_printf(" - step %d\n", 2*i );
+#endif
+   
+      // compute world[0] from world[1]
+      compute_new_gen( 0 , base_line , nb_lines );
+
+      // copy world[0] to display[0]
+      copy_world( 0 , base_line , nb_lines );
+
+      // synchronise with other procs
+      sqt_barrier_wait( &barrier );
+
+      // main makes display[0]
+      if ( base_line == 0 ) giet_fbf_cma_display ( 0 );
+
+#if VERBOSE
+      if ( base_line == 0 ) giet_tty_printf(" - step %d\n", 2*i + 1 );
+#endif
+
+      i++;
+
+   } // end evolution loop
+
+   giet_pthread_exit("Completed");
+
+} // end main()
+
+
 
 ////////////////////////////////////////
@@ -133,5 +218,5 @@
    giet_proc_xyp( &x, &y, &p );
 
-   // get processors number
+   // get platform parameters
    unsigned int x_size;
    unsigned int y_size;
@@ -139,128 +224,105 @@
    giet_procs_number( &x_size, &y_size, &nprocs );
 
-   // compute continuous processor index & number of procs
-   unsigned int proc_id = (((x * y_size) + y) * nprocs) + p;  
-   unsigned int n_global_procs = x_size * y_size * nprocs; 
-
-   unsigned int i;
-
-   unsigned int nb_line       = HEIGHT / n_global_procs;
-   unsigned int base_line     = nb_line * proc_id; 
-   
-   // parameters checking
-   giet_assert( (n_global_procs <= HEIGHT),
-                " Number or processors larger than world height" );
-
-   giet_assert( ((WIDTH == FBUF_X_SIZE) && (HEIGHT == FBUF_Y_SIZE)),
-                "Frame Buffer size does not fit the world size" );
-   
-   giet_assert( ((x_size == 1) || (x_size == 2) || (x_size == 4) ||
-                 (x_size == 8) || (x_size == 16)),
-                "x_size must be a power of 2 no larger than 16" );
-
-   giet_assert( ((y_size == 1) || (y_size == 2) || (y_size == 4) ||
-                 (y_size == 8) || (y_size == 16)),
-                "y_size must be a power of 2 no larger than 16" );
-
-   giet_assert( ((nprocs == 1) || (nprocs == 2) || (nprocs == 4)), 
-                "nprocs must be a power of 2 no larger than 4" );
-
-   // P[0,0,0] makes initialisation
-   if ( proc_id == 0 )
-   {
-      // get a private TTY for P[0,0,0]
-      giet_tty_alloc( 0 );
-
-      // get a Chained Buffer DMA channel
-      giet_fbf_cma_alloc();
-
-      // initializes the source and destination buffers
-      giet_fbf_cma_init_buf( &DISPLAY[0][0][0] , 
-                             &DISPLAY[1][0][0] , 
-                             status0 ,
-                             status1 );
-
-      // activates CMA channel
-      giet_fbf_cma_start( HEIGHT * WIDTH );
-
-      // initializes distributed heap
-      unsigned int cx;
-      unsigned int cy;
-      for ( cx = 0 ; cx < x_size ; cx++ )
-      {
-         for ( cx = 0 ; cx < x_size ; cx++ )
-         {
-            heap_init( cx , cy );
-         }
-      }
-
-      // initialises barrier
-      sqt_barrier_init( &barrier , x_size , y_size , nprocs );
-
-      PRINTF("\n[GAMEOFLIFE] P[0,0,0] completes initialisation at cycle %d\n"
-             " nprocs = %d / nlines = %d\n", 
-             giet_proctime() , n_global_procs, HEIGHT );
-
-      // activates all other processors
-      init_ok = 1;
+   giet_pthread_assert( (x_size <= 16) , "x_size no larger than 16" );
+   giet_pthread_assert( (y_size <= 16) , "y_size no larger than 16" );
+   giet_pthread_assert( (nprocs <=  4) , "nprocs no larger than 16" );
+
+   // compute number of threads and min number of lines per thread
+   // extra is the number of threads that must process one extra line
+   unsigned int total_procs = x_size * y_size * nprocs; 
+   unsigned int nthreads;
+   unsigned int nlines;
+   unsigned int extra;
+   if ( total_procs > HEIGHT )
+   {
+      nthreads = HEIGHT;
+      nlines   = 1;
+      extra    = 0;
    }
    else
    {
-      while ( init_ok == 0 ) asm volatile("nop\n nop\n nop");
-   }
-
-   ///////////// world  initialization ( All processors )
-
-   // All processors initialize WORLD[0]
-   init_world( 0 , base_line , nb_line );
-
-   // copy WORLD[0] to DISPLAY[0]
-   copy_world( 0 , base_line , nb_line );
-
-   // synchronise with other procs
-   sqt_barrier_wait( &barrier );
-
-   // P(0,0,0) displays DISPLAY[0]
-   if ( proc_id == 0 ) giet_fbf_cma_display ( 0 );
-
-   PRINTF("\n[GAMEOFLIFE] starts evolution at cycle %d\n", giet_proctime() );
-   
-   //////////// evolution : 2 steps per iteration 
-
-   for (i = 0 ; i < NB_ITERATION ; i++)
-   {
-      // compute WORLD[1] from WORLD[0]
-      compute_new_gen( 1 , base_line , nb_line );
-
-      // copy WORLD[1] to DISPLAY[1]
-      copy_world( 1 , base_line , nb_line );
-
-      // synchronise with other procs
-      sqt_barrier_wait( &barrier );
-
-      // P(0,0,0) displays DISPLAY[1]
-      if ( proc_id == 0 ) giet_fbf_cma_display ( 1 );
-   
-      PRINTF(" - step %d\n", 2*i );
-   
-      // compute WORLD[0] from WORLD[1]
-      compute_new_gen( 0 , base_line , nb_line );
-
-      // copy WORLD[0] to DISPLAY[0]
-      copy_world( 0 , base_line , nb_line );
-
-      // synchronise with other procs
-      sqt_barrier_wait( &barrier );
-
-      // P(0,0,0) displays DISPLAY[0]
-      if ( proc_id == 0 ) giet_fbf_cma_display ( 0 );
-
-      PRINTF(" - step %d\n", 2*i + 1 );
-   } // end main loop
-
-   PRINTF("\n*** End of main at cycle %d ***\n", giet_proctime());
-
-   giet_exit("Completed");
+      nthreads = total_procs;
+      nlines   = HEIGHT / total_procs;
+      extra    = HEIGHT % total_procs;  
+   }
+
+   // get a shared TTY 
+   giet_tty_alloc( 1 );
+
+   // get a Chained Buffer DMA channel
+   giet_fbf_cma_alloc();
+
+   // initializes the source and destination buffers
+   giet_fbf_cma_init_buf( &display[0][0][0] , 
+                          &display[1][0][0] , 
+                          status0 ,
+                          status1 );
+
+   // activates CMA channel
+   giet_fbf_cma_start( HEIGHT * WIDTH );
+
+   // initializes distributed heap
+   unsigned int cx;
+   unsigned int cy;
+   for ( cx = 0 ; cx < x_size ; cx++ )
+   {
+      for ( cy = 0 ; cy < y_size ; cy++ )
+      {
+         heap_init( cx , cy );
+      }
+   }
+
+   // initialises barrier
+   sqt_barrier_init( &barrier , x_size , y_size , nprocs );
+
+   giet_tty_printf("\n[GAMEOFLIFE] P[%d,%d,%d] completes initialisation at cycle %d\n"
+                   " nprocs = %d / nlines = %d / nthreads = %d\n", 
+                   x, y, p, giet_proctime() , total_procs , HEIGHT , nthreads );
+
+   // compute arguments (index, nlines) for all threads
+   unsigned int n;                   // thread index
+   unsigned int index;               // first line index 
+   for ( n = 0 , index = 0 ; n < nthreads ; n++ )
+   {
+      if ( extra )
+      {
+         args[n].index = index;
+         args[n].lines = nlines + 1;
+         index         = index + nlines + 1;
+      }
+      else
+      {
+         args[n].index = index;
+         args[n].lines = nlines;
+         index         = index + nlines;
+      }
+#if VERBOSE      
+giet_tty_printf("[GAMEOFLIFE] Thread %d : first = %d / nlines = %d\n",
+                n , args[n].index , args[n].lines );
+#endif
+   }
+
+   // launch all other threads
+   pthread_t  trdid;                 // unused because no pthread_join()
+   for ( n = 1 ; n < nthreads ; n++ )
+   {
+      if ( giet_pthread_create( &trdid,
+                                NULL,                  // no attribute
+                                &execute,
+                                &args[n] ) )
+      {
+          giet_tty_printf("\n[TRANSPOSE ERROR] creating thread %x\n", n );
+          giet_pthread_exit( NULL );
+      }
+   }
+
+   // run execute function
+   execute( &args[0] );
+
+   giet_pthread_exit( "completed" );
+    
 } // end main()
+
+
 
 // Local Variables:
