Index: soft/giet_vm/giet_boot/boot.c
===================================================================
--- soft/giet_vm/giet_boot/boot.c	(revision 490)
+++ soft/giet_vm/giet_boot/boot.c	(revision 493)
@@ -1,21 +1,24 @@
-/////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
 // File     : boot.c
 // Date     : 01/11/2013
 // Author   : alain greiner
 // Copyright (c) UPMC-LIP6
-//////////////////////////////////////////////////////////////////////////////////////////
-// The boot.c file is part of the GIET-VM nano-kernel.
+///////////////////////////////////////////////////////////////////////////////////////
+// The boot.c file contains the bootloader for the GIET-VM static OS.  
 //
-// This nano-kernel has been written for the MIPS32 processor.
+// This code has been written for the MIPS32 processor.
 // The virtual adresses are on 32 bits and use the (unsigned int) type. The 
 // physicals addresses can have up to 40 bits, and use the  (unsigned long long) type.
 // It natively supports clusterised shared memory multi-processors architectures, 
-// where each processor is identified by a composite index (cluster_xy, local_id),
+// where each processor is identified by a composite index [x,y,p],
 // and where there is one physical memory bank per cluster.
 //
-// This code, executed in the boot phase by proc[0,0,0], performs the following tasks:
-// - load into memory various binary files, from a FAT32 file system,
-// - build the various page tables (one page table per vspace) 
-// - initialize the shedulers (one scheduler per processor)
+// The boot.elf file is stored on disk and is loaded into memory by proc[0,0,0],
+// executing the generic preloader (stored in ROM). The boot-loader code itself
+// is executed in parallel by all proc[x,y,0], and performs the following tasks:
+// - load into memory various binary files, from a FAT32 file system.
+// - build the various page tables (one page table per vspace). 
+// - initialize the shedulers (one scheduler per processor).
+// - initialize the external peripherals.
 //
 // 1) The binary files to be loaded are:
@@ -23,8 +26,8 @@
 //      mapping directives. It must be stored in the the seg_boot_mapping segment 
 //      (at address SEG_BOOT_MAPPING_BASE defined in hard_config.h file).
-//    - the "sys.elf" file contains the kernel binary code and data.
+//    - the "kernel.elf" file contains the kernel binary code and data.
 //    - the various "application.elf" files.
 //
-// 2) The map.bin file contains the binary representation of the map.xml file defining: 
+// 2) The "map.bin" file contains the C binary structure defining: 
 //    - the hardware architecture: number of clusters, number or processors, 
 //      size of the memory segments, and peripherals in each cluster.
@@ -41,5 +44,6 @@
 //      of the software objects (vsegs) on the physical memory banks (psegs).
 //
-//    The max number of vspaces (GIET_NB_VSPACE_MAX) is a configuration parameter.
+//    The max number of vspaces (GIET_NB_VSPACE_MAX) is a configuration parameter,
+//    and - for each application - the tasks are statically allocateded on procesors.
 //    The page table are statically build in the boot phase, and they do not 
 //    change during execution. 
@@ -52,13 +56,13 @@
 //    A PT2 is indexed the ix2 field (9 bits) of the VPN. Each entry is a double word. 
 //    The first word contains the flags, the second word contains the PPN.
-//
-//    When this is required in the mapping, the page tables can be replicated 
-//    in all clusters.
+//    The page tables are distributed/replicated in all clusters.
 ///////////////////////////////////////////////////////////////////////////////////////
 // Implementation Notes:
 //
 // 1) The cluster_id variable is a linear index in the mapping_info array of clusters. 
-//    We use the cluster_xy variable for the tological index = x << Y_WIDTH + y
+//    The cluster_xy variable is the tological index = x << Y_WIDTH + y
 // 
+// 2) We set the _tty0_boot_mode variable to force the _printf() function to use
+//    the tty0_spin_lock for exclusive access to TTY0.
 ///////////////////////////////////////////////////////////////////////////////////////
 
@@ -67,5 +71,4 @@
 #include <mapping_info.h>
 #include <kernel_malloc.h>
-#include <barrier.h>
 #include <memspace.h>
 #include <tty_driver.h>
@@ -86,5 +89,6 @@
 #include <utils.h>
 #include <tty0.h>
-#include <locks.h>
+#include <kernel_locks.h>
+#include <kernel_barriers.h>
 #include <elf-types.h>
 #include <fat32.h>
@@ -131,80 +135,56 @@
 
 // FAT internal representation for boot code  
-__attribute__((section (".bootdata"))) 
-fat32_fs_t             fat   __attribute__((aligned(512)));
+__attribute__((section(".kdata")))
+fat32_fs_t          fat   __attribute__((aligned(512)));
 
 // Temporaty buffer used to load one complete .elf file  
-__attribute__((section (".bootdata"))) 
-char                   boot_elf_buffer[GIET_ELF_BUFFER_SIZE] __attribute__((aligned(512)));
+__attribute__((section(".kdata")))
+char                boot_elf_buffer[GIET_ELF_BUFFER_SIZE] __attribute__((aligned(512)));
 
 // Physical memory allocators array (one per cluster)
-__attribute__((section (".bootdata"))) 
-pmem_alloc_t           boot_pmem_alloc[X_SIZE][Y_SIZE];
+__attribute__((section(".kdata")))
+pmem_alloc_t        boot_pmem_alloc[X_SIZE][Y_SIZE];
 
 // Distributed kernel heap (one per cluster)
-__attribute__((section (".bootdata"))) 
-kernel_heap_t          kernel_heap[X_SIZE][Y_SIZE];
+// __attribute__((section(".kdata")))
+// kernel_heap_t       kernel_heap[X_SIZE][Y_SIZE];
 
 // Schedulers virtual base addresses array (one per processor)
-__attribute__((section (".bootdata"))) 
-static_scheduler_t*    _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX];
+__attribute__((section(".kdata")))
+static_scheduler_t* _schedulers[X_SIZE][Y_SIZE][NB_PROCS_MAX];
 
 // Page tables virtual base addresses array (one per vspace)
-__attribute__((section (".bootdata"))) 
-unsigned int           _ptabs_vaddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
+__attribute__((section(".kdata")))
+unsigned int        _ptabs_vaddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
 
 // Page tables physical base addresses (one per vspace and per cluster)
-__attribute__((section (".bootdata"))) 
-paddr_t                _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
+__attribute__((section(".kdata")))
+paddr_t             _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
 
 // Page tables pt2 allocators (one per vspace and per cluster)
-__attribute__((section (".bootdata"))) 
-unsigned int           _ptabs_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
+__attribute__((section(".kdata")))
+unsigned int        _ptabs_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
 
 // Page tables max_pt2  (same value for all page tables)
-__attribute__((section (".bootdata"))) 
-unsigned int           _ptabs_max_pt2;
-
-__attribute__((section (".bootdata"))) 
-//volatile struct _boot_init_ok {
-//    unsigned int value;
-//}__attribute__((aligned(64)));
-//struct _boot_init_ok boot_init_ok = {0};
-volatile unsigned int boot_init_ok = 0;
-
-__attribute__((section (".bootdata"))) 
-volatile _giet_lock_t lock_tty;
-
-__attribute__((section (".bootdata"))) 
-volatile _giet_barrier_t barrier_boot;
-
-__attribute__((section (".bootdata"))) 
-volatile _giet_lock_t lock_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
-
-// Global variables for TTY
-__attribute__((section (".bootdata"))) 
-sbt_lock_t             _tty_tx_lock[NB_TTY_CHANNELS]   __attribute__((aligned(64)));
-
-__attribute__((section (".bootdata"))) 
-unsigned int           _tty_rx_full[NB_TTY_CHANNELS];
-#if BOOT_DEBUG_MAPPING
-unsigned int  word;
-unsigned int  line;
-unsigned int* pointer = (unsigned int*)SEG_BOOT_MAPPING_BASE;
-_puts("\n[BOOT] First block of mapping");
-for ( line = 0 ; line < 8 ; line++ )
-{
-    for ( word = 0 ; word < 8 ; word++ )
-    {
-        _puts(" | ");
-        _putx( *(pointer + word) );
-    }
-    _puts(" |\n");
-    pointer = pointer + 8;
-}
-#endif
-
-__attribute__((section (".bootdata"))) 
-unsigned int           _tty_rx_buf[NB_TTY_CHANNELS];
+__attribute__((section(".kdata")))
+unsigned int        _ptabs_max_pt2;
+
+// WTI channel allocator (one per cluster)
+__attribute__((section(".kdata")))
+unsigned int        _wti_channel_alloc[X_SIZE][Y_SIZE];
+
+// boot code uses a spin lock to protect TTY0
+__attribute__((section(".kdata")))
+unsigned int        _tty0_boot_mode = 1;
+
+__attribute__((section(".kdata")))
+spin_lock_t         _ptabs_spin_lock[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
+
+// barrier used by boot code for parallel execution
+__attribute__((section(".kdata")))
+simple_barrier_t    _barrier_all_clusters;
+
+// this variable is defined in the tty0.c file
+extern spin_lock_t  _tty0_spin_lock;
 
 //////////////////////////////////////////////////////////////////////////////
@@ -212,4 +192,6 @@
 // by the vspace_id argument, and the (x,y) coordinates.
 // It updates only the first level PT1.
+// As each vseg is mapped by a different processor, the PT1 entry cannot
+// be concurrently accessed, and we don't need to take any lock.
 //////////////////////////////////////////////////////////////////////////////
 void boot_add_pte1( unsigned int vspace_id,
@@ -220,50 +202,14 @@
                     unsigned int ppn )       // 28 bits right-justified
 {
-
-#if (BOOT_DEBUG_PT > 1)
-_get_lock(&lock_tty);
-_puts(" - PTE1 in PTAB[");
-_putd( vspace_id );
-_puts(",");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("] : vpn = ");
-_putx( vpn );
-_puts(" / ppn = ");
-_putx( ppn );
-_puts(" / flags = ");
-_putx( flags );
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
-
-    unsigned int procid     = _get_procid();
-    unsigned int x_cluster  = (procid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
-    unsigned int y_cluster  = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
-
     // compute index in PT1
     unsigned int    ix1 = vpn >> 9;         // 11 bits for ix1
 
     // get page table physical base address 
-    paddr_t         pt1_pbase = _ptabs_paddr[vspace_id][x][y];
-
-    // check pt1_base
+    paddr_t  pt1_pbase = _ptabs_paddr[vspace_id][x][y];
+
     if ( pt1_pbase == 0 )
     {
-        _get_lock(&lock_tty);
-        _puts("\n[BOOT ERROR] in boot_add_pte1() : illegal pbase address for PTAB[");
-        _putd( vspace_id );
-        _puts(",");
-        _putd( x );
-        _puts(",");
-        _putd( y );
-        _puts("]");
-        _puts(" in cluster[");
-        _putd(x_cluster);
-        _puts(",");
-        _putd(y_cluster);
-        _puts("]\n");
-        _release_lock(&lock_tty);
+        _printf("\n[BOOT ERROR] in boot_add_pte1() : no PTAB in cluster[%d,%d]"
+                    " containing processors\n", x , y );
         _exit();
     }
@@ -277,18 +223,5 @@
     _physical_write( pt1_pbase + 4*ix1, pte1 );
 
-#if (BOOT_DEBUG_PT > 1 )
-_get_lock(&lock_tty);
-_puts(" - Write pte1 ");
-_putx( pte1 );
-_puts(" in paddr ");
-_putl( pt1_pbase + 4*ix1 );
-_puts(" in cluster[");
-_putd(x_cluster);
-_puts(",");
-_putd(y_cluster);
-_puts("]\n");
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
+    asm volatile ("sync");
 
 }   // end boot_add_pte1()
@@ -300,4 +233,6 @@
 // As the set of PT2s is implemented as a fixed size array (no dynamic 
 // allocation), this function checks a possible overflow of the PT2 array.
+// As a given entry in PT1 can be shared by several vsegs, mapped by 
+// different processors, we need to take the lock protecting PTAB[v][x]y].
 //////////////////////////////////////////////////////////////////////////////
 void boot_add_pte2( unsigned int vspace_id,
@@ -308,23 +243,4 @@
                     unsigned int ppn )       // 28 bits right-justified
 {
-
-#if (BOOT_DEBUG_PT > 1)
-_get_lock(&lock_tty);
-_puts(" - PTE2 in PTAB[");
-_putd( vspace_id );
-_puts(",");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("] : vpn = ");
-_putx( vpn );
-_puts(" / ppn = ");
-_putx( ppn );
-_puts(" / flags = ");
-_putx( flags );
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
-
     unsigned int ix1;
     unsigned int ix2;
@@ -337,39 +253,32 @@
     ix2 = vpn & 0x1FF;          //  9 bits for ix2
 
-    // get page table physical base address and size
+    // get page table physical base address 
     paddr_t      pt1_pbase = _ptabs_paddr[vspace_id][x][y];
 
-    // check pt1_base
     if ( pt1_pbase == 0 )
     {
-        _get_lock(&lock_tty);
-        _puts("\n[BOOT ERROR] in boot_add_pte2() : PTAB[");
-        _putd( vspace_id );
-        _puts(",");
-        _putd( x );
-        _puts(",");
-        _putd( y );
-        _puts("] undefined\n");
-        _release_lock(&lock_tty);
+        _printf("\n[BOOT ERROR] in boot_add_pte2() : no PTAB for vspace %d "
+                "in cluster[%d,%d]\n", vspace_id , x , y );
         _exit();
     }
 
+    // get lock protecting PTAB[vspace_id][x][y]
+    _spin_lock_acquire( &_ptabs_spin_lock[vspace_id][x][y] );
+
     // get ptd in PT1
-    _get_lock(&lock_next_pt2[vspace_id][x][y]);
-    ptd = _physical_read(pt1_pbase + 4 * ix1);
+    ptd = _physical_read( pt1_pbase + 4 * ix1 );
 
     if ((ptd & PTE_V) == 0)    // undefined PTD: compute PT2 base address, 
                                // and set a new PTD in PT1 
     {
+        // get a new pt2_id
         pt2_id = _ptabs_next_pt2[vspace_id][x][y];
+        _ptabs_next_pt2[vspace_id][x][y] = pt2_id + 1;
+
+        // check overflow
         if (pt2_id == _ptabs_max_pt2) 
         {
-            _puts("\n[BOOT ERROR] in boot_add_pte2() : PTAB[");
-            _putd( vspace_id );
-            _puts(",");
-            _putd( x );
-            _puts(",");
-            _putd( y );
-            _puts("] contains not enough PT2s\n");
+            _printf("\n[BOOT ERROR] in boot_add_pte2() : PTAB[%d,%d,%d]"
+                    " contains not enough PT2s\n", vspace_id, x, y );
             _exit();
         }
@@ -377,6 +286,7 @@
         pt2_pbase = pt1_pbase + PT1_SIZE + PT2_SIZE * pt2_id;
         ptd = PTE_V | PTE_T | (unsigned int) (pt2_pbase >> 12);
+
+        // set PTD into PT1
         _physical_write( pt1_pbase + 4*ix1, ptd);
-        _ptabs_next_pt2[vspace_id][x][y] = pt2_id + 1;
     }
     else                       // valid PTD: compute PT2 base address
@@ -385,9 +295,13 @@
     }
 
-    _release_lock(&lock_next_pt2[vspace_id][x][y]);
     // set PTE in PT2 : flags & PPN in two 32 bits words
     pte2_paddr  = pt2_pbase + 8 * ix2;
-    _physical_write(pte2_paddr     , (PTE_V |flags) );
-    _physical_write(pte2_paddr + 4 , ppn);
+    _physical_write(pte2_paddr     , (PTE_V | flags) );
+    _physical_write(pte2_paddr + 4 , ppn );
+
+    // release lock protecting PTAB[vspace_id][x][y]
+    _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] );
+
+    asm volatile ("sync");
 
 }   // end boot_add_pte2()
@@ -397,5 +311,5 @@
 // defined by alignPow2 == L2(alignement).
 ////////////////////////////////////////////////////////////////////////////////////
-paddr_t paddr_align_to(paddr_t paddr, unsigned int alignPow2) 
+paddr_t paddr_align_to( paddr_t paddr, unsigned int alignPow2 ) 
 {
     paddr_t mask = (1 << alignPow2) - 1;
@@ -403,5 +317,5 @@
 }
 
-unsigned int vaddr_align_to(unsigned int vaddr, unsigned int alignPow2) 
+unsigned int vaddr_align_to( unsigned int vaddr, unsigned int alignPow2 ) 
 {
     unsigned int mask = (1 << alignPow2) - 1;
@@ -412,5 +326,5 @@
 // This function map a vseg identified by the vseg pointer.
 //
-// A given vseg can be mapped in Big Physical Pages (BPP: 2 Mbytes) or in a
+// A given vseg can be mapped in a Big Physical Pages (BPP: 2 Mbytes) or in a
 // Small Physical Pages (SPP: 4 Kbytes), depending on the "big" attribute of vseg,
 // with the following rules:
@@ -424,15 +338,15 @@
 //    account the alignment constraints and register it in vobj->vbase field.
 //
-// 2) Second step: it allocates the required number of physical pages, 
+// 2) Second step: it allocates the required number of contiguous physical pages, 
 //    computes the physical base address (if the vseg is not identity mapping),
 //    and register it in the vseg pbase field.
-//    Only the 4 vsegs used by the boot code and the peripheral vsegs
-//    can be identity mapping: The first big physical page in cluster[0,0] 
-//    is reserved for the 4 boot vsegs.
+//    Only the vsegs used by the boot code and the peripheral vsegs
+//    can be identity mapping. The first big physical page in cluster[0,0] 
+//    is reserved for the boot vsegs.
 //
-// 3) Third step (only for vseg that have the VOBJ_TYPE_PTAB): all page tables
-//    associated to the various vspaces must be packed in the same vseg.
-//    We divide the vseg in M sub-segments, and compute the vbase and pbase
-//    addresses for each page table, and register it in the _ptabs_paddr
+// 3) Third step (only for vseg that have the VOBJ_TYPE_PTAB): the M page tables
+//    associated to the M vspaces must be packed in the same vseg.
+//    We divide this vseg in M sub-segments, and compute the vbase and pbase
+//    addresses for M page tables, and register these addresses in the _ptabs_paddr
 //    and _ptabs_vaddr arrays.
 //  
@@ -496,7 +410,7 @@
     //////////// - if vseg is ram      :  ppn <= physical memory allocator
 
-    unsigned int ppn;          // first physical page index ( 28 bits = |x|y|bppi|sppi| ) 
-    unsigned int vpn;          // first virtual page index  ( 20 bits = |ix1|ix2| )
-    unsigned int vpn_max;      // last  virtual page index  ( 20 bits = |ix1|ix2| )
+    unsigned int ppn;          // first physical page index (28 bits = |x|y|bppi|sppi|) 
+    unsigned int vpn;          // first virtual page index  (20 bits = |ix1|ix2|)
+    unsigned int vpn_max;      // last  virtual page index  (20 bits = |ix1|ix2|)
 
     vpn     = vseg->vbase >> 12;
@@ -539,23 +453,5 @@
                     paddr_t      paddr = _ptabs_paddr[vsid][x_dest][y_dest] + (ix1<<2);
                     unsigned int pte1  = _physical_read( paddr );
-#if (BOOT_DEBUG_PT > 1)
-_get_lock(&lock_tty);
-_puts("[BOOT DEBUG] ");
-_puts( vseg->name );
-_puts(" in cluster[");
-_putd( x_dest );
-_puts(",");
-_putd( y_dest );
-_puts("] : vbase = ");
-_putx( vseg->vbase );
-_puts(" / paddr = ");
-_putl( paddr );
-_puts(" / pte1 = ");
-_putx( pte1 );
-_puts(" by processor ");
-_putd(_get_procid());
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
+
                     if ( (pte1 & PTE_V) == 0 )     // BPP not allocated yet
                     {
@@ -572,15 +468,11 @@
                         if (pte1 & PTE_W) pte1_mode |= W_MODE_MASK;
                         if (pte1 & PTE_U) pte1_mode |= U_MODE_MASK;
-                        if (vseg->mode != pte1_mode) {
-                            _puts("\n[BOOT ERROR] in boot_vseg_map() : vseg ");
-                            _puts( vseg->name );
-                            _puts(" has different flags (");
-                            _putx( vseg->mode );
-                            _puts(") than other vsegs sharing the same big page (");
-                            _putx( pte1_mode );
-                            _puts(")");
+                        if (vseg->mode != pte1_mode) 
+                        {
+                            _printf("\n[BOOT ERROR] in boot_vseg_map() : "
+                                    "vseg %s has different flags than another vseg "
+                                    "in the same BPP\n", vseg->name );
                             _exit();
                         }
-
                         ppn = ((pte1 << 9) & 0x0FFFFE00);
                     }
@@ -597,4 +489,5 @@
     // update vseg.pbase field and update vsegs chaining
     vseg->pbase     = ((paddr_t)ppn) << 12;
+    vseg->mapped    = 1;
     vseg->next_vseg = pseg->next_vseg;
     pseg->next_vseg = (unsigned int)vseg;
@@ -637,23 +530,15 @@
     }
 
+    asm volatile ("sync");
+
 #if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("[BOOT DEBUG] ");
-_puts( vseg->name );
-_puts(" in cluster[");
-_putd( x_dest );
-_puts(",");
-_putd( y_dest );
-_puts("] : vbase = ");
-_putx( vseg->vbase );
-_puts(" / length = ");
-_putx( vseg->length );
-if ( big ) _puts(" / BIG   / npages = ");
-else       _puts(" / SMALL / npages = ");
-_putd( npages );
-_puts(" / pbase = ");
-_putl( vseg->pbase );
-_puts("\n");
-_release_lock(&lock_tty);
+if ( big )
+_printf("\n[BOOT] vseg %s : cluster[%d,%d] / "
+       "vbase = %x / length = %x / BIG    / npages = %d / pbase = %l\n",
+       vseg->name, x_dest, y_dest, vseg->vbase, vseg->length, npages, vseg-> pbase );
+else
+_printf("\n[BOOT] vseg %s : cluster[%d,%d] / "
+        "vbase = %x / length = %x / SMALL / npages = %d / pbase = %l\n",
+       vseg->name, x_dest, y_dest, vseg->vbase, vseg->length, npages, vseg-> pbase );
 #endif
 
@@ -661,10 +546,10 @@
 
 /////////////////////////////////////////////////////////////////////////////////////
-// For the vseg defined by the vseg pointer, this function register all PTEs
+// For the vseg defined by the vseg pointer, this function register PTEs
 // in one or several page tables.
 // It is a global vseg (kernel vseg) if (vspace_id == 0xFFFFFFFF).
 // The number of involved PTABs depends on the "local" and "global" attributes:
 //  - PTEs are replicated in all vspaces for a global vseg.
-//  - PTEs are replicated in all clusters for a non local vseg.
+//  - PTEs are replicated in all clusters containing procs for a non local vseg.
 /////////////////////////////////////////////////////////////////////////////////////
 void boot_vseg_pte( mapping_vseg_t*  vseg,
@@ -690,7 +575,7 @@
 
     // compute vseg flags
-    // The three flags (Local, Remote and Dirty) are set to 1 to reduce
-    // latency of TLB miss (L/R) and write (D): Avoid hardware update
-    // mechanism for these flags because GIET_VM does use these flags.
+    // The three flags (Local, Remote and Dirty) are set to 1 
+    // to avoid hardware update for these flags, because GIET_VM 
+    // does use these flags.
     unsigned int flags = 0;
     if (vseg->mode & C_MODE_MASK) flags |= PTE_C;
@@ -711,19 +596,17 @@
     else            npages  = (vpn_max>>9) - (vpn>>9) + 1; 
 
-    // compute destination cluster coordinates
-    unsigned int        x_dest;
-    unsigned int        y_dest;
-    mapping_header_t*   header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
-    mapping_cluster_t*  cluster = _get_cluster_base(header);
-    mapping_pseg_t*     pseg    = _get_pseg_base(header);
-    pseg     = pseg + vseg->psegid;
-    cluster  = cluster + pseg->clusterid;
-    x_dest   = cluster->x;
-    y_dest   = cluster->y;
-
-    unsigned int p;     // iterator for physical page index
-    unsigned int x;     // iterator for cluster x coordinate  
-    unsigned int y;     // iterator for cluster y coordinate  
-    unsigned int v;     // iterator for vspace index 
+    // compute destination cluster coordinates, for local vsegs
+    mapping_header_t*   header       = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_cluster_t*  cluster      = _get_cluster_base(header);
+    mapping_pseg_t*     pseg         = _get_pseg_base(header);
+    mapping_pseg_t*     pseg_dest    = &pseg[vseg->psegid];
+    mapping_cluster_t*  cluster_dest = &cluster[pseg_dest->clusterid];
+    unsigned int        x_dest       = cluster_dest->x;
+    unsigned int        y_dest       = cluster_dest->y;
+
+    unsigned int p;           // iterator for physical page index
+    unsigned int x;           // iterator for cluster x coordinate  
+    unsigned int y;           // iterator for cluster y coordinate  
+    unsigned int v;           // iterator for vspace index 
 
     // loop on PTEs
@@ -757,21 +640,24 @@
                 for ( y = 0 ; y < Y_SIZE ; y++ )
                 {
-                    if ( big )   // big pages => PTE1s
+                    if ( cluster[(x * Y_SIZE) + y].procs )
                     {
-                        boot_add_pte1( vsid,
-                                       x,
-                                       y,
-                                       vpn + (p<<9),
-                                       flags, 
-                                       ppn + (p<<9) );
-                    }
-                    else         // small pages => PTE2s
-                    {
-                        boot_add_pte2( vsid,
-                                       x,
-                                       y,
-                                       vpn + p,
-                                       flags, 
-                                       ppn + p );
+                        if ( big )   // big pages => PTE1s
+                        {
+                            boot_add_pte1( vsid,
+                                           x,
+                                           y,
+                                           vpn + (p<<9),
+                                           flags, 
+                                           ppn + (p<<9) );
+                        }
+                        else         // small pages => PTE2s
+                        {
+                            boot_add_pte2( vsid,
+                                           x,
+                                           y,
+                                           vpn + p,
+                                           flags, 
+                                           ppn + p );
+                        }
                     }
                 }
@@ -808,23 +694,26 @@
                 for ( y = 0 ; y < Y_SIZE ; y++ )
                 {
-                    for ( v = 0 ; v < header->vspaces ; v++ )
+                    if ( cluster[(x * Y_SIZE) + y].procs )
                     {
-                        if ( big )  // big pages => PTE1s
+                        for ( v = 0 ; v < header->vspaces ; v++ )
                         {
-                            boot_add_pte1( v,
-                                           x,
-                                           y,
-                                           vpn + (p<<9),
-                                           flags, 
-                                           ppn + (p<<9) );
-                        }
-                        else        // small pages -> PTE2s
-                        {
-                            boot_add_pte2( v,
-                                           x,
-                                           y,
-                                           vpn + p,
-                                           flags, 
-                                           ppn + p );
+                            if ( big )  // big pages => PTE1s
+                            {
+                                boot_add_pte1( v,
+                                               x,
+                                               y,
+                                               vpn + (p<<9),
+                                               flags, 
+                                               ppn + (p<<9) );
+                            }
+                            else        // small pages -> PTE2s
+                            {
+                                boot_add_pte2( v,
+                                               x,
+                                               y,
+                                               vpn + p,
+                                               flags, 
+                                               ppn + p );
+                            }
                         }
                     }
@@ -833,21 +722,46 @@
         }
     }  // end for pages
+
+    asm volatile ("sync");
+
 }  // end boot_vseg_pte()
 
+
 ///////////////////////////////////////////////////////////////////////////////
-// This function initialises the page tables for all vspaces defined 
-// in the mapping_info data structure.
-// For each vspace, there is one page table per cluster.
+// Processor P[x][y][0] computes physical base address for all globals vsegs,
+// using the local Page Table, to check page tables initialisation.
+///////////////////////////////////////////////////////////////////////////////
+void boot_ptab_check( unsigned int x,
+                      unsigned int y )
+{
+    mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_vseg_t*     vseg   = _get_vseg_base(header);
+    page_table_t*       ptab   = (page_table_t*)_ptabs_vaddr[0][x][y];
+
+    unsigned int vseg_id;
+    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
+    {
+        unsigned int  vpn   = vseg[vseg_id].vbase >> 12;
+        unsigned int  ppn   = 0;  
+        unsigned int  flags = 0;
+        _v2p_translate( ptab , vpn , &ppn , &flags );
+        _printf("@@@ P[%d,%d,0] access vseg %s : vpn = %x / ppn = %x\n",
+                x , y , vseg[vseg_id].name , vpn , ppn );  
+    }
+} 
+
+///////////////////////////////////////////////////////////////////////////////
+// This function is executed by  processor[x][y][0] in each cluster 
+// containing at least one processor.
+// It initialises all page table for all global or private vsegs
+// mapped in cluster[x][y], as specified in the mapping.
 // In each cluster all page tables for the different vspaces must be
 // packed in one vseg occupying one single BPP (Big Physical Page).
 // 
-// This fonction is executed by the processor[x][y][0], the vsegs mapped in the 
-// cluster[x][y] in map.bin file are handled by the processor[x][y][0]
-//
 // For each vseg, the mapping is done in two steps:
 // 1) mapping : the boot_vseg_map() function allocates contiguous BPPs 
 //    or SPPs (if the vseg is not associated to a peripheral), and register
 //    the physical base address in the vseg pbase field. It initialises the
-//    _ptabs_vaddr and _ptabs_paddr arrays if the vseg is a PTAB.
+//    _ptabs_vaddr[] and _ptabs_paddr[] arrays if the vseg is a PTAB.
 //
 // 2) page table initialisation : the boot_vseg_pte() function initialise 
@@ -857,10 +771,11 @@
 //
 // We must handle vsegs in the following order
-//   1) all global vsegs containing a page table,
-//   2) all global vsegs occupying more than one BPP, 
-//   3) all others global vsegs
-//   4) all private vsegs in user space.
+//   1) global vseg containing PTAB mapped in cluster[x][y],
+//   2) global vsegs occupying more than one BPP mapped in cluster[x][y], 
+//   3) others global vsegs mapped in cluster[x][y],
+//   4) all private vsegs in all user spaces mapped in cluster[x][y].
 ///////////////////////////////////////////////////////////////////////////////
-void boot_ptabs_init() 
+void boot_ptab_init( unsigned int cx,
+                     unsigned int cy ) 
 {
     mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
@@ -875,35 +790,24 @@
 
     unsigned int procid     = _get_procid();
-    unsigned int x_cluster  = (procid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
-    unsigned int y_cluster  = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
     unsigned int lpid       = procid & ((1<<P_WIDTH)-1);
 
-    if(lpid)
-    {
-        _puts("[BOOT ERROR] boot_ptabs_init() : error local processor id\n");
+    if( lpid )
+    {
+        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
+                "P[%d][%d][%d] should not execute it\n", cx, cy, lpid );
         _exit();
     } 
 
-    if (header->vspaces == 0 )
-    {
-        _puts("\n[BOOT ERROR] in boot_ptabs_init() : mapping ");
-        _puts( header->name );
-        _puts(" contains no vspace\n");
+    if ( header->vspaces == 0 )
+    {
+        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
+                "mapping %s contains no vspace\n", header->name );
         _exit();
     }
 
-    ///////// Phase 1 : global vsegs containing a PTAB (two loops required)
-
-#if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("\n[BOOT DEBUG] map PTAB global vsegs in cluster[");
-_putd(x_cluster);
-_puts(",");
-_putd(y_cluster);
-_puts("]");
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
-
+    ///////// Phase 1 : global vseg containing the PTAB (two barriers required)
+
+    // get local PTAB vseg
+    unsigned int found = 0;
     for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
     {
@@ -912,42 +816,30 @@
         cluster = _get_cluster_base(header) + pseg->clusterid;
         if ( (vobj[vobj_id].type == VOBJ_TYPE_PTAB) && 
-             (cluster->x == x_cluster) &&
-             (cluster->y == y_cluster))
-        {
-            boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
-            vseg[vseg_id].mapped = 1;
-        }
-    }
-
-    _barrier_wait(&barrier_boot);
-
-    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
-    {
-        unsigned int vobj_id = vseg[vseg_id].vobj_offset;
-        pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
-        cluster = _get_cluster_base(header) + pseg->clusterid;
-        if ( (vobj[vobj_id].type == VOBJ_TYPE_PTAB) && 
-             (cluster->x == x_cluster) &&
-             (cluster->y == y_cluster))
-        {
-            boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
-            vseg[vseg_id].mapped = 1;
-        }
-    }
-
-    _barrier_wait(&barrier_boot);
-
-    ///////// Phase 2 : global vsegs occupying more than one BPP (one loop)
-
-#if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("\n[BOOT DEBUG] map all multi-BPP global vseg in cluster[");
-_putd(x_cluster);
-_puts(",");
-_putd(y_cluster);
-_puts("]");
-_puts("\n");
-_release_lock(&lock_tty);
-#endif   
+             (cluster->x == cx) && (cluster->y == cy) )
+        {
+            found = 1;
+            break;
+        }
+    }
+    if ( found == 0 )
+    {
+        _printf("\n[BOOT ERROR] in boot_ptab_init() : "
+                "cluster[%d][%d] contains no PTAB vseg\n", cx , cy );
+        _exit();
+    }
+
+    boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
+
+    //////////////////////////////////////////////
+    _simple_barrier_wait( &_barrier_all_clusters );
+    //////////////////////////////////////////////
+
+    boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
+
+    //////////////////////////////////////////////
+    _simple_barrier_wait( &_barrier_all_clusters );
+    //////////////////////////////////////////////
+
+    ///////// Phase 2 : global vsegs occupying more than one BPP 
 
     for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
@@ -958,60 +850,29 @@
         if ( (vobj[vobj_id].length > 0x200000) &&
              (vseg[vseg_id].mapped == 0) &&
-             (cluster->x == x_cluster) &&
-             (cluster->y == y_cluster))
+             (cluster->x == cx) && (cluster->y == cy) )
         {
             boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
-            vseg[vseg_id].mapped = 1;
             boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
         }
     }
 
-    ///////// Phase 3 : all others global vsegs (one loop)
-
-#if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("\n[BOOT DEBUG] map all others global in cluster[ ");
-_putd(x_cluster);
-_puts(",");
-_putd(y_cluster);
-_puts("]");
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
+    ///////// Phase 3 : all others global vsegs 
 
     for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
-    {
-        unsigned int vobj_id = vseg[vseg_id].vobj_offset;
+    { 
         pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
         cluster = _get_cluster_base(header) + pseg->clusterid;
-        if ( (vobj[vobj_id].length <= 0x200000) &&
-             (vseg[vseg_id].mapped == 0) && 
-             (cluster->x == x_cluster) &&
-             (cluster->y == y_cluster))
+        if ( (vseg[vseg_id].mapped == 0) && 
+             (cluster->x == cx) && (cluster->y == cy) )
         {
             boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
-            vseg[vseg_id].mapped = 1;
             boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
         }
     }
 
-    ///////// Phase 4 : all private vsegs (two nested loops)
+    ///////// Phase 4 : all private vsegs 
 
     for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
     {
-
-#if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("\n[BOOT DEBUG] map private vsegs for vspace ");
-_puts( vspace[vspace_id].name );
-_puts(" in cluster[ ");
-_putd(x_cluster);
-_puts(",");
-_putd(y_cluster);
-_puts("]");
-_puts("\n");
-_release_lock(&lock_tty);
-#endif
-
         for (vseg_id = vspace[vspace_id].vseg_offset;
              vseg_id < (vspace[vspace_id].vseg_offset + vspace[vspace_id].vsegs);
@@ -1020,10 +881,7 @@
             pseg    = _get_pseg_base(header) + vseg[vseg_id].psegid;
             cluster = _get_cluster_base(header) + pseg->clusterid;
-            if((vseg[vseg_id].mapped == 0) && 
-               (cluster->x == x_cluster) &&
-               (cluster->y == y_cluster))
+            if ( (cluster->x == cx) && (cluster->y == cy) )
             {
                 boot_vseg_map( &vseg[vseg_id], vspace_id );
-                vseg[vseg_id].mapped = 1;
                 boot_vseg_pte( &vseg[vseg_id], vspace_id );
             }
@@ -1031,89 +889,34 @@
     }
 
-#if (BOOT_DEBUG_PT > 2) 
-_get_lock(&lock_tty);
-mapping_vseg_t*    curr;
-mapping_pseg_t*    pseg    = _get_pseg_base(header);
-mapping_cluster_t* cluster = _get_cluster_base(header);
-unsigned int       pseg_id;
-for( pseg_id = 0 ; pseg_id < header->psegs ; pseg_id++ )
+    //////////////////////////////////////////////
+    _simple_barrier_wait( &_barrier_all_clusters );
+    //////////////////////////////////////////////
+
+} // end boot_ptab_init()
+
+////////////////////////////////////////////////////////////////////////////////
+// This function should be executed by P[0][0][0] only. It complete the
+// page table initialisation, taking care of all global vsegs that are
+// not mapped in a cluster containing a processor, and have not been
+// handled by the boot_ptab_init(x,y) function.
+// An example of such vsegs are the external peripherals in TSAR_LETI platform.
+////////////////////////////////////////////////////////////////////////////////
+void boot_ptab_extend()
 {
-    unsigned int cluster_id = pseg[pseg_id].clusterid;
-    _puts("\n[BOOT DEBUG] vsegs mapped on pseg ");
-    _puts( pseg[pseg_id].name );
-    _puts(" in cluster[");
-    _putd( cluster[cluster_id].x );
-    _puts(",");
-    _putd( cluster[cluster_id].y );
-    _puts("]\n");
-    for( curr = (mapping_vseg_t*)pseg[pseg_id].next_vseg ;
-         curr != 0 ;
-         curr = (mapping_vseg_t*)curr->next_vseg )
-    {
-        _puts(" - vseg ");
-        _puts( curr->name );
-        _puts(" : len = ");
-        _putx( curr->length );
-        _puts(" / vbase ");
-        _putx( curr->vbase );
-        _puts(" / pbase ");
-        _putl( curr->pbase );
-        _puts("\n");
-    }  
-}
-_release_lock(&lock_tty);
-#endif
-
-} // end boot_ptabs_init()
-
-///////////////////////////////////////////////////////////////////////////////
-// This function initializes the private vobjs that have the CONST type.
-// The MMU is supposed to be activated...
-///////////////////////////////////////////////////////////////////////////////
-void boot_vobjs_init() 
-{
-    mapping_header_t* header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
-    mapping_vspace_t* vspace = _get_vspace_base(header);
-    mapping_vobj_t* vobj     = _get_vobj_base(header);
-
-    unsigned int vspace_id;
-    unsigned int vobj_id;
-
-    // loop on the vspaces
-    for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
-    {
-
-#if BOOT_DEBUG_VOBJS
-_puts("\n[BOOT DEBUG] ****** vobjs initialisation in vspace ");
-_puts(vspace[vspace_id].name);
-_puts(" ******\n");
-#endif
-
-        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id][0][0] >> 13) );
-
-        // loop on the vobjs
-        for (vobj_id = vspace[vspace_id].vobj_offset;
-             vobj_id < (vspace[vspace_id].vobj_offset + vspace[vspace_id].vobjs);
-             vobj_id++) 
-        {
-            if ( (vobj[vobj_id].type) == VOBJ_TYPE_CONST )
-            {
-#if BOOT_DEBUG_VOBJS
-_puts("CONST   : ");
-_puts(vobj[vobj_id].name);
-_puts(" / vaddr  = ");
-_putx(vobj[vobj_id].vaddr);
-_puts(" / paddr  = ");
-_putl(vobj[vobj_id].paddr);
-_puts(" / value  = ");
-_putx(vobj[vobj_id].init);
-_puts("\n");
-#endif
-                unsigned int* addr = (unsigned int *) vobj[vobj_id].vbase;
-                *addr = vobj[vobj_id].init;
-            }
-        }
-    }
-} // end boot_vobjs_init()
+
+    mapping_header_t*   header = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_vseg_t*     vseg   = _get_vseg_base(header);
+
+    unsigned int vseg_id;
+
+    for (vseg_id = 0; vseg_id < header->globals; vseg_id++) 
+    {
+        if ( vseg[vseg_id].mapped == 0 )  
+        {
+            boot_vseg_map( &vseg[vseg_id], 0xFFFFFFFF );
+            boot_vseg_pte( &vseg[vseg_id], 0xFFFFFFFF );
+        }
+    }
+}  // end boot_ptab_extend()
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1147,9 +950,6 @@
     {
         mapping_cluster_t* cluster = _get_cluster_base(header);
-        _puts("\n[BOOT ERROR] No vobj of type SCHED in cluster [");
-        _putd( cluster[cluster_id].x );
-        _puts(",");
-        _putd( cluster[cluster_id].y );
-        _puts("]\n");
+        _printf("\n[BOOT ERROR] No vobj of type SCHED in cluster [%d,%d]\n",
+                cluster[cluster_id].x, cluster[cluster_id].y );
         _exit();
     }
@@ -1157,355 +957,151 @@
 
 ////////////////////////////////////////////////////////////////////////////////////
-// This function initialises all processors schedulers.
-// This is done by processor 0, and the MMU must be activated.
-// - In Step 1, it initialises the _schedulers[x][y][l] pointers array, and scan
-//              the processors for a first initialisation of the schedulers:
-//              idle_task context, and HWI / SWI / PTI vectors. 
+// This function is executed in parallel by all processors P[x][y][0].
+// It initialises all schedulers in cluster [x][y]. The MMU must be activated.
+// It is split in two phases separated by a synchronisation barrier.
+// - In Step 1, it initialises the _schedulers[x][y][l] pointers array,
+//              the idle_task context and the HWI / PTI vectors. 
 // - In Step 2, it scan all tasks in all vspaces to complete the tasks contexts, 
-//              initialisation as specified in the mapping_info data structure. 
+//              initialisation as specified in the mapping_info data structure,
+//              and set the CP0_SCHED register. 
 ////////////////////////////////////////////////////////////////////////////////////
-void boot_schedulers_init() 
+void boot_scheduler_init( unsigned int x, 
+                          unsigned int y )
 {
-    mapping_header_t*  header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
-    mapping_cluster_t* cluster = _get_cluster_base(header);
-    mapping_vspace_t*  vspace  = _get_vspace_base(header);
-    mapping_task_t*    task    = _get_task_base(header);
-    mapping_vobj_t*    vobj    = _get_vobj_base(header);
-    mapping_periph_t*  periph  = _get_periph_base(header);
-    mapping_irq_t*     irq     = _get_irq_base(header);
-
-    unsigned int cluster_id;    // cluster index in mapping_info 
-    unsigned int periph_id;     // peripheral index in mapping_info
-    unsigned int irq_id;        // irq index in mapping_info
-    unsigned int vspace_id;     // vspace index in mapping_info
-    unsigned int task_id;       // task index in mapping_info
-    unsigned int vobj_id;       // vobj index in mapping_info
-
-    unsigned int lpid;          // local processor index (for several loops)
-
-    // WTI allocators to processors (for HWIs translated to WTIs)  
-    // In all clusters the first NB_PROCS_MAX WTIs are reserved for WAKUP
-    unsigned int alloc_wti_channel[X_SIZE*Y_SIZE];   // one per cluster
-
-    // pointers on the XCU and PIC peripherals
+    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_cluster_t*   cluster = _get_cluster_base(header);
+    mapping_vspace_t*    vspace  = _get_vspace_base(header);
+    mapping_task_t*      task    = _get_task_base(header);
+    mapping_vobj_t*      vobj    = _get_vobj_base(header);
+    mapping_periph_t*    periph  = _get_periph_base(header);
+    mapping_irq_t*       irq     = _get_irq_base(header);
+
+    unsigned int         periph_id; 
+    unsigned int         irq_id;
+    unsigned int         vspace_id;
+    unsigned int         task_id; 
+    unsigned int         vobj_id; 
+
+    unsigned int         sched_vbase;          // schedulers array vbase address 
+    unsigned int         sched_length;         // schedulers array length
+    static_scheduler_t*  psched;               // pointer on processor scheduler
+
+    unsigned int cluster_id = x * Y_SIZE + y;  
+    unsigned int nprocs = cluster[cluster_id].procs;
+    unsigned int lpid;                       
+    
+    /////////////////////////////////////////////////////////////////////////
+    // Step 1 : initialize the schedulers[] array of pointers,
+    //          the idle task context and the HWI and PTI interrupt vectors.
+    //          The WTI interrupt vector entries corresponding to interrupts
+    //          generated by the PIC component are handled later.
+
+    // get scheduler array virtual base address in cluster[x,y]
+    boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
+
+    if ( sched_length < (nprocs<<13) ) // 8 Kbytes per scheduler
+    {
+        _printf("\n[BOOT ERROR] Sched segment too small in cluster[%d,%d]\n", x, y );
+        _exit();
+    }
+
+    // loop on local processors
+    for ( lpid = 0 ; lpid < nprocs ; lpid++ )
+    {
+        // get scheduler pointer and initialise the schedulers pointers array
+        psched = (static_scheduler_t*)(sched_vbase + (lpid<<13));
+        _schedulers[x][y][lpid] = psched;
+
+        // initialise the "tasks" and "current" variables default values
+        psched->tasks   = 0;
+        psched->current = IDLE_TASK_INDEX;
+
+        // default values for HWI / PTI / SWI vectors (valid bit = 0)
+        unsigned int slot;
+        for (slot = 0; slot < 32; slot++)
+        {
+            psched->hwi_vector[slot] = 0;
+            psched->pti_vector[slot] = 0;
+            psched->wti_vector[slot] = 0;
+        }
+
+        // WTI[lpid] <= ISR_WAKUP / PTI[lpid] <= ISR_TICK 
+        psched->wti_vector[lpid] = ISR_WAKUP | 0x80000000;
+        psched->pti_vector[lpid] = ISR_TICK  | 0x80000000;
+
+        // initializes the idle_task context:
+        // - the SR slot is 0xFF03 because this task run in kernel mode.
+        // - it uses the page table of vspace[0]
+        // - it uses the kernel TTY terminal
+        // - slots containing addresses (SP,RA,EPC) are initialised by kernel_init()
+
+        psched->context[IDLE_TASK_INDEX][CTX_CR_ID]   = 0;
+        psched->context[IDLE_TASK_INDEX][CTX_SR_ID]   = 0xFF03;
+        psched->context[IDLE_TASK_INDEX][CTX_PTPR_ID] = _ptabs_paddr[0][x][y]>>13;
+        psched->context[IDLE_TASK_INDEX][CTX_PTAB_ID] = _ptabs_vaddr[0][x][y];
+        psched->context[IDLE_TASK_INDEX][CTX_TTY_ID]  = 0;
+        psched->context[IDLE_TASK_INDEX][CTX_LTID_ID] = IDLE_TASK_INDEX;
+        psched->context[IDLE_TASK_INDEX][CTX_VSID_ID] = 0;
+        psched->context[IDLE_TASK_INDEX][CTX_RUN_ID]  = 1;
+    }
+
+    // scan local peripherals to get local XCU 
     mapping_periph_t*  xcu = NULL;
-    mapping_periph_t*  pic = NULL;
-
-    unsigned int          sched_vbase;  // schedulers array vbase address in a cluster
-    unsigned int          sched_length; // schedulers array length
-    static_scheduler_t*   psched;       // pointer on processor scheduler
-
-    /////////////////////////////////////////////////////////////////////////
-    // Step 1 : loop on the clusters and on the processors 
-    //          to initialize the schedulers[] array of pointers,
-    //          idle task context and interrupt vectors.
-    // Implementation note:
-    // We need to use both (proc_id) to scan the mapping info structure,
-    // and (x,y,lpid) to access the schedulers array.
-
-    for (cluster_id = 0 ; cluster_id < X_SIZE*Y_SIZE ; cluster_id++) 
-    {
-        unsigned int x          = cluster[cluster_id].x;
-        unsigned int y          = cluster[cluster_id].y;
-
-#if BOOT_DEBUG_SCHED
-_puts("\n[BOOT DEBUG] Initialise schedulers in cluster[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("]\n");
-#endif
-        alloc_wti_channel[cluster_id] = NB_PROCS_MAX;
-
-        // checking processors number
-        if ( cluster[cluster_id].procs > NB_PROCS_MAX )
-        {
-            _puts("\n[BOOT ERROR] Too much processors in cluster[");
-            _putd( x );
-            _puts(",");
-            _putd( y );
-            _puts("]\n");
-            _exit();
-        }
- 
-        // no schedulers initialisation if nprocs == 0
-        if ( cluster[cluster_id].procs > 0 )
-        {
-            // get scheduler array virtual base address in cluster[cluster_id]
-            boot_get_sched_vaddr( cluster_id, &sched_vbase, &sched_length );
-
-            if ( sched_length < (cluster[cluster_id].procs<<13) ) // 8 Kbytes per scheduler
+
+    for ( periph_id = cluster[cluster_id].periph_offset ;
+          periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs;
+          periph_id++ )
+    {
+        if( periph[periph_id].type == PERIPH_TYPE_XCU ) 
+        {
+            xcu = &periph[periph_id];
+
+            if ( xcu->arg < (nprocs * header->irq_per_proc) )
             {
-                _puts("\n[BOOT ERROR] Schedulers segment too small in cluster[");
-                _putd( x );
-                _puts(",");
-                _putd( y );
-                _puts("]\n");
+                _printf("\n[BOOT ERROR] Not enough inputs for XCU[%d,%d]\n", x, y );
                 _exit();
             }
-
-            // scan peripherals to find the XCU and the PIC component
-
-            xcu = NULL;  
-            for ( periph_id = cluster[cluster_id].periph_offset ;
-                  periph_id < cluster[cluster_id].periph_offset + cluster[cluster_id].periphs;
-                  periph_id++ )
-            {
-                if( periph[periph_id].type == PERIPH_TYPE_XCU ) 
-                {
-                    xcu = &periph[periph_id];
-
-                    if ( xcu->arg < cluster[cluster_id].procs )
-                    {
-                        _puts("\n[BOOT ERROR] Not enough inputs for XCU[");
-                        _putd( x );
-                        _puts(",");
-                        _putd( y );
-                        _puts("]\n");
-                        _exit();
-                    }
-                }
-                if( periph[periph_id].type == PERIPH_TYPE_PIC )   
-                {
-                    pic = &periph[periph_id];
-                }
-            } 
-            if ( xcu == NULL )
-            {         
-                _puts("\n[BOOT ERROR] No XCU component in cluster[");
-                _putd( x );
-                _puts(",");
-                _putd( y );
-                _puts("]\n");
-                _exit();
-            }
-
-            // loop on processors for schedulers default values
-            // initialisation, including WTI and PTI vectors
-            for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
-            {
-                // pointer on processor scheduler
-                psched = (static_scheduler_t*)(sched_vbase + (lpid<<13));
-
-                // initialise the schedulers pointers array
-                _schedulers[x][y][lpid] = psched;
-
-#if BOOT_DEBUG_SCHED
-unsigned int   sched_vbase = (unsigned int)_schedulers[x][y][lpid];
-unsigned int   sched_ppn;
-unsigned int   sched_flags;
-paddr_t        sched_pbase;
-
-page_table_t* ptab = (page_table_t*)(_ptabs_vaddr[0][x][y]);
-_v2p_translate( ptab, sched_vbase>>12, &sched_ppn, &sched_flags );
-sched_pbase = ((paddr_t)sched_ppn)<<12;
-
-_puts("\nProc[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts(",");
-_putd( lpid );
-_puts("] : scheduler vbase = ");
-_putx( sched_vbase );
-_puts(" : scheduler pbase = ");
-_putl( sched_pbase );
-_puts("\n");
-#endif
-                // initialise the "tasks" and "current" variables default values
-                psched->tasks   = 0;
-                psched->current = IDLE_TASK_INDEX;
-
-                // default values for HWI / PTI / SWI vectors (valid bit = 0)
-                unsigned int slot;
-                for (slot = 0; slot < 32; slot++)
-                {
-                    psched->hwi_vector[slot] = 0;
-                    psched->pti_vector[slot] = 0;
-                    psched->wti_vector[slot] = 0;
-                }
-
-                // WTI[lpid] <= ISR_WAKUP / PTI[lpid] <= ISR_TICK 
-                psched->wti_vector[lpid] = ISR_WAKUP | 0x80000000;
-                psched->pti_vector[lpid] = ISR_TICK  | 0x80000000;
-
-                // initializes the idle_task context in scheduler:
-                // - the SR slot is 0xFF03 because this task run in kernel mode.
-                // - it uses the page table of vspace[0]
-                // - it uses the kernel TTY terminal
-                // - slots containing addresses (SP, RA, EPC)
-                //   must be initialised by kernel_init()
-
-                psched->context[IDLE_TASK_INDEX][CTX_CR_ID]   = 0;
-                psched->context[IDLE_TASK_INDEX][CTX_SR_ID]   = 0xFF03;
-                psched->context[IDLE_TASK_INDEX][CTX_PTPR_ID] = _ptabs_paddr[0][x][y]>>13;
-                psched->context[IDLE_TASK_INDEX][CTX_PTAB_ID] = _ptabs_vaddr[0][x][y];
-                psched->context[IDLE_TASK_INDEX][CTX_TTY_ID]  = 0;
-                psched->context[IDLE_TASK_INDEX][CTX_LTID_ID] = IDLE_TASK_INDEX;
-                psched->context[IDLE_TASK_INDEX][CTX_VSID_ID] = 0;
-                psched->context[IDLE_TASK_INDEX][CTX_RUN_ID]  = 1;
-
-            }  // end for processors
-
-            // scan HWIs connected to local XCU 
-            // for round-robin allocation to processors
-            lpid = 0;
-            for ( irq_id = xcu->irq_offset ;
-                  irq_id < xcu->irq_offset + xcu->irqs ;
-                  irq_id++ )
-            {
-                unsigned int type    = irq[irq_id].srctype;
-                unsigned int srcid   = irq[irq_id].srcid;
-                unsigned int isr     = irq[irq_id].isr & 0xFFFF;
-                unsigned int channel = irq[irq_id].channel << 16;
-
-                if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
-                {
-                    _puts("\n[BOOT ERROR] Bad IRQ in XCU of cluster[");
-                    _putd( x );
-                    _puts(",");
-                    _putd( y );
-                    _puts("]\n");
-                    _exit();
-                }
-
-                _schedulers[x][y][lpid]->hwi_vector[srcid] = isr | channel | 0x80000000;
-                lpid = (lpid + 1) % cluster[cluster_id].procs; 
-
-            } // end for irqs
-        } // end if nprocs > 0
-    } // end for clusters
-
-    // If there is an external PIC component, we scan HWIs connected to PIC
-    // for Round Robin allocation (as WTI) to processors.
-    // We allocate one WTI per processor, starting from proc[0,0,0], 
-    // and we increment (cluster_id, lpid) as required.
-    if ( pic != NULL )
-    {   
-        unsigned int cluster_id = 0;   // index in clusters array
-        unsigned int lpid       = 0;   // processor local index
-
-        // scan IRQS defined in PIC
-        for ( irq_id = pic->irq_offset ;
-              irq_id < pic->irq_offset + pic->irqs ;
-              irq_id++ )
-        {
-            // compute next values for (cluster_id,lpid)
-            // if no more procesor available in current cluster
-            unsigned int overflow = 0;
-            while ( (lpid >= cluster[cluster_id].procs) ||
-                    (alloc_wti_channel[cluster_id] >= xcu->arg) )
-            {
-                overflow++;
-                cluster_id = (cluster_id + 1) % (X_SIZE*Y_SIZE);
-                lpid       = 0;
-
-                // overflow detection
-                if ( overflow > (X_SIZE*Y_SIZE*NB_PROCS_MAX*32) )
-                {
-                    _puts("\n[BOOT ERROR] Not enough processors for external IRQs\n");
-                    _exit();
-                }
-            } // end while
-
-            unsigned int type    = irq[irq_id].srctype;
-            unsigned int srcid   = irq[irq_id].srcid;
-            unsigned int isr     = irq[irq_id].isr & 0xFFFF;
-            unsigned int channel = irq[irq_id].channel << 16;
-
-            if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
-            {
-                _puts("\n[BOOT ERROR] Bad IRQ in PIC component\n");
-                _exit();
-            }
-
-            // get scheduler[cluster_id] address
-            unsigned int x          = cluster[cluster_id].x;
-            unsigned int y          = cluster[cluster_id].y;
-            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
-            psched                  = _schedulers[x][y][lpid];
-
-            // update WTI vector for scheduler[cluster_id][lpid]
-            unsigned int index            = alloc_wti_channel[cluster_id];
-            psched->wti_vector[index]     = isr | channel | 0x80000000;
-
-            // increment pointers
-            alloc_wti_channel[cluster_id] = index + 1;
-            lpid                          = lpid + 1;
-
-            // update IRQ fields in mapping for PIC initialisation
-            irq[irq_id].dest_id = index;
-            irq[irq_id].dest_xy = cluster_xy;
-
-        }  // end for IRQs
-    } // end if PIC
-                
-#if BOOT_DEBUG_SCHED
-for ( cluster_id = 0 ; cluster_id < (X_SIZE*Y_SIZE) ; cluster_id++ )
-{
-    unsigned int x          = cluster[cluster_id].x;
-    unsigned int y          = cluster[cluster_id].y;
-    unsigned int slot;
-    unsigned int entry;
-    for ( lpid = 0 ; lpid < cluster[cluster_id].procs ; lpid++ )
-    {
-        psched = _schedulers[x][y][lpid];
-        
-        _puts("\n*** IRQS for proc[");
-        _putd( x );
-        _puts(",");
-        _putd( y );
-        _puts(",");
-        _putd( lpid );
-        _puts("]\n");
-        for ( slot = 0 ; slot < 32 ; slot++ )
-        {
-            entry = psched->hwi_vector[slot];
-            if ( entry & 0x80000000 ) 
-            {
-                _puts(" - HWI ");
-                _putd( slot );
-                _puts(" / isrtype = ");
-                _putd( entry & 0xFFFF ); 
-                _puts(" / channel = ");
-                _putd( (entry >> 16) & 0x7FFF ); 
-                _puts("\n");
-            }
-        }
-        for ( slot = 0 ; slot < 32 ; slot++ )
-        {
-            entry = psched->wti_vector[slot];
-            if ( entry & 0x80000000 ) 
-            {
-                _puts(" - WTI ");
-                _putd( slot );
-                _puts(" / isrtype = ");
-                _putd( entry & 0xFFFF ); 
-                _puts(" / channel = ");
-                _putd( (entry >> 16) & 0x7FFF ); 
-                _puts("\n");
-            }
-        }
-        for ( slot = 0 ; slot < 32 ; slot++ )
-        {
-            entry = psched->pti_vector[slot];
-            if ( entry & 0x80000000 ) 
-            {
-                _puts(" - PTI ");
-                _putd( slot );
-                _puts(" / isrtype = ");
-                _putd( entry & 0xFFFF ); 
-                _puts(" / channel = ");
-                _putd( (entry >> 16) & 0x7FFF ); 
-                _puts("\n");
-            }
-        }
-    }
-}
-#endif
-
-    ///////////////////////////////////////////////////////////////////
-    // Step 2 : loop on the vspaces and the tasks  to complete
-    //          the schedulers and task contexts initialisation.
+        }
+    } 
+
+    if ( xcu == NULL )
+    {         
+        _printf("\n[BOOT ERROR] missing XCU in cluster[%d,%d]\n", x , y );
+        _exit();
+    }
+
+    // scan HWIs connected to local XCU 
+    // for round-robin allocation to local processors
+    lpid = 0;
+    for ( irq_id = xcu->irq_offset ;
+          irq_id < xcu->irq_offset + xcu->irqs ;
+          irq_id++ )
+    {
+        unsigned int type    = irq[irq_id].srctype;
+        unsigned int srcid   = irq[irq_id].srcid;
+        unsigned int isr     = irq[irq_id].isr & 0xFFFF;
+        unsigned int channel = irq[irq_id].channel << 16;
+
+        if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
+        {
+            _printf("\n[BOOT ERROR] Bad IRQ in cluster[%d,%d]\n", x, y );
+            _exit();
+        }
+
+        _schedulers[x][y][lpid]->hwi_vector[srcid] = isr | channel | 0x80000000;
+
+        lpid = (lpid + 1) % nprocs; 
+    } // end for irqs
+
+    //////////////////////////////////////////////
+    _simple_barrier_wait( &_barrier_all_clusters );
+    //////////////////////////////////////////////
+
+    ////////////////////////////////////////////////////////////////////////
+    // Step 2 : Initialise the tasks context. The context of task placed
+    //          on  processor P must be stored in the scheduler of P.
+    //          This require two nested loops: loop on the tasks, and loop 
+    //          on the local processors. We complete the scheduler when the
+    //          required placement fit one local processor.
 
     for (vspace_id = 0; vspace_id < header->vspaces; vspace_id++) 
@@ -1513,5 +1109,5 @@
         // We must set the PTPR depending on the vspace, because the start_vector 
         // and the stack address are defined in virtual space.
-        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id][0][0] >> 13) );
+        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[vspace_id][x][y] >> 13) );
 
         // loop on the tasks in vspace (task_id is the global index in mapping)
@@ -1520,20 +1116,8 @@
              task_id++) 
         {
-            // compute the cluster coordinates & local processor index
-            unsigned int x          = cluster[task[task_id].clusterid].x;
-            unsigned int y          = cluster[task[task_id].clusterid].y;
-            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
-            unsigned int lpid       = task[task_id].proclocid;                 
-
-#if BOOT_DEBUG_SCHED
-_puts("\n[BOOT DEBUG] Initialise context for task ");
-_puts( task[task_id].name );
-_puts(" in vspace ");
-_puts( vspace[vspace_id].name );
-_puts("\n");
-#endif
-            // compute gpid (global processor index) and scheduler base address
-            unsigned int gpid = (cluster_xy << P_WIDTH) + lpid;
-            psched            = _schedulers[x][y][lpid];
+            // get the required task placement coordinates [x,y,p]
+            unsigned int req_x      = cluster[task[task_id].clusterid].x;
+            unsigned int req_y      = cluster[task[task_id].clusterid].y;
+            unsigned int req_p      = task[task_id].proclocid;                 
 
             // ctx_sr : value required before an eret instruction
@@ -1541,8 +1125,8 @@
 
             // ctx_ptpr : page table physical base address (shifted by 13 bit)
-            unsigned int ctx_ptpr = (unsigned int)(_ptabs_paddr[vspace_id][x][y] >> 13);
+            unsigned int ctx_ptpr = (_ptabs_paddr[vspace_id][req_x][req_y] >> 13);
 
             // ctx_ptab : page_table virtual base address
-            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id][x][y];
+            unsigned int ctx_ptab = _ptabs_vaddr[vspace_id][req_x][req_y];
 
             // ctx_epc : Get the virtual address of the memory location containing
@@ -1556,84 +1140,246 @@
             unsigned int ctx_sp = vobj[vobj_id].vbase + vobj[vobj_id].length;
 
-            // get local task index in scheduler
-            unsigned int ltid = psched->tasks;
-
             // get vspace thread index
             unsigned int thread_id = task[task_id].trdid;
 
-            if (ltid >= IDLE_TASK_INDEX) 
+            // loop on the local processors
+            for ( lpid = 0 ; lpid < nprocs ; lpid++ )
             {
-                _puts("\n[BOOT ERROR] in boot_schedulers_init() : ");
-                _putd( ltid );
-                _puts(" tasks allocated to processor ");
-                _putd( gpid );
-                _puts(" / max is ");
-                _putd( IDLE_TASK_INDEX );
-                _puts("\n");
+                if ( (x == req_x) && (y == req_y) && (req_p == lpid) )   // fit
+                {
+                    // pointer on selected scheduler
+                    psched = _schedulers[x][y][lpid];
+
+                    // get local task index in scheduler
+                    unsigned int ltid = psched->tasks;
+
+                    // update the "tasks" and "current" fields in scheduler:
+                    psched->tasks   = ltid + 1;
+                    psched->current = 0;
+
+                    // initializes the task context 
+                    psched->context[ltid][CTX_CR_ID]     = 0;
+                    psched->context[ltid][CTX_SR_ID]     = ctx_sr;
+                    psched->context[ltid][CTX_SP_ID]     = ctx_sp;
+                    psched->context[ltid][CTX_EPC_ID]    = ctx_epc;
+                    psched->context[ltid][CTX_PTPR_ID]   = ctx_ptpr;
+                    psched->context[ltid][CTX_PTAB_ID]   = ctx_ptab;
+                    psched->context[ltid][CTX_LTID_ID]   = ltid;
+                    psched->context[ltid][CTX_GTID_ID]   = task_id;
+                    psched->context[ltid][CTX_TRDID_ID]  = thread_id;
+                    psched->context[ltid][CTX_VSID_ID]   = vspace_id;
+                    psched->context[ltid][CTX_RUN_ID]    = 1;
+
+                    psched->context[ltid][CTX_TTY_ID]    = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_CMA_FB_ID] = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_CMA_RX_ID] = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_CMA_TX_ID] = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_NIC_RX_ID] = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_NIC_TX_ID] = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_TIM_ID]    = 0xFFFFFFFF;
+                    psched->context[ltid][CTX_HBA_ID]    = 0xFFFFFFFF;
+
+#if BOOT_DEBUG_SCHED
+_printf("\nTask %s in vspace %s allocated to P[%d,%d,%d]\n"
+        " - ctx[LTID]  = %d\n"
+        " - ctx[SR]    = %x\n"
+        " - ctx[SP]    = %x\n"
+        " - ctx[EPC]   = %x\n"
+        " - ctx[PTPR]  = %x\n"
+        " - ctx[PTAB]  = %x\n"
+        " - ctx[VSID]  = %d\n"
+        " - ctx[TRDID] = %d\n",
+        task[task_id].name,
+        vspace[vspace_id].name,
+        x, y, lpid,
+        psched->context[ltid][CTX_LTID_ID],
+        psched->context[ltid][CTX_SR_ID],
+        psched->context[ltid][CTX_SP_ID],
+        psched->context[ltid][CTX_EPC_ID],
+        psched->context[ltid][CTX_PTPR_ID],
+        psched->context[ltid][CTX_PTAB_ID],
+        psched->context[ltid][CTX_VSID_ID],
+        psched->context[ltid][CTX_TRDID_ID] );
+#endif
+                } // end if FIT
+            } // end for loop on local procs
+        } // end loop on tasks
+    } // end loop on vspaces
+} // end boot_scheduler_init()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// This function loops on all processors in all clusters to display
+// the interrupt vectors for each processor.
+/////////////////////////////////////////////////////////////////////////////
+void boot_sched_irq_display()
+{
+    unsigned int         cx;
+    unsigned int         cy;
+    unsigned int         lpid;
+    unsigned int         slot;
+    unsigned int         entry;
+
+    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_cluster_t*   cluster = _get_cluster_base(header);
+
+    static_scheduler_t*  psched; 
+
+    for ( cx = 0 ; cx < X_SIZE ; cx++ )
+    {
+        for ( cy = 0 ; cy < Y_SIZE ; cy++ )
+        {
+            unsigned int cluster_id = (cx * Y_SIZE) + cy;
+            unsigned int nprocs = cluster[cluster_id].procs;
+
+            for ( lpid = 0 ; lpid < nprocs ; lpid++ )
+            {
+                psched = _schedulers[cx][cy][lpid];
+        
+                _printf("\n[BOOT] scheduler for proc[%d,%d,%d] : ntasks = %d\n",
+                        cx , cy , lpid , psched->tasks );
+
+                for ( slot = 0 ; slot < 32 ; slot++ )
+                {
+                    entry = psched->hwi_vector[slot];
+                    if ( entry & 0x80000000 ) 
+                    _printf(" - HWI %d / isrtype = %d / channel = %d\n",
+                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
+                }
+                for ( slot = 0 ; slot < 32 ; slot++ )
+                {
+                    entry = psched->wti_vector[slot];
+                    if ( entry & 0x80000000 ) 
+                    _printf(" - WTI %d / isrtype = %d / channel = %d\n",
+                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
+                }
+                for ( slot = 0 ; slot < 32 ; slot++ )
+                {
+                    entry = psched->pti_vector[slot];
+                    if ( entry & 0x80000000 ) 
+                    _printf(" - PTI %d / isrtype = %d / channel = %d\n",
+                            slot , (entry & 0xFFFF) , ((entry >> 16) & 0x7FFF) );
+                }
+            }
+        }
+    } 
+}  // end boot_sched_display()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// This function complete the schedulers initialisation when the platform
+// contains a PIC component in the IO cluster.
+// It is executed by P[0][0][0] only.
+// It scan HWIs connected to PIC for Round Robin allocation to processors,
+// as WTI. It allocates one WTI per processor, starting from P[0,0,0], 
+// and increments (cluster_id, lpid) as required.
+/////////////////////////////////////////////////////////////////////////////
+void boot_pic_wti_init()
+{
+    mapping_header_t*    header  = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
+    mapping_cluster_t*   cluster = _get_cluster_base(header);
+    mapping_periph_t*    periph  = _get_periph_base(header);
+    mapping_irq_t*       irq     = _get_irq_base(header);
+
+    unsigned int         periph_id;   // peripheral index in mapping_info
+    unsigned int         irq_id;      // irq index in mapping_info
+
+    // get cluster_io index in mapping
+    unsigned int         x_io       = header->x_io;  
+    unsigned int         y_io       = header->y_io;  
+    unsigned int         cluster_io = (x_io * Y_SIZE) + y_io; 
+    
+    // scan peripherals in cluster_io to find PIC 
+    mapping_periph_t*    pic = NULL;
+
+    for ( periph_id = cluster[cluster_io].periph_offset ;
+          periph_id < cluster[cluster_io].periph_offset + cluster[cluster_io].periphs;
+          periph_id++ )
+    {
+        if ( periph[periph_id].type == PERIPH_TYPE_PIC ) 
+        {
+            pic = &periph[periph_id];
+            break;
+        }
+    }
+
+    if ( pic == NULL )  return;
+
+    // initialize WTI channel allocators in all clusters
+    unsigned int x;
+    unsigned int y;
+    for ( x = 0 ; x < X_SIZE ; x++ )
+    {
+        for ( y = 0 ; y < Y_SIZE ; y++ )
+        {
+            _wti_channel_alloc[x][y] = NB_PROCS_MAX;
+        }
+    }
+
+    // scan IRQS defined in PIC
+    unsigned int  cluster_id = 0;
+    unsigned int  lpid       = 0;
+    unsigned int  cx         = cluster[cluster_id].x;
+    unsigned int  cy         = cluster[cluster_id].y;
+
+    for ( irq_id = pic->irq_offset ;
+          irq_id < pic->irq_offset + pic->irqs ;
+          irq_id++ )
+    {
+        // compute next values for cluster_id, lpid, cx, cy
+        // if no more WTI allocatable in current cluster
+        unsigned int overflow = 0;
+
+        while ( (lpid >= cluster[cluster_id].procs) ||
+                (_wti_channel_alloc[cx][cy] >= 16) )
+        {
+            cluster_id = (cluster_id + 1) % (X_SIZE*Y_SIZE);
+            cx         = cluster[cluster_id].x;
+            cy         = cluster[cluster_id].y;
+            lpid       = 0;
+
+            overflow++;
+
+            if ( overflow > 1024 )
+            {
+                _printf("\n[BOOT ERROR] Not enough processors for external IRQs\n");
                 _exit();
             }
-
-            // update the "tasks" and "current" fields in scheduler:
-            // the first task to execute is task 0 as soon as there is at least
-            // one task allocated to processor. 
-            psched->tasks   = ltid + 1;
-            psched->current = 0;
-
-            // initializes the task context 
-            psched->context[ltid][CTX_CR_ID]     = 0;
-            psched->context[ltid][CTX_SR_ID]     = ctx_sr;
-            psched->context[ltid][CTX_SP_ID]     = ctx_sp;
-            psched->context[ltid][CTX_EPC_ID]    = ctx_epc;
-            psched->context[ltid][CTX_PTPR_ID]   = ctx_ptpr;
-            psched->context[ltid][CTX_PTAB_ID]   = ctx_ptab;
-            psched->context[ltid][CTX_LTID_ID]   = ltid;
-            psched->context[ltid][CTX_GTID_ID]   = task_id;
-            psched->context[ltid][CTX_TRDID_ID]  = thread_id;
-            psched->context[ltid][CTX_VSID_ID]   = vspace_id;
-            psched->context[ltid][CTX_RUN_ID]    = 1;
-
-            psched->context[ltid][CTX_TTY_ID]    = 0xFFFFFFFF;
-            psched->context[ltid][CTX_CMA_FB_ID] = 0xFFFFFFFF;
-            psched->context[ltid][CTX_CMA_RX_ID] = 0xFFFFFFFF;
-            psched->context[ltid][CTX_CMA_TX_ID] = 0xFFFFFFFF;
-            psched->context[ltid][CTX_NIC_RX_ID] = 0xFFFFFFFF;
-            psched->context[ltid][CTX_NIC_TX_ID] = 0xFFFFFFFF;
-            psched->context[ltid][CTX_TIM_ID]    = 0xFFFFFFFF;
-            psched->context[ltid][CTX_HBA_ID]    = 0xFFFFFFFF;
+        } 
+        // allocate a WTI to processor defined by (cluster_id,lpid)
+        unsigned int type    = irq[irq_id].srctype;
+        unsigned int srcid   = irq[irq_id].srcid;
+        unsigned int isr     = irq[irq_id].isr & 0xFFFF;
+        unsigned int channel = irq[irq_id].channel << 16;
+
+        if ( (type != IRQ_TYPE_HWI) || (srcid > 31) )
+        {
+            _printf("\n[BOOT ERROR] in boot_pic_wti_init() Bad IRQ type\n");
+            _exit();
+        }
+
+        // get scheduler address for selected processor
+        static_scheduler_t* psched = _schedulers[cx][cy][lpid];
+
+        // update WTI vector for selected processor
+        unsigned int index            = _wti_channel_alloc[cx][cy];
+        psched->wti_vector[index]     = isr | channel | 0x80000000;
+
+        // update IRQ fields in mapping for PIC initialisation
+        irq[irq_id].dest_id = index;
+        irq[irq_id].dest_xy = (cx << Y_WIDTH) + cy;
+
+        // update pointers
+        _wti_channel_alloc[cx][cy] = index + 1;
+        lpid                       = lpid + 1;
+
+    }  // end for IRQs
 
 #if BOOT_DEBUG_SCHED
-_puts("\nTask ");
-_putd( task_id );
-_puts(" allocated to processor[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts(",");
-_putd( lpid );
-_puts("]\n  - ctx[LTID]   = ");
-_putd( psched->context[ltid][CTX_LTID_ID] );
-_puts("\n  - ctx[SR]     = ");
-_putx( psched->context[ltid][CTX_SR_ID] );
-_puts("\n  - ctx[SP]     = ");
-_putx( psched->context[ltid][CTX_SP_ID] );
-_puts("\n  - ctx[EPC]    = ");
-_putx( psched->context[ltid][CTX_EPC_ID] );
-_puts("\n  - ctx[PTPR]   = ");
-_putx( psched->context[ltid][CTX_PTPR_ID] );
-_puts("\n  - ctx[PTAB]   = ");
-_putx( psched->context[ltid][CTX_PTAB_ID] );
-_puts("\n  - ctx[GTID]   = ");
-_putx( psched->context[ltid][CTX_GTID_ID] );
-_puts("\n  - ctx[VSID]   = ");
-_putx( psched->context[ltid][CTX_VSID_ID] );
-_puts("\n  - ctx[TRDID]  = ");
-_putx( psched->context[ltid][CTX_TRDID_ID] );
-_puts("\n");
-#endif
-
-        } // end loop on tasks
-    } // end loop on vspaces
-} // end boot_schedulers_init()
-
+boot_sched_irq_display();
+#endif
+
+} // end boot_pic_wti_init()
+                
 //////////////////////////////////////////////////////////////////////////////////
 // This function loads the map.bin file from block device.
@@ -1650,12 +1396,10 @@
     if ( fd_id == -1 )
     {
-        _puts("\n[BOOT ERROR] : map.bin file not found \n");
+        _printf("\n[BOOT ERROR] : map.bin file not found \n");
         _exit();
     }
 
 #if BOOT_DEBUG_MAPPING
-_puts("\n[BOOT] map.bin file successfully open at cycle ");
-_putd(_get_proctime());
-_puts("\n");
+_printf("\n[BOOT] map.bin file successfully open at cycle %d\n", _get_proctime() );
 #endif
 
@@ -1665,16 +1409,11 @@
     if ( size > SEG_BOOT_MAPPING_SIZE )
     {
-        _puts("\n[BOOT ERROR] : allocated segment too small for map.bin file\n");
+        _printf("\n[BOOT ERROR] : allocated segment too small for map.bin file\n");
         _exit();
     }
 
 #if BOOT_DEBUG_MAPPING
-_puts("\n[BOOT] map.bin buffer pbase = ");
-_putx( SEG_BOOT_MAPPING_BASE );
-_puts(" / buffer size = ");
-_putx( SEG_BOOT_MAPPING_SIZE );
-_puts(" / file size = ");
-_putx( size );
-_puts("\n");
+_printf("\n[BOOT] map.bin buffer pbase = %x / buffer size = %x / file_size = %x\n",
+        SEG_BOOT_MAPPING_BASE , SEG_BOOT_MAPPING_SIZE , size );
 #endif
 
@@ -1691,12 +1430,10 @@
     if ( ok == -1 )
     {
-        _puts("\n[BOOT ERROR] : unable to load map.bin file \n");
+        _printf("\n[BOOT ERROR] : unable to load map.bin file \n");
         _exit();
     }
 
 #if BOOT_DEBUG_MAPPING
-_puts("\n[BOOT] map.bin file successfully loaded at cycle ");
-_putd(_get_proctime());
-_puts("\n");
+_printf("\n[BOOT] map.bin file successfully loaded at cycle %d\n", _get_proctime() );
 #endif
 
@@ -1710,29 +1447,28 @@
 
 #if BOOT_DEBUG_MAPPING
-unsigned int  word;
 unsigned int  line;
 unsigned int* pointer = (unsigned int*)SEG_BOOT_MAPPING_BASE;
-_puts("\n[BOOT] First block of mapping\n");
+_printf("\n[BOOT] First block of mapping\n");
 for ( line = 0 ; line < 8 ; line++ )
 {
-    for ( word = 0 ; word < 8 ; word++ )
-    {
-        _puts(" | ");
-        _putx( *(pointer + word) );
-    }
-    _puts(" |\n");
+    _printf(" | %x | %x | %x | %x | %x | %x | %x | %x |\n",
+            *(pointer + 0),
+            *(pointer + 1),
+            *(pointer + 2),
+            *(pointer + 3),
+            *(pointer + 4),
+            *(pointer + 5),
+            *(pointer + 6),
+            *(pointer + 7) );
+
     pointer = pointer + 8;
 }
 #endif
-        _puts("\n[BOOT ERROR] Illegal mapping signature: ");
-        _putx(header->signature);
-        _puts("\n");
+        _printf("\n[BOOT ERROR] Illegal mapping signature: %x\n", header->signature );
         _exit();
     }
 
 #if BOOT_DEBUG_MAPPING
-_puts("\n[BOOT] map.bin file checked at cycle ");
-_putd(_get_proctime());
-_puts("\n");
+_printf("\n[BOOT] map.bin file checked at cycle %d\n", _get_proctime() );
 #endif
 
@@ -1770,9 +1506,6 @@
 
 #if BOOT_DEBUG_ELF
-_puts("\n[BOOT DEBUG] Start searching file ");
-_puts( pathname );
-_puts(" at cycle ");
-_putd( _get_proctime() );
-_puts("\n");
+_printf("\n[BOOT] Start searching file %s at cycle %d\n", 
+        pathname, _get_proctime() );
 #endif
 
@@ -1783,7 +1516,5 @@
     if ( fd_id < 0 )
     {
-        _puts("\n[BOOT ERROR] load_one_elf_file() : ");
-        _puts( pathname );
-        _puts(" not found\n");
+        _printf("\n[BOOT ERROR] load_one_elf_file() : %s not found\n", pathname );
         _exit();
     }
@@ -1792,11 +1523,7 @@
     if ( fat.fd[fd_id].file_size > GIET_ELF_BUFFER_SIZE )
     {
-        _puts("\n[BOOT ERROR] in load_one_elf_file() : ");
-        _puts( pathname );
-        _puts(" size = ");
-        _putx( fat.fd[fd_id].file_size );
-        _puts("\n exceeds the GIET_ELF_BUFFERSIZE = ");
-        _putx( GIET_ELF_BUFFER_SIZE );
-        _puts("\n");
+        _printf("\n[BOOT ERROR] in load_one_elf_file() : %s / size = %x "
+                "larger than GIET_ELF_BUFFER_SIZE = %x\n",
+                pathname , fat.fd[fd_id].file_size , GIET_ELF_BUFFER_SIZE );
         _exit();
     }
@@ -1814,7 +1541,6 @@
                    0 ) != nsectors )
     {
-        _puts("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file ");
-        _puts( pathname );
-        _puts("\n");   
+        _printf("\n[BOOT ERROR] load_one_elf_file() : unexpected EOF for file %s\n",
+                pathname );
         _exit();
     }
@@ -1828,7 +1554,6 @@
          (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
     {
-        _puts("\n[BOOT ERROR] load_elf() : file ");
-        _puts( pathname );
-        _puts(" does not use ELF format\n");   
+        _printf("\n[BOOT ERROR] load_elf() : file %s does not use ELF format\n",
+                pathname );
         _exit();
     }
@@ -1838,7 +1563,6 @@
     if( pht_index == 0 )
     {
-        _puts("\n[BOOT ERROR] load_one_elf_file() : file ");
-        _puts( pathname );
-        _puts(" does not contain loadable segment\n");   
+        _printf("\n[BOOT ERROR] load_one_elf_file() : file %s "
+                "does not contain loadable segment\n", pathname );
         _exit();
     }
@@ -1847,10 +1571,4 @@
     // get number of segments
     unsigned int nsegments   = elf_header_ptr->e_phnum;
-
-    _puts("\n[BOOT] File ");
-    _puts( pathname );
-    _puts(" loaded at cycle ");
-    _putd( _get_proctime() );
-    _puts("\n");
 
     // Loop on loadable segments in the .elf file
@@ -1866,20 +1584,12 @@
 
 #if BOOT_DEBUG_ELF
-_puts(" - segment ");
-_putd( seg_id );
-_puts(" / vaddr = ");
-_putx( seg_vaddr );
-_puts(" / file_size = ");
-_putx( seg_filesz );
-_puts("\n");
+_printf("\n[BOOT] Segment %d : vaddr = %x / size = %x\n",
+        seg_id , seg_vaddr , seg_filesz );
 #endif
 
             if( seg_memsz < seg_filesz )
             {
-                _puts("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = ");
-                _putx( seg_vaddr );
-                _puts(" in file ");
-                _puts( pathname );
-                _puts(" has memsz < filesz \n");   
+                _printf("\n[BOOT ERROR] load_one_elf_file() : segment at vaddr = %x"
+                        " in file %s has memsize < filesize \n", seg_vaddr, pathname );
                 _exit();
             }
@@ -1889,5 +1599,6 @@
             {
                 unsigned int i; 
-                for( i = seg_filesz ; i < seg_memsz ; i++ ) boot_elf_buffer[i+seg_offset] = 0;
+                for( i = seg_filesz ; i < seg_memsz ; i++ ) 
+                   boot_elf_buffer[i+seg_offset] = 0;
             } 
 
@@ -1922,23 +1633,13 @@
                     
 #if BOOT_DEBUG_ELF
-_puts("   loaded into vseg ");
-_puts( vseg[vseg_id].name );
-_puts(" at paddr = ");
-_putl( seg_paddr );
-_puts(" (buffer size = ");
-_putx( seg_size );
-_puts(")\n");
+_printf("   loaded into vseg %s at paddr = %l / buffer size = %x\n",
+        vseg[vseg_id].name , seg_paddr , seg_size );
 #endif
                     // check vseg size
                     if ( seg_size < seg_filesz )
                     {
-                        _puts("\n[BOOT ERROR] in load_one_elf_file()\n");
-                        _puts("vseg ");
-                        _puts( vseg[vseg_id].name );
-                        _puts(" is to small for loadable segment ");
-                        _putx( seg_vaddr );
-                        _puts(" in file ");
-                        _puts( pathname );
-                        _puts(" \n");   
+                        _printf("\n[BOOT ERROR] in load_one_elf_file() : vseg %s "
+                                "is to small for loadable segment %x in file %s\n",
+                                vseg[vseg_id].name , seg_vaddr , pathname );
                         _exit();
                     }
@@ -1966,11 +1667,8 @@
             if ( found == 0 )
             {
-                _puts("\n[BOOT ERROR] in load_one_elf_file()\n");
-                _puts("vseg for loadable segment ");
-                _putx( seg_vaddr );
-                _puts(" in file ");
-                _puts( pathname );
-                _puts(" not found: \n");   
-                _puts(" check consistency between the .py and .ld files...\n");
+                _printf("\n[BOOT ERROR] in load_one_elf_file() : vseg for loadable "
+                        "segment %x in file %s not found "
+                        "check consistency between the .py and .ld files\n",
+                        seg_vaddr, pathname );
                 _exit();
             }
@@ -1980,4 +1678,7 @@
     // close .elf file
     _fat_close( fd_id );
+
+    _printf("\n[BOOT] File %s loaded at cycle %d\n", 
+            pathname , _get_proctime() );
 
 } // end load_one_elf_file()
@@ -2018,5 +1719,5 @@
     if (found == 0)
     {
-        _puts("[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
+        _printf("\n[BOOT ERROR] boot_elf_load() : kernel.elf file not found\n");
         _exit();
     }
@@ -2047,7 +1748,6 @@
         if (found == 0)
         {
-            _puts("[BOOT ERROR] boot_elf_load() : .elf file not found for vspace ");
-            _puts( vspace[vspace_id].name );
-            _puts("\n");
+            _printf("\n[BOOT ERROR] boot_elf_load() : "
+                    ".elf file not found for vspace %s\n", vspace[vspace_id].name );
             _exit();
         }
@@ -2090,9 +1790,5 @@
 
 #if BOOT_DEBUG_PERI
-_puts("\n[BOOT DEBUG] Peripherals initialisation in cluster[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("]\n");
+_printf("\n[BOOT] Peripherals initialisation in cluster[%d,%d]\n", x , y );
 #endif
 
@@ -2171,19 +1867,6 @@
 
 #if BOOT_DEBUG_PERI
-unsigned int address = _pic_get_register( channel_id, IOPIC_ADDRESS );
-unsigned int extend  = _pic_get_register( channel_id, IOPIC_EXTEND  );
-_puts("    hwi_index = ");
-_putd( hwi_id );
-_puts(" / wti_index = ");
-_putd( wti_id );
-_puts(" / vaddr = ");
-_putx( vaddr );
-_puts(" in cluster[");
-_putd( cluster_xy >> Y_WIDTH );
-_puts(",");
-_putd( cluster_xy & ((1<<Y_WIDTH)-1) );
-_puts("] / checked_xcu_paddr = ");
-_putl( (paddr_t)address + (((paddr_t)extend)<<32) );
-_puts("\n");
+_printf("[BOOT] PIC : hwi_index = %d => wti_index = %d for XCU[%d,%d]\n",
+        hwi_id , wti_id , cluster_xy >> Y_WIDTH , cluster_xy & ((1<<Y_WIDTH)-1) ); 
 #endif
                     }
@@ -2194,9 +1877,5 @@
 
 #if BOOT_DEBUG_PERI
-_puts("\n[BOOT DEBUG] Coprocessors initialisation in cluster[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("]\n");
+_printf("\n[BOOT] Coprocessors initialisation in cluster[%d,%d]\n", x , y );
 #endif
 
@@ -2206,12 +1885,4 @@
               cluster[cluster_id].coprocs; coproc_id++ ) 
         {
-
-#if BOOT_DEBUG_PERI
-_puts("- coprocessor name : ");
-_puts(coproc[coproc_id].name);
-_puts(" / nb ports = ");
-_putd((unsigned int) coproc[coproc_id].ports);
-_puts("\n");
-#endif
             // loop on the coprocessor ports
             for ( cp_port_id = coproc[coproc_id].port_offset;
@@ -2241,13 +1912,5 @@
                               cp_port[cp_port_id].direction, 
                               pbase );
-#if BOOT_DEBUG_PERI
-_puts("     port direction: ");
-_putd( (unsigned int)cp_port[cp_port_id].direction );
-_puts(" / mwmr_channel_pbase = ");
-_putl( pbase );
-_puts(" / name = ");
-_puts(vobj[vobj_id].name);
-_puts("\n"); 
-#endif
+
             } // end for cp_ports
         } // end for coprocs
@@ -2255,10 +1918,10 @@
 } // end boot_peripherals_init()
 
-/////////////////////////////////////////////////////////////////////////
-// This function initialises the physical memory allocators in each
-// cluster containing a RAM pseg.
-// it is handled by the processor[x][y][0]
-/////////////////////////////////////////////////////////////////////////
-void boot_pmem_init() 
+///////////////////////////////////////////////////////////////////////////////////////
+// This function is executed in parallel by all processors[x][y][0].
+// It initialises the physical memory allocator in each cluster containing a RAM pseg.
+///////////////////////////////////////////////////////////////////////////////////////
+void boot_pmem_init( unsigned int cx,
+                     unsigned int cy ) 
 {
     mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
@@ -2266,56 +1929,47 @@
     mapping_pseg_t*    pseg       = _get_pseg_base(header);
 
-    unsigned int cluster_id;
     unsigned int pseg_id;
     unsigned int procid     = _get_procid();
-    unsigned int x_cluster  = (procid >> (Y_WIDTH + P_WIDTH)) & ((1<<X_WIDTH)-1);
-    unsigned int y_cluster  = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
     unsigned int lpid       = procid & ((1<<P_WIDTH)-1);
-    if(lpid)
-    {
-        _puts("[BOOT ERROR] boot_pmem_init() : error local processor id\n");
+
+    if( lpid )
+    {
+        _printf("\n[BOOT ERROR] boot_pmem_init() : "
+        "P[%d][%d][%d] should not execute it\n", cx, cy, lpid );
         _exit();
-    }      // scan all clusters
-
-    cluster_id = x_cluster * Y_SIZE + y_cluster;
-    // scan the psegs in cluster to find first pseg of type RAM
-    unsigned int pseg_min = cluster[cluster_id].pseg_offset;
-    unsigned int pseg_max = pseg_min + cluster[cluster_id].psegs;
+    }   
+
+    // scan the psegs in local cluster to find  pseg of type RAM
+    unsigned int found      = 0;
+    unsigned int cluster_id = cx * Y_SIZE + cy;
+    unsigned int pseg_min   = cluster[cluster_id].pseg_offset;
+    unsigned int pseg_max   = pseg_min + cluster[cluster_id].psegs;
     for ( pseg_id = pseg_min ; pseg_id < pseg_max ; pseg_id++ )
     {
         if ( pseg[pseg_id].type == PSEG_TYPE_RAM )
         {
-            unsigned int x    = cluster[cluster_id].x;
-            unsigned int y    = cluster[cluster_id].y;
-            if(x != x_cluster || y != y_cluster)
-            {
-                _puts("[BOOT ERROR] boot_pmem_init() : error cluster id \n");
-                _exit();
-            }  
             unsigned int base = (unsigned int)pseg[pseg_id].base;
             unsigned int size = (unsigned int)pseg[pseg_id].length;
-            _pmem_alloc_init( x, y, base, size );
+            _pmem_alloc_init( cx, cy, base, size );
+            found = 1;
 
 #if BOOT_DEBUG_PT
-_get_lock(&lock_tty);
-_puts("\n[BOOT DEBUG] pmem allocator initialised in cluster[");
-_putd( x );
-_puts(",");
-_putd( y );
-_puts("] base = ");
-_putx( base );
-_puts(" / size = ");
-_putx( size );
-_puts("\n");
-_release_lock(&lock_tty);
+_printf("\n[BOOT] pmem allocator initialised in cluster[%d][%d]"
+        " : base = %x / size = %x\n", cx , cy , base , size );
 #endif
             break;
         }
     }
+
+    if ( found == 0 )
+    {
+        _printf("\n[BOOT ERROR] boot_pmem_init() : no RAM in cluster[%d][%d]\n",
+              cx , cy );
+        _exit();
+    }   
 } // end boot_pmem_init()
  
 /////////////////////////////////////////////////////////////////////////
 // This function is the entry point of the boot code for all processors.
-// Most of this code is executed by Processor 0 only.
 /////////////////////////////////////////////////////////////////////////
 void boot_init() 
@@ -2323,135 +1977,165 @@
     mapping_header_t*  header     = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
     mapping_cluster_t* cluster    = _get_cluster_base(header);
+
     unsigned int       gpid       = _get_procid();
-    unsigned int       clusterid, p;
-
-    if ( gpid == 0 )    // only Processor 0 does it
-    {
-        _puts("\n[BOOT] boot_init start at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
+    unsigned int       cx         = gpid >> (Y_WIDTH + P_WIDTH);
+    unsigned int       cy         = (gpid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
+    unsigned int       lpid       = gpid & ((1 << P_WIDTH) -1);
+    unsigned int       cluster_id = (cx * Y_SIZE) + cy;
+
+    // Phase ONE : only P[0][0][0] execute it
+    if ( gpid == 0 )    
+    {
+        unsigned int cid;  // index for loops 
+
+        // initialises the TTY0 spin lock
+        _spin_lock_init( &_tty0_spin_lock );
+
+        _printf("\n[BOOT] P[0,0,0] starts at cycle %d\n", _get_proctime() );
 
         // initialises the FAT
         _fat_init( IOC_BOOT_MODE );
 
-        _puts("\n[BOOT] Fat initialised at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-        // Load the map.bin file into memory and check it
+        _printf("\n[BOOT] FAT initialised at cycle %d\n", _get_proctime() );
+
+        // Load the map.bin file into memory 
         boot_mapping_init();
 
-        _puts("\n[BOOT] Mapping \"");
-        _puts( header->name );
-        _puts("\" loaded at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-
-        _barrier_init(&barrier_boot, X_SIZE*Y_SIZE);
-
-        for ( clusterid = 1 ; clusterid < X_SIZE*Y_SIZE ; clusterid++ ) 
-        {
-            unsigned int x          = cluster[clusterid].x;
-            unsigned int y          = cluster[clusterid].y;
-            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
-
-            _xcu_send_wti_paddr( cluster_xy, 0, (unsigned int)boot_entry );
-        }
-    }
-    //Parallel phase to construct the ptab by each processor[x][y][0] 
-    if( (gpid & ((1 << P_WIDTH) -1)) == 0)
-    {
-        // Initializes the physical memory allocators
-        boot_pmem_init();
-        // Build ge tables
-        boot_ptabs_init();
-        //wait for all processors finished the work
-        _barrier_wait(&barrier_boot);
-
-        if( gpid ) while( boot_init_ok == 0);
-    }
-
-    if ( gpid == 0 )    // only Processor 0 does it
-    {
-        _puts("\n[BOOT] Physical memory allocators and Page table initialized at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-
-        // Activate MMU for proc [0,0,0]
-        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][0][0]>>13) );
+        _printf("\n[BOOT] Mapping %s loaded at cycle %d\n",
+                header->name , _get_proctime() );
+
+        // initialises the barrier for all clusters containing processors
+        unsigned int nclusters = 0;
+        for ( cid = 0 ; cid < X_SIZE*Y_SIZE ; cid++ )
+        {
+            if ( cluster[cid].procs ) nclusters++ ;
+        } 
+
+        _simple_barrier_init( &_barrier_all_clusters , nclusters );
+
+        // wake up all processors P[x][y][0]
+        for ( cid = 1 ; cid < X_SIZE*Y_SIZE ; cid++ ) 
+        {
+            unsigned int x          = cluster[cid].x;
+            unsigned int y          = cluster[cid].y;
+            unsigned int cluster_xy = (x << Y_WIDTH) + y;
+
+            if ( cluster[cid].procs ) 
+            {
+                unsigned long long paddr = (((unsigned long long)cluster_xy)<<32) +
+                                           SEG_XCU_BASE + XCU_REG( XCU_WTI_REG , 0 );
+
+                _physical_write( paddr , (unsigned int)boot_entry );
+            }
+        }
+
+        _printf("\n[BOOT] Processors P[x,y,0] start at cycle %d\n", _get_proctime() );
+    }
+
+    // Phase TWO : All processors P[x][y][0] execute it in parallel
+    if( lpid == 0 )
+    {
+        // Initializes physical memory allocator in cluster[cx][cy]
+        boot_pmem_init( cx , cy );
+
+        // Build page table in cluster[cx][cy]
+        boot_ptab_init( cx , cy );
+
+        //////////////////////////////////////////////
+        _simple_barrier_wait( &_barrier_all_clusters );
+        //////////////////////////////////////////////
+
+        // P[0][0][0] complete page tables with vsegs 
+        // mapped in clusters without processors 
+        if ( gpid == 0 )   
+        {
+            // complete page tables initialisation
+            boot_ptab_extend();
+
+            _printf("\n[BOOT] Physical memory allocators and page tables"
+                    " initialized at cycle %d\n", _get_proctime() );
+        }
+
+        //////////////////////////////////////////////
+        _simple_barrier_wait( &_barrier_all_clusters );
+        //////////////////////////////////////////////
+
+        // All processors P[x,y,0] activate MMU (using local PTAB) 
+        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][cx][cy]>>13) );
         _set_mmu_mode( 0xF );
-
-        _puts("\n[BOOT] Processor[0,0,0] : MMU activation at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-
-        // Initialise private vobjs in vspaces
-        boot_vobjs_init();
-
-        _puts("\n[BOOT] Private vobjs initialised at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-  
-        // Initialise schedulers
-        boot_schedulers_init();
-
-        _puts("\n[BOOT] Schedulers initialised at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
         
-        // Set CP0_SCHED register for proc [0,0,0]
-        _set_sched( (unsigned int)_schedulers[0][0][0] );
-
-        // Initialise non replicated peripherals
-        boot_peripherals_init();
-
-        _puts("\n[BOOT] Non replicated peripherals initialised at cycle ");
-        _putd(_get_proctime());
-        _puts("\n");
-
-        // Loading all .elf files
-        boot_elf_load();
-
-        // wake up the processors which has constructed the ptab before
-        boot_init_ok = 1;
-
-        for ( clusterid = 0 ; clusterid < X_SIZE*Y_SIZE ; clusterid++ ) 
-        {
-            unsigned int nprocs     = cluster[clusterid].procs;
-            unsigned int x          = cluster[clusterid].x;
-            unsigned int y          = cluster[clusterid].y;
-            unsigned int cluster_xy = (x<<Y_WIDTH) + y;
-
-            for ( p = 1 ; p < nprocs; p++ ) 
+        // Each processor P[x,y,0] initialises all schedulers in cluster[x,y]
+        boot_scheduler_init( cx , cy );
+
+        // Each processor P[x][y][0] initialises its CP0_SCHED register
+        _set_sched( (unsigned int)_schedulers[cx][cy][0] );
+
+        //////////////////////////////////////////////
+        _simple_barrier_wait( &_barrier_all_clusters );
+        //////////////////////////////////////////////
+        
+        // Processor P[0,0,0] completes schedulers with PIC-WTI 
+        // initialises external peripherals and load .elf files.
+        if ( gpid == 0 ) 
+        {
+            // complete schedulers initialisation
+            boot_pic_wti_init();
+
+            _printf("\n[BOOT] Schedulers initialised at cycle %d\n", _get_proctime() );
+
+            // initialize non replicated peripherals
+            boot_peripherals_init();
+
+            _printf("\n[BOOT] Peripherals initialised at cycle %d\n", _get_proctime() );
+
+            // Loading all .elf files
+            boot_elf_load();
+        }
+/*  
+        // Each processor P[x][y][0] checks sequencially its local page table
+        unsigned int seq_x;
+        unsigned int seq_y;
+        for ( seq_x = 0 ; seq_x < X_SIZE ; seq_x++ )
+        {
+            for ( seq_y = 0 ; seq_y < Y_SIZE ; seq_y++ )
             {
-                _xcu_send_wti( cluster_xy, p, (unsigned int)boot_entry );
+                if ( (cx == seq_x) && (cy == seq_y) ) boot_ptab_check( cx , cy );
+                
+                //////////////////////////////////////////////
+                _simple_barrier_wait( &_barrier_all_clusters );
+                //////////////////////////////////////////////
             }
         }
-    }  // end monoprocessor boot
-
-    ///////////////////////////////////////////////////////////////////////////////
-    //            Parallel execution starts actually here
-    ///////////////////////////////////////////////////////////////////////////////
-
-    // all processor initialise the SCHED register
-    // from the _schedulers[x][y][lpid array]
-    unsigned int cluster_xy = gpid >> P_WIDTH;
-    unsigned int lpid       = gpid & ((1<<P_WIDTH)-1);
-    unsigned int x          = cluster_xy >> Y_WIDTH;
-    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
-    _set_sched( (unsigned int)_schedulers[x][y][lpid] );
-
-    // all processors (but Proc[0,0,0]) activate MMU
-    if ( gpid != 0 )
-    {
-        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][x][y]>>13) );
+*/          
+        //////////////////////////////////////////////
+        _simple_barrier_wait( &_barrier_all_clusters );
+        //////////////////////////////////////////////
+        
+        // each processor P[x][y][0] wake up other processors in same cluster
+        unsigned int cluster_xy = (cx << Y_WIDTH) + cy;
+        unsigned int p;
+        for ( p = 1 ; p < cluster[cluster_id].procs ; p++ )
+        {
+            _xcu_send_wti( cluster_xy , p , (unsigned int)boot_entry );
+        }
+
+        if ( gpid == 0 )    // only P[0][0][0] makes display
+        _printf("\n[BOOT] All processors start at cycle %d\n", _get_proctime() );
+    }
+
+    // Other processors than P[x][y][0] activate MMU (using local PTAB)
+    if ( lpid != 0 )
+    {
+        _set_mmu_ptpr( (unsigned int)(_ptabs_paddr[0][cx][cy]>>13) );
         _set_mmu_mode( 0xF );
     }
 
-    // all processors reset BEV bit in the status register to use
-    // the GIET_VM exception handler instead of the PRELOADER exception handler
+    // All processors set CP0_SCHED register 
+    _set_sched( (unsigned int)_schedulers[cx][cy][lpid] );
+
+    // All processors reset BEV bit in SR to use GIET_VM exception handler 
     _set_sr( 0 );
 
-    // all processors jump to kernel_init 
-    // using the address defined in the giet_vsegs.ld file
+    // All processors jump to kernel_init 
     unsigned int kernel_entry = (unsigned int)&kernel_init_vbase;
     asm volatile( "jr   %0" ::"r"(kernel_entry) );
