Index: /trunk/softs/giet_tsar/giet.S
===================================================================
--- /trunk/softs/giet_tsar/giet.S	(revision 628)
+++ /trunk/softs/giet_tsar/giet.S	(revision 629)
@@ -169,52 +169,52 @@
     /* It depends on both the cluster_xy & local_id,  */
     /* and we must use the physical address extension */
-    mfc0    $10,    $15,    1       /* $10 <= proc_id */
-    andi    $10,    $10,    0x3FF   /* at most 1024 processors */ 
+    mfc0    $10,    $15,    1        /* $10 <= proc_id                                 */
+    andi    $10,    $10,    0x3FF    /* at most 1024 processors                        */ 
     li      $11,    NB_PROCS_MAX
     divu    $10,    $11
-    mflo    $12                      /* $12 <= cluster_xy */
-    mfhi    $13                      /* $13 <= local_id */
-
-    li      $7,     0b011110000000   /* $7 <= PRIO offset */
-    sll     $8,     $13,    2        /* $8 <= local_id*4 */
-    addu    $9,     $7,     $8       /* $9 <= PRIO offset + local_id*4 */
-    la      $27,    seg_xcu_base    
-    addu    $26,    $9,     $27      /* $26 <= seg_icu_base + PRIO offset + local_id*4 */
-
-    /* XCU[cluster_xy] access to get PRIO register value */
-    mtc2    $12,    $24              /* set PADDR extension */
-    lw      $14,    ($26)            /* $14 <= PRIO register value */
-    mtc2    $0,     $24              /* reset PADDR extension */
-
-    /* test PTI, then HWI, then WTI */
-    andi    $27,    $14,    0x1      /* test bit T in PRIO register */
-    bne     $27,    $0,     _int_PTI /* branch to PTI handler */
-    andi    $27,    $14,    0x2      /* test bit W in PRIO register */
-    bne     $27,    $0,     _int_HWI /* branch to HWI handler */
-    andi    $27,    $14,    0x4      /* test bit W in PRIO register */
-    bne     $27,    $0,     _int_WTI /* branch to IPI handler */
+    mflo    $12                      /* $12 <= cluster_xy                              */
+    mfhi    $13                      /* $13 <= local_id                                */
+    la      $14,    seg_xcu_base     /* $14 <= seg_xcu_base                            */
+
+    li      $7,     0b011110000000   /* $7 <= PRIO offset                              */
+    sll     $8,     $13,    2        /* $8 <= local_id*4                               */
+    addu    $9,     $7,     $8       /* $9 <= PRIO offset + local_id*4                 */
+    addu    $26,    $9,     $14      /* $26 <= seg_icu_base + PRIO offset + local_id*4 */
+
+    /* XCU[cluster_xy] access to get PRIO register value                               */
+    mtc2    $12,    $24              /* set PADDR extension                            */
+    lw      $15,    ($26)            /* $15 <= PRIO register value                     */
+    mtc2    $0,     $24              /* reset PADDR extension                          */
+
+    /* test PTI, then HWI, then WTI                                                    */
+    andi    $27,    $15,    0x1      /* test bit T in PRIO register                    */
+    bne     $27,    $0,     _int_PTI /* branch to PTI handler                          */
+    andi    $27,    $15,    0x2      /* test bit W in PRIO register                    */
+    bne     $27,    $0,     _int_HWI /* branch to HWI handler                          */
+    andi    $27,    $15,    0x4      /* test bit W in PRIO register                    */
+    bne     $27,    $0,     _int_WTI /* branch to WTI handler                          */
     
     /* exit interrupt handler: restore registers */
 _int_restore:
     .set noat
-    lw      $1,     4*4($29)         /* restore $1 */
+    lw      $1,     4*4($29)
     .set at
-    lw      $2,     4*5($29)         /* restore $2 */
-    lw      $3,     4*6($29)         /* restore $3 */
-    lw      $4,     4*7($29)         /* restore $4 */
-    lw      $5,     4*8($29)         /* restore $5 */
-    lw      $6,     4*9($29)         /* restore $6 */
-    lw      $7,     4*10($29)        /* restore $7 */
-    lw      $8,     4*11($29)        /* restore $8 */
-    lw      $9,     4*12($29)        /* restore $9 */
-    lw      $10,    4*13($29)        /* restore $10 */
-    lw      $11,    4*14($29)        /* restore $11 */
-    lw      $12,    4*15($29)        /* restore $12 */
-    lw      $13,    4*16($29)        /* restore $13 */
-    lw      $14,    4*17($29)        /* restore $14 */
-    lw      $15,    4*18($29)        /* restore $15 */
-    lw      $24,    4*19($29)        /* restore $24 */
-    lw      $25,    4*20($29)        /* restore $25 */
-    lw      $31,    4*21($29)        /* restore $31 */
+    lw      $2,     4*5($29) 
+    lw      $3,     4*6($29) 
+    lw      $4,     4*7($29)
+    lw      $5,     4*8($29) 
+    lw      $6,     4*9($29)
+    lw      $7,     4*10($29) 
+    lw      $8,     4*11($29)
+    lw      $9,     4*12($29)
+    lw      $10,    4*13($29)
+    lw      $11,    4*14($29)
+    lw      $12,    4*15($29)
+    lw      $13,    4*16($29)
+    lw      $14,    4*17($29)
+    lw      $15,    4*18($29)
+    lw      $24,    4*19($29)
+    lw      $25,    4*20($29)
+    lw      $31,    4*21($29)
     lw      $27,    4*22($29)        /* get EPC */ 
     addiu   $29,    $29,    23*4     /* restore SP */
@@ -222,30 +222,50 @@
     eret                             /* exit GIET */
 
+    /* The PTI handler get PTI index, */
+    /* acknowledge the PTI register   */
+    /* and call the corresponding ISR */
 _int_PTI:
-    srl     $26,    $14,    6        /* $26 <= (PRIO>>6  = PTI index) */ 
-    j       _int_call_isr
-    nop
-
-_int_HWI:
-    srl     $26,    $14,    14       /* $26 <= (PRIO>>14 = HWI index) */
-    j       _int_call_isr
-    nop
-
-_int_WTI:
-    srl     $26,    $14,    22       /* $26 <= (PRIO>>22 = WTI index) */
-    j       _int_call_isr
-    nop
-    
-    /* Call the relevant ISR */
-_int_call_isr:
-    andi    $26,    $26,    0x7C     /* $26 <= interrupt_index * 4 */
+    srl     $26,    $15,    6        /* $26 <= PRIO >> 6             */
+    andi    $26,    $26,    0x7C     /* $26 <= PTI_INDEX * 4         */
+    addi    $27,    $14,    0x180    /* $27 <= &PTI_ACK[0]           */
+    add     $27,    $27,    $26      /* $27 <= &PTI_ACK[PTI_INDEX]   */
+    lw      $0,     ($27)            /* acknowledge XICU PTI         */
     la      $27,    _interrupt_vector
     addu    $26,    $26,    $27
-    lw      $26,    ($26)            /* read ISR address */ 
-    jalr    $26                      /* call ISR */
-    nop
-    j       _int_restore
-    nop
-
+    lw      $26,    ($26)            /* read ISR address             */ 
+    jalr    $26                      /* call ISR                     */
+    nop
+    j       _int_restore             /* return from INT handler      */
+    nop
+
+    /* The HWI handler get HWI index  */
+    /* and call the corresponding ISR */
+_int_HWI:
+    srl     $26,    $15,    14       /* $26 <= PRIO >> 14            */
+    andi    $26,    $26,    0x7C     /* $26 <= HWI_INDEX * 4         */
+    la      $27,    _interrupt_vector
+    addu    $26,    $26,    $27      /* $26 <= &ISR[HWI_INDEX        */
+    lw      $26,    ($26)            /* read ISR address             */ 
+    jalr    $26                      /* call ISR                     */
+    nop
+    j       _int_restore             /* return from INT handler      */
+    nop
+
+    /* The WTI handler get WTI index, */
+    /* acknowledge the WTI register   */
+    /* and call the corresponding ISR */
+_int_WTI:
+    srl     $26,    $15,    22       /* $26 <= PRIO >> 22            */
+    andi    $26,    $26,    0x7C     /* $26 <= WTI_INDEX * 4         */
+    add     $27,    $14,    $26      /* $27 <= &WTI_REG[WTI_INDEX]   */
+    lw      $0,     ($27)            /* acknowledge XICU WTI         */
+    la      $27,    _interrupt_vector
+    addu    $26,    $26,    $27      /* $26 <= &ISR[WTI_INDEX]       */
+    lw      $26,    ($26)            /* read ISR address             */ 
+    jalr    $26                      /* call ISR                     */
+    nop
+    j       _int_restore             /* return from INT handler */
+    nop
+    
 /* The default ISR is called when no specific ISR has been installed */
 /* in the interrupt vector. It simply displays a message on TTY0     */
Index: /trunk/softs/giet_tsar/reset.S
===================================================================
--- /trunk/softs/giet_tsar/reset.S	(revision 628)
+++ /trunk/softs/giet_tsar/reset.S	(revision 629)
@@ -10,14 +10,24 @@
 *
 * As we don't want to use the virtual memory, the physical address is 
-* equal to  the virtual address (identity mapping) and all processors use
-* the physical memory bank in cluster 0. Both the reset base address and 
-* the kernel base address can be redefined to use a physical memory bank
-* smaller than 4 Gbytes.
+* equal to  the virtual address (identity mapping) and all processors stacks
+* and code segments are allocated in the physical memory bank in cluster 0. 
+*
+* Both the reset base address and the kernel base address must be redefined
+* to use a physical memory bank smaller than 2 Gbytes.
 *
 * There is one XCU iand one MMC per cluster.
-* All other peripherals (including the boot ROM) are located in cluster 0.
-* Only two HWI interrupts are supported:
-* - IRQ_IN[0]      IOC 
-* - IRQ_IN[12]     MMC
+*
+* There is one IOPIC component in cluster_io.
+*
+* There is two sets of peripherals:
+*
+* 1) A block device and a single channel TTY controller are available 
+*    in cluster(0,0).
+*
+* 2) Other peripherals (including another Blockdevice, a multi-channels TTY 
+*    contrÃŽler, a Frame buffer) are located in cluster_io.
+*    For those externals peripherals, hardware interrupts (HWI) are translated
+*    to software interrupts (WTI) by and IOPIC component, that is programmed
+*    to route all SWI to to processor 0 in cluster (0,0).
 *
 * The boot sequence is the following:
@@ -25,4 +35,5 @@
 *   - Each processor initializes the CP0 EBASE register
 *	- Only processor 0 initializes the Interrupt vector.
+*	- Only processor 0 initializes the IOPIC component.
 *   - Each processor initializes its private XCU mask.
 *	- Each processor initializes the Status Register (SR) 
@@ -37,8 +48,10 @@
 	.extern	seg_stack_base
 	.extern	seg_xcu_base
+	.extern	seg_pic_base
     .extern seg_kcode_base
 	.extern _interrupt_vector
 	.extern _ioc_isr
 	.extern _mmc_isr
+    .extern _tty_isr
     .extern main
 
@@ -62,5 +75,5 @@
     la      $27,    seg_stack_base
     addi    $26,    $10,    1		    /* $26 <= (proc_id + 1)           */
-    sll     $26,    $26,    16          /* $26 <= (proc_id + 1) * 64K     */
+    sll     $26,    $26,    14          /* $26 <= (proc_id + 1) * 16K     */
     addu    $29,    $27,    $26		    /* $29 <= seg_stack_base(proc_id) */
 
@@ -69,24 +82,55 @@
     mtc0    $26,    CP0_EBASE           /* CP0_EBASE <= seg_kcode_base */
 
-/* only proc (0,0,0) initializes interrupt vector */
+/* only proc (0,0,0) initializes interrupt vector for IOC, TTY, MMC     */
     bne	    $10,    $0,    reset_xcu
     nop
 
-    la      $26,    _interrupt_vector   /* interrupt vector address */
+    la      $26,    _interrupt_vector   /* interrupt vector address                */
+    la      $27,    _mmc_isr 
+    sw      $27,    32($26)             /* interrupt_vector[8] <= _mmc_isr         */
     la      $27,    _ioc_isr 
-    sw      $27,     0($26)             /* interrupt_vector[0] <= _isr_ioc */
-    la      $27,    _mmc_isr 
-    sw      $27,     48($26)            /* interrupt_vector[12] <= _isr_mmc */
-    
+    sw      $27,    36($26)             /* interrupt_vector[9] <= _ioc_isr         */
+    la      $27,    _tty_isr 
+    sw      $27,    40($26)             /* interrupt_vector[10] <= _tty_isr        */
+
+/* only proc (0,0,0) initializes IOPIC : IOPIC_ADDRESS[i] <= &XICU[0].WTI_REG[i]   */
+
+    li      $20,    X_SIZE
+    addi    $20,    $20,    -1
+    sll     $20,    $20,    4
+    li      $21,    Y_SIZE
+    add     $22,    $20,    $21         /* $22 <= cluster(X_SIZE-1, Y_SIZE)        */
+
+    mtc2    $22,    CP2_PADDR_EXT       /* CP2_PADDR_EXT <= cluster_io             */
+
+    li      $24,    16                  /* $24  iteration (de)counter              */
+    la      $27,    seg_xcu_base        /* $27 <= &(XICU[0].WTI_REG[0])            */
+    la      $26,    seg_pic_base        /* $26 <= &IOPIC_ADDRESS[0]                */
+
+reset_loop:
+    sw      $27,    0($26)              /* IOPIC_ADDRESS[i] <= &XICU[0].WTI_REG[i] */
+    addi    $24,    $24,    -1          /* decrement iteration index               */
+    addi    $27,    $27,     4          /* $27 <= &(XICU[0].WTI_REG[i++]           */
+    addi    $26,    $26,     16         /* $26 <= &IOPIC_ADDRESS[i++]              */
+    bne     $24,    $0, reset_loop
+    nop
+
+    mtc2    $0,     CP2_PADDR_EXT       /* CP2_PADDR_EXT <= zero                   */
+   
 reset_xcu:
 
-/* only proc (x,y,0) receive IRQs and initialise its private XCU mask */
+/* only proc (x,y,0) receive IRQs and initialise HWI and WTI XICU masks */
     bne     $11,    $0,     reset_end
     nop
     la      $26,    seg_xcu_base
-    li      $27,    0b010010000000      /* offset for MSK_HWI_ENABLE & lpid == 0 */
-    addu    $24,    $26,    $27         /* $24 <= &MASK  */
-    li      $25,    0x00001001		    /* IOC: IRQ[0] / MEMC: IRQ[12] */
-    sw      $25,    0($24)              /* set MASK */
+    li      $27,    0b010010000000      /* offset for MSK_HWI_ENABLE[lpid == 0]    */
+    addu    $24,    $26,    $27         /* $24 <= &HWI_MASK                        */
+    li      $25,    0x0700		        /* TTY:HWI[10]  IOC:HWI[9]  MEMC:HWI[8]    */
+    sw      $25,    0($24)              /* set HWI mask                            */
+
+    li      $27,    0b011010000000      /* offset for MSK_WTI_ENABLE[lpid == 0]    */
+    addu    $24,    $26,    $27         /* $24 <= $WTI_MASK                        */
+    li      $25,    0xFFFFFFFF          /* all WTI enabled                         */
+    sw      $25,    0($24)              /* set WTI mask                            */
 
 reset_end:
Index: /trunk/softs/giet_tsar/stdio.c
===================================================================
--- /trunk/softs/giet_tsar/stdio.c	(revision 628)
+++ /trunk/softs/giet_tsar/stdio.c	(revision 629)
@@ -4,5 +4,5 @@
 // Date : janvier 2014 
 //
-// This file define varions functions that can be used by applications to access
+// This file defines various functions that can be used by applications to access
 // peripherals, for the TSAR multi-processors multi_clusters architecture.
 // There is NO separation between application code and system code, as the
@@ -22,4 +22,5 @@
 // - NB_PROCS_MAX    : max number of processor per cluster
 // - NB_TTY_CHANNELS : max number of TTY channels
+// - USE_EXT_IO      : use external peripherals if not zero
 //
 // The follobing base addresses must be defined in the ldscript
@@ -31,4 +32,43 @@
 #include "stdio.h"
 
+#if !defined(NB_PROCS_MAX)
+#error: you must define NB_PROCS_MAX in the hard_config.h file
+#endif
+
+#if !defined(USE_EXT_IO)
+#error: you must define USE_EXT_IO in the hard_config.h file
+#endif
+
+#if !defined(X_SIZE)
+#error: you must define X_SIZE in the hard_config.h file
+#endif
+
+#if !defined(Y_SIZE)
+#error: you must define Y_SIZE in the hard_config.h file
+#endif
+
+#if !defined(X_WIDTH)
+#error: you must define X_WIDTH in the hard_config.h file
+#endif
+
+#if (X_WIDTH != 4)
+#error: The X_WIDTH parameter must be equal to 4
+#endif
+
+#if !defined(Y_WIDTH)
+#error: you must define X_WIDTH in the hard_config.h file
+#endif
+
+#if (X_WIDTH != 4)
+#error: The Y_WIDTH parameter must be equal to 4
+#endif
+
+#if !defined(NB_TTY_CHANNELS)
+#error: you must define NB_TTY_CHANNELS in the hard_config.h file
+#endif
+
+
+
+
 #define NB_LOCKS      256
 #define NB_BARRIERS   16
@@ -74,5 +114,5 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////
-// Taken from MutekH.
+// Memcopy taken from MutekH.
 ////////////////////////////////////////////////////////////////////////////////////////
 in_drivers void* _memcpy( void*        _dst, 
@@ -100,5 +140,30 @@
     return _dst;
 }
-
+////////////////////////////////////////////////////////////////////////////////////////
+// Memcopy using extended addresses
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers void  _extended_memcpy( unsigned int dst_cluster,
+                                   unsigned int dst_address,
+                                   unsigned int src_cluster,
+                                   unsigned int src_address,
+                                   unsigned int length )
+{
+    if ( (dst_address & 0x3) || (src_address & 0x3) || (length & 0x3) )
+    {
+        _tty_get_lock( 0 );
+        _tty_puts( "ERROR in _extended_memcpy()" );
+        _tty_release_lock( 0 );
+        _exit();
+    }
+
+    unsigned int i;
+    unsigned int word;
+
+    for ( i = 0 ; i < length ; i = i+4 )
+    {
+        word = _word_extended_read( src_cluster, (src_address + i) );
+        _word_extended_write( dst_cluster, (dst_address + i), word );
+    }
+}
 ////////////////////////////////////////////////////////////////////////////////////////
 // Access CP0 and returns processor ident
@@ -179,6 +244,113 @@
 }
 
-///////////////////////////////////////////////////////////////////////////////////////
-// Exit (suicide) after printing message on  a TTY terminal.
+////////////////////////////////////////////////////////////////////////////
+// This function makes a physical read access to a 32 bits word in memory, 
+// after a temporary paddr extension.
+////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned int _word_extended_read( unsigned int  cluster,
+                                             unsigned int  address )
+{
+    unsigned int value;
+    asm volatile(
+            "li      $3,        0xFFFFFFFE    \n"
+            "mfc0    $2,        $12           \n"
+            "and     $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
+
+            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
+            "lw      %0,        0(%1)         \n"     /* value <= *paddr  */
+            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */
+
+            "li      $3,        0x00000001    \n"
+            "mfc0    $2,        $12           \n"
+            "or      $3,        $3, $2        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
+            : "=r" (value)
+            : "r" (address), "r" (cluster)
+            : "$2", "$3" );
+    return value;
+}
+////////////////////////////////////////////////////////////////////////////
+// This function makes a physical read access to a single byte in memory, 
+// after a temporary paddr extension.
+////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned char _byte_extended_read( unsigned int  cluster,
+                                              unsigned int  address )
+{
+    unsigned int value;
+    asm volatile(
+            "li      $3,        0xFFFFFFFE    \n"
+            "mfc0    $2,        $12           \n"
+            "and     $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
+
+            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
+            "lb      %0,        0(%1)         \n"     /* value <= *paddr  */
+            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */
+
+            "li      $3,        0x00000001    \n"
+            "mfc0    $2,        $12           \n"
+            "or      $3,        $3, $2        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
+            : "=r" (value)
+            : "r" (address), "r" (cluster)
+            : "$2", "$3" );
+    return (unsigned char)value;
+}
+////////////////////////////////////////////////////////////////////////////
+// This function makes a physical write access to a 32 bits word in memory, 
+// after a temporary DTLB address extension.
+////////////////////////////////////////////////////////////////////////////
+in_drivers void _word_extended_write( unsigned int  cluster, 
+                                      unsigned int  address,
+                                      unsigned int  word ) 
+{
+    asm volatile(
+            "li      $3,        0xFFFFFFFE    \n"
+            "mfc0    $2,        $12           \n"
+            "and     $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
+
+            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
+            "sw      %0,        0(%1)         \n"     /* *paddr <= value  */
+            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */   
+
+            "li      $3,        0x00000001    \n"
+            "mfc0    $2,        $12           \n"
+            "or      $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
+            :
+            : "r" (word), "r" (address), "r" (cluster)
+            : "$2", "$3");
+}
+////////////////////////////////////////////////////////////////////////////
+// This function makes a physical write access to single byte in memory, 
+// after a temporary DTLB de-activation and address extension.
+////////////////////////////////////////////////////////////////////////////
+in_drivers void _byte_extended_write( unsigned int  cluster, 
+                                      unsigned int  address,
+                                      unsigned char byte ) 
+{
+    asm volatile(
+            "li      $3,        0xFFFFFFFE    \n"
+            "mfc0    $2,        $12           \n"
+            "and     $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
+
+            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
+            "sb      %0,        0(%1)         \n"     /* *paddr <= value  */
+            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */   
+
+            "li      $3,        0x00000001    \n"
+            "mfc0    $2,        $12           \n"
+            "or      $3,        $2, $3        \n"
+            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
+            :
+            : "r" (byte), "r" (address), "r" (cluster)
+            : "$2", "$3");
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Exit (suicide) after printing message on TTY0 
 ///////////////////////////////////////////////////////////////////////////////////////
 in_drivers void _exit()
@@ -189,5 +361,13 @@
     unsigned int y       = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
 
-    _tty_printf("\n\n!!!  Exit  Processor (%d,%d,%d)  !!!\n", x, y, l );
+    _tty_get_lock( 0 );
+    _tty_puts("\n !!! exit proc[");
+    _tty_putd( x );
+    _tty_puts(",");
+    _tty_putd( y );
+    _tty_puts(",");
+    _tty_putd( l );
+    _tty_puts("]  !!!\n");
+    _tty_release_lock( 0 );
 
     while(1) asm volatile("nop");   // infinite loop...
@@ -227,15 +407,22 @@
 ///////////////////////////////////////////////////////////////////////////////////////
 //  The total number of TTY terminals is defined by NB_TTY_CHANNELS.
-//  1. If there is only one terminal, it is supposed to be shared, and used by
-//     all processors: a lock must be taken before display.
-//  2. If there is several terminals, and the number of processors is smaller 
-//     than the number of terminals, there is one terminal per processor, but 
-//     the TTY index is not equal to the proc_id, due to cluster indexing policy:
-//     - proc_id = cluster_xy * NB_PROCS_MAX + local_id (with cluster_xy = x << Y_WIDTH + y)
-//     - tty_id  = cluster_id * NB_PROCS_MAX + local_id (with cluster_id = x * Y_SIZE + y)
-//  3. If the computed tty_id is larger than NB_TTY_CHANNELS, an error is returned.
+//  - If there is only one terminal, it is supposed to be shared, and used by
+//    all processors: a lock must be taken before display.
+//  - If there is several terminals, and the number of processors is smaller 
+//    than the number of terminals, there is one terminal per processor, but 
+//    the TTY index is not equal to the proc_id, due to cluster indexing policy:
+//    proc_id = cluster_xy * NB_PROCS_MAX + local_id (with cluster_xy = x << Y_WIDTH + y)
+//    tty_id  = cluster_id * NB_PROCS_MAX + local_id (with cluster_id = x * Y_SIZE + y)
+//  - If the computed tty_id is larger than NB_TTY_CHANNELS, an error is returned.
+///////////////////////////////////////////////////////////////////////////////////////
+//  If USE_EXT_IO is set, we use the TTY controler implemented in cluster_io
+//  (x = X_SIZE-1 / y = Y_SIZE), which requires and extended address access. 
+//  If USE_EXT_IO not set, we use the single channel TTY contrÃŽler in cluster (0,0).
+///////////////////////////////////////////////////////////////////////////////////////
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // Write one or several characters directly from a fixed length user buffer
 // to the TTY_WRITE register of the TTY controler.
+// The channel index must be checked by the calling function.
 // This is a non blocking call : it test the TTY_STATUS register.
 // If the TTY_STATUS_WRITE bit is set, the transfer stops and the function
@@ -246,18 +433,31 @@
                            unsigned int    channel )
 {
-    char*           tty_address;
-    unsigned int    base		= (unsigned int)&seg_tty_base;
-    unsigned int    nwritten 	= 0;
-    int	i;
-
-    tty_address = (char*)(base + channel*TTY_SPAN*4);
+    unsigned int    base       = (unsigned int)&seg_tty_base + channel*TTY_SPAN*4;
+    unsigned int    nwritten   = 0;
+    unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+    unsigned int    status;
+    unsigned int	i;
 
     for ( i=0 ; i < length ; i++ )
     {
-        if((tty_address[TTY_STATUS*4] & 0x2) == 0x2)  break;
-        else
-        {
-            tty_address[TTY_WRITE*4] = buffer[i]; // write character
-            nwritten++;
+        if( USE_EXT_IO )    // extended addressing to reach cluster_io
+        {
+            status = _word_extended_read( cluster_io, base + TTY_STATUS*4 );
+            if ( (status & 0x2) == 0x2 ) break;
+            else
+            {
+                _byte_extended_write( cluster_io, base + TTY_WRITE*4 , buffer[i] );
+                nwritten++;
+            }
+        }
+        else                // direct addressing to cluster(0,0)
+        {
+            char* tty = (char*)base;
+            if ( (tty[TTY_STATUS*4] & 0x2) == 0x2 )  break;
+            else
+            {
+                tty[TTY_WRITE*4] = buffer[i]; // write character
+                nwritten++;
+            }
         }
     }
@@ -265,7 +465,9 @@
     return nwritten;
 }
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // Fetch one character directly from the TTY_READ register of the TTY controler,
 // and writes this character to the user buffer.
+// The channel index must be checked by the calling function.
 // This is a non blocking call : it returns 0 if the register is empty,
 // and returns 1 if the register is full.
@@ -274,19 +476,37 @@
                           unsigned int   channel )
 {
-    char*           tty_address;
-    unsigned int    base		= (unsigned int)&seg_tty_base;
-
-    tty_address = (char*)(base + channel*TTY_SPAN*4);
-
-    if((tty_address[TTY_STATUS*4] & 0x1) == 0x1)
-    {
-        buffer[0] = tty_address[TTY_READ*4];
-        return 1;
+    unsigned int    base       = (unsigned int)&seg_tty_base + channel*TTY_SPAN*4;
+    unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+    unsigned int    status;
+
+    if( USE_EXT_IO )
+    {
+        status = _word_extended_read( cluster_io, base + TTY_STATUS*4 );
+        if ( (status & 0x1) == 0x1 )
+        {
+            buffer[0] = (char)_word_extended_read( cluster_io, base + TTY_READ*4 );
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
     }
     else
     {
-        return 0;
-    }
-}
+        char* tty = (char*)base;
+
+        if((tty[TTY_STATUS*4] & 0x1) == 0x1)
+        {
+            buffer[0] = tty[TTY_READ*4];
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // This function displays a string on TTY0.
@@ -356,6 +576,16 @@
 in_drivers void _tty_get_lock( unsigned int channel )
 {
-    unsigned int* tty_address = (unsigned int *) &seg_tty_base;
-    while ( tty_address[channel * TTY_SPAN + TTY_CONFIG] ) asm volatile("nop"); 
+    if ( USE_EXT_IO )  // extended addressing to cluster_io
+    {
+        unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int    address    = (unsigned int)&seg_tty_base 
+                                     + ((TTY_CONFIG + channel*TTY_SPAN)*4);
+        while ( _word_extended_read( cluster_io, address ) ) asm volatile("nop");
+    }
+    else               // direct addressing to cluster(0,0)
+    {
+        unsigned int* tty = (unsigned int *) &seg_tty_base;
+        while ( tty[channel * TTY_SPAN + TTY_CONFIG] ) asm volatile("nop"); 
+    }
 }
 
@@ -366,6 +596,16 @@
 in_drivers void _tty_release_lock( unsigned int channel )
 {
-    unsigned int* tty_address = (unsigned int *) &seg_tty_base;
-    tty_address[channel * TTY_SPAN + TTY_CONFIG] = 0;
+    if ( USE_EXT_IO )  // extended addressing to cluster_io
+    {
+        unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int    address    = (unsigned int)&seg_tty_base 
+                                     + ((TTY_CONFIG + channel*TTY_SPAN)*4);
+        _word_extended_write( cluster_io, address, 0 );
+    }
+    else               // direct addressing to cluster(0,0)
+    {
+        unsigned int* tty_address = (unsigned int *) &seg_tty_base;
+        tty_address[channel * TTY_SPAN + TTY_CONFIG] = 0;
+    }
 }
 
@@ -383,22 +623,15 @@
     unsigned int y;
 
-    // compute TTY terminal index
-    if ( NB_TTY_CHANNELS == 1 )
-    {
-        channel = 0;
-    }
-    else
-    {
-        l           = (proc_id % NB_PROCS_MAX);
-        x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
-        y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
-        channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
-        if (channel >= NB_TTY_CHANNELS )
-        {
-            _tty_get_lock( 0 );
-            _tty_puts( "ERROR in _tty_getc()\n" );
-            _tty_release_lock( 0 );
-            _exit();
-        }
+    // check TTY channel
+    l           = (proc_id % NB_PROCS_MAX);
+    x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
+    y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
+    channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
+    if (channel >= NB_TTY_CHANNELS )
+    {
+        _tty_get_lock( 0 );
+        _tty_puts( "ERROR in _tty_getc(): TTY index too large\n" );
+        _tty_release_lock( 0 );
+        _exit();
     }
 
@@ -433,26 +666,19 @@
     unsigned int  i;
     unsigned int  channel;
-    unsigned int  l;
     unsigned int  x;
     unsigned int  y;
-
-    // compute TTY terminal index
-    if ( NB_TTY_CHANNELS == 1 )
-    {
-        channel = 0;
-    }
-    else
-    {
-        l           = (proc_id % NB_PROCS_MAX);
-        x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
-        y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
-        channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
-        if (channel >= NB_TTY_CHANNELS )   
-        {
-            _tty_get_lock( 0 );
-            _tty_puts( "ERROR in _tty_getw()\n" );
-            _tty_release_lock( 0 );
-            _exit();
-        }
+    unsigned int  l;
+
+    // check TTY channel
+    l           = (proc_id % NB_PROCS_MAX);
+    x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
+    y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
+    channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
+    if (channel >= NB_TTY_CHANNELS )
+    {
+        _tty_get_lock( 0 );
+        _tty_puts( "ERROR in _tty_getw(): TTY index too large\n" );
+        _tty_release_lock( 0 );
+        _exit();
     }
 
@@ -519,11 +745,13 @@
 
     unsigned int channel;
-    unsigned int l;
     unsigned int x;
     unsigned int y;
     unsigned int proc_id = _procid();
 
-    // compute TTY channel
-    if ( NB_TTY_CHANNELS == 1 )
+    // compute TTY channel :
+    // if the number of TTY channels is smaller 
+    // than the number of clusters, use TTY_0_0
+    // else, TTY channel <= cluster index
+    if ( NB_TTY_CHANNELS < (X_SIZE * Y_SIZE) )
     {
         channel = 0;
@@ -531,23 +759,7 @@
     else
     {
-        l           = (proc_id % NB_PROCS_MAX);
         x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
         y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
-        channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
-        if (channel >= NB_TTY_CHANNELS )
-        {
-            _tty_get_lock( 0 );
-            _tty_puts("ERROR in _tty_printf() for proc[" );
-            _tty_putd( x );
-            _tty_puts(",");
-            _tty_putd( y );
-            _tty_puts(",");
-            _tty_putd( l );
-            _tty_puts("] / TTY channel too large = ");
-            _tty_putd( channel );
-            _tty_puts("\n");
-            _tty_release_lock( 0 );
-            _exit();
-        }
+        channel     = (x * Y_SIZE + y);
     }
 
@@ -640,17 +852,29 @@
 //////////////////////////////////////////////////////////////////////////////////////
 //  These functions are the ISRs that must be executed when an IRQ is activated
-//  by the TTY: _tty_isr_X is associated to channel [X].
-//  It save the character in the communication buffer _tty_get_buf[X],
-//  and set the set/reset variable _tty_get_full[X].
+//  by the TTY: _tty_isr_XX is associated to TTY channel [XX].
+//  It save the character in the communication buffer _tty_get_buf[XX],
+//  and set the set/reset variable _tty_get_full[XX].
 //  A character is lost if the buffer is full when the ISR is executed.
 //////////////////////////////////////////////////////////////////////////////////////
 in_drivers void _tty_isr_indexed(size_t index)
 {
-    char*   base = (char*)&seg_tty_base;
-    char*   tty_address = (char*)(base + index*TTY_SPAN*4);
-
-    _tty_get_buf[index]  = tty_address[TTY_READ*4];	// save character and reset IRQ
-    _tty_get_full[index] = 1;	                    // signals character available
-}
+    if ( USE_EXT_IO )   // extended addressing to TTY in cluster_io
+    {
+        unsigned int  cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int  base    = (unsigned int)&seg_tty_base +
+                                ((index*TTY_SPAN + TTY_READ)*4); 
+
+        _tty_get_buf[index] = (char)_word_extended_read( cluster, base );
+    }
+    else                // direct addressing to TTY in cluster(0,0)
+    {
+        char* tty = (char*)&seg_tty_base + index*TTY_SPAN*4;
+
+        _tty_get_buf[index] = tty[TTY_READ*4];	// save character and reset IRQ
+    }
+    _tty_get_full[index] = 1;               // signals character available
+}
+
+in_drivers void _tty_isr()    { _tty_isr_indexed(0); }
 
 in_drivers void _tty_isr_00() { _tty_isr_indexed(0); }
@@ -689,6 +913,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
-//  I/O BLOCK_DEVICE
-// The three functions below use the three variables _ioc_lock _ioc_done, 
+//   BLOCK_DEVICE (IOC)
+//////////////////////////////////////////////////////////////////////////////////////////
+// The functions below use the three variables _ioc_lock _ioc_done, 
 // and _ioc_status for synchronisation.
 // - As the IOC component can be used by several programs running in parallel,
@@ -705,4 +930,10 @@
 // reset the _ioc_done variable to zero, and releases the _ioc_lock variable.
 ///////////////////////////////////////////////////////////////////////////////////////
+//  If USE_EXT_IO is set, we use the IOC controler implemented in cluster_io
+//  (x = X_SIZE-1 / y = Y_SIZE), which requires and extended address access. 
+//  If USE_EXT_IO not set, we use the IOC contrÃŽler in cluster (0,0).
+///////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////
 // This blocking function is used by the _ioc_read() and _ioc_write() functions 
 // to get _ioc_lock using LL/SC.
@@ -720,4 +951,5 @@
                   ::"r"(plock):"$2","$3");
 }
+
 //////////////////////////////////////////////////////////////////////////////////////
 // Transfer data from a memory buffer to the block_device.
@@ -725,5 +957,5 @@
 // - buffer : base address of the memory buffer
 // - count  : number of blocks to be transfered
-// The source buffer must be in user address space.
+// - ext    : cluster index for the memory buffer
 ///////////////////////////////////////////////////////////////////////////////////////
 in_drivers void _ioc_write( size_t   lba, 
@@ -732,17 +964,32 @@
                             size_t   ext )
 {
-    volatile unsigned int*	ioc_address = (unsigned int*)&seg_ioc_base;
-
     // get the lock
     _ioc_get_lock();
 
-    // block_device configuration
-    ioc_address[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
-    ioc_address[BLOCK_DEVICE_BUFFER_EXT] = ext;
-    ioc_address[BLOCK_DEVICE_COUNT]      = count;
-    ioc_address[BLOCK_DEVICE_LBA]        = lba;
-    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
-    ioc_address[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_WRITE;
-}
+    if ( USE_EXT_IO )   // extended addressing to cluster_io
+    {
+        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int    base    = (unsigned int)&seg_ioc_base;
+
+        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER*4,     (unsigned int)buffer );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER_EXT*4, ext );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_COUNT*4,      count );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_LBA*4,        lba );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_IRQ_ENABLE*4, 1 );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_OP*4,         BLOCK_DEVICE_WRITE );
+    }
+    else                // direct addressing to cluster(0,0)
+    {
+        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
+
+        ioc[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
+        ioc[BLOCK_DEVICE_BUFFER_EXT] = ext;
+        ioc[BLOCK_DEVICE_COUNT]      = count;
+        ioc[BLOCK_DEVICE_LBA]        = lba;
+        ioc[BLOCK_DEVICE_IRQ_ENABLE] = 1;
+        ioc[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_WRITE;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // Transfer data from a file on the block device to a memory buffer.
@@ -750,7 +997,5 @@
 // - buffer : base address of the memory buffer
 // - count  : number of blocks to be transfered
-// The destination buffer must be in user address space.
-// All cache lines corresponding to the the target buffer must be invalidated
-// for cache coherence.
+// - ext    : cluster index for the memory buffer
 ///////////////////////////////////////////////////////////////////////////////////////
 in_drivers void _ioc_read( size_t   lba, 
@@ -759,17 +1004,32 @@
                            size_t   ext )
 {
-    volatile unsigned int*    	ioc_address = (unsigned int*)&seg_ioc_base;
-
     // get the lock
     _ioc_get_lock();
 
-    // block_device configuration
-    ioc_address[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
-    ioc_address[BLOCK_DEVICE_BUFFER_EXT] = ext;
-    ioc_address[BLOCK_DEVICE_COUNT]      = count;
-    ioc_address[BLOCK_DEVICE_LBA]        = lba;
-    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
-    ioc_address[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_READ;
-}
+    if ( USE_EXT_IO )   // extended addressing to cluster_io
+    {
+        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int    base    = (unsigned int)&seg_ioc_base;
+
+        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER*4,     (unsigned int)buffer );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER_EXT*4, ext );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_COUNT*4,      count );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_LBA*4,        lba );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_IRQ_ENABLE*4, 1 );
+        _word_extended_write( cluster, base + BLOCK_DEVICE_OP*4,         BLOCK_DEVICE_READ );
+    }
+    else                // direct addressing to cluster(0,0)
+    {
+        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
+
+        ioc[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
+        ioc[BLOCK_DEVICE_BUFFER_EXT] = ext;
+        ioc[BLOCK_DEVICE_COUNT]      = count;
+        ioc[BLOCK_DEVICE_LBA]        = lba;
+        ioc[BLOCK_DEVICE_IRQ_ENABLE] = 1;
+        ioc[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_READ;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // This blocking function cheks completion of an I/O transfer and reports errors.
@@ -795,4 +1055,5 @@
     }
 }
+
 //////////////////////////////////////////////////////////////////////////////////////
 //  This ISR must be executed when an IRQ is activated by IOC to signal completion.
@@ -803,8 +1064,18 @@
 in_drivers void _ioc_isr()
 {
-    int* ioc_address = (int*)&seg_ioc_base;
+    if ( USE_EXT_IO )  // extended addressing to cluster_io
+    {
+        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
+        unsigned int    base    = (unsigned int)&seg_ioc_base;
+
+        _ioc_status = _word_extended_read( cluster, base + BLOCK_DEVICE_STATUS*4 );
+    }
+    else               // direct addressing to cluster(Ã ,0)
+    {
+        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
     
-    _ioc_status = ioc_address[BLOCK_DEVICE_STATUS];	// save status & reset IRQ
-    _ioc_done   = 1;					            // signals completion
+        _ioc_status = ioc[BLOCK_DEVICE_STATUS];	// save status & reset IRQ
+    }
+    _ioc_done   = 1;	   // signals completion
 }
 
@@ -825,40 +1096,58 @@
 //////////////////////////////////////////////////////////////////////////////////////
 //  FRAME_BUFFER
+//////////////////////////////////////////////////////////////////////////////////////
 // The _fb_sync_write & _fb_sync_read functions use a memcpy strategy to implement 
 // the transfer between a data buffer and the frame buffer.
 // They are blocking until completion of the transfer.
 //////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
 //  _fb_sync_write()
 // Transfer data from an user buffer to the frame_buffer device with a memcpy.
-// - offset     : offset (in bytes) in the frame buffer
+// - offset : offset (in bytes) in the frame buffer
 // - buffer : base address of the memory buffer
 // - length : number of bytes to be transfered
-//////////////////////////////////////////////////////////////////////////////////////
-in_drivers void _fb_sync_write( size_t  offset, 
-                                void*   buffer, 
-                                size_t  length,
-                                size_t  ext )
-{
-    volatile char*  fb = (char*)(void*)&seg_fbf_base + offset;
-    char*       ub = buffer;
-
-    _memcpy( (void*)fb, (void*)ub, length );
-}
+// - ext    : cluster_xy for the user buffer
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers void _fb_sync_write( unsigned int  offset, 
+                                unsigned int  buffer, 
+                                unsigned int  length,
+                                unsigned int  ext )
+{
+    unsigned int  src_address = buffer;
+    unsigned int  src_cluster = ext;
+    unsigned int  dst_address = (unsigned int)&seg_fbf_base + offset;
+    unsigned int  dst_cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;  // cluster_xy for I/O
+
+    _extended_memcpy( dst_cluster,
+                      dst_address,
+                      src_cluster,
+                      src_address,
+                      length );
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////
 //  _fb_sync_read()
 // Transfer data from the frame_buffer device to an user buffer with a memcpy.
-// - offset     : offset (in bytes) in the frame buffer
+// - offset : offset (in bytes) in the frame buffer
 // - buffer : base address of the memory buffer
 // - length : number of bytes to be transfered
-//////////////////////////////////////////////////////////////////////////////////////
-in_drivers void  _fb_sync_read( size_t  offset, 
-                                void*   buffer, 
-                                size_t  length,
-                                size_t  ext )
-{
-    volatile char*  fb = (char*)(void*)&seg_fbf_base + offset;
-    char*       ub = buffer;
-
-    _memcpy( (void*)ub, (void*)fb, length );
+// - ext    : cluster_xy for the user buffer
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers void  _fb_sync_read( unsigned int  offset, 
+                                unsigned int  buffer, 
+                                unsigned int  length,
+                                unsigned int  ext )
+{
+    unsigned int  dst_address = buffer;
+    unsigned int  dst_cluster = ext;
+    unsigned int  src_address = (unsigned int)&seg_fbf_base + offset;
+    unsigned int  src_cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;  // cluster_xy for I/O
+
+    _extended_memcpy( dst_cluster,
+                      dst_address,
+                      src_cluster,
+                      src_address,
+                      length );
 }
 
@@ -879,4 +1168,5 @@
     _spin_lock[index] = 0;
 }
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // Try to take a software spin-lock.
@@ -954,4 +1244,5 @@
                   ::"r"(pinit),"r"(pcount),"r"(plock),"r"(value):"$2","$3");
 }
+
 //////////////////////////////////////////////////////////////////////////////////////
 // This blocking function uses a busy_wait technics (on the barrier_lock value), 
Index: /trunk/softs/giet_tsar/stdio.h
===================================================================
--- /trunk/softs/giet_tsar/stdio.h	(revision 628)
+++ /trunk/softs/giet_tsar/stdio.h	(revision 629)
@@ -59,4 +59,9 @@
 void*           _memcpy( void* dst, const void* src, size_t size );
 
+void            _extended_memcpy( unsigned int dst_cluster,
+                                  unsigned int dst_address,
+                                  unsigned int src_cluster,
+                                  unsigned int src_address,
+                                  unsigned int length );
 unsigned int 	_procid();
 unsigned int 	_proctime();
@@ -85,4 +90,5 @@
 void            _tty_getw( unsigned int* buffer );
 void            _tty_printf( char* format, ... );
+void            _tty_isr();
 
 void            _ioc_get_lock();
@@ -94,6 +100,12 @@
 void            _mmc_isr();
 
-void            _fb_sync_write( size_t offset, void* buffer, size_t length, size_t ext );
-void            _fb_sync_read( size_t offset, void* buffer, size_t length, size_t ext );
+void            _fb_sync_write( unsigned int offset, 
+                                unsigned int buffer,
+                                unsigned int length,
+                                unsigned int ext );
+void            _fb_sync_read(  unsigned int offset, 
+                                unsigned int buffer,
+                                unsigned int length,
+                                unsigned int ext );
 
 void            _release_lock( size_t lock_index );
@@ -103,4 +115,14 @@
 void            _barrier_wait(size_t index);
 
+unsigned char   _byte_extended_read(  unsigned int   cluster, 
+                                      unsigned int   address );
+unsigned int    _word_extended_read(  unsigned int   cluster, 
+                                      unsigned int   address );
+void            _word_extended_write( unsigned int   cluster, 
+                                      unsigned int   address, 
+                                      unsigned int   word );
+void            _byte_extended_write( unsigned int   cluster, 
+                                      unsigned int   address, 
+                                      unsigned char  byte );
 #endif
 
Index: /trunk/softs/soft_hello_giet/hard_config.h
===================================================================
--- /trunk/softs/soft_hello_giet/hard_config.h	(revision 628)
+++ /trunk/softs/soft_hello_giet/hard_config.h	(revision 629)
@@ -12,12 +12,14 @@
 #define	 Y_WIDTH             4
 
-#define	 NB_PROCS_MAX        2
+#define	 NB_PROCS_MAX        4
+
+#define  USE_EXT_IO          1
 
 #define	 NB_DMA_CHANNELS     0
-#define	 NB_TTY_CHANNELS     (NB_PROCS_MAX * X_SIZE * Y_SIZE)
 #define	 NB_HBA_CHANNELS     0
 #define	 NB_NIC_CHANNELS     0
 #define	 NB_CMA_CHANNELS     0
 
+#define	 NB_TTY_CHANNELS     4
 
 #endif //_HARD_CONFIG_H
Index: /trunk/softs/soft_hello_giet/ldscript
===================================================================
--- /trunk/softs/soft_hello_giet/ldscript	(revision 628)
+++ /trunk/softs/soft_hello_giet/ldscript	(revision 629)
@@ -23,8 +23,11 @@
 
 seg_xcu_base    = 0xF0000000;       /* controler XCU */
-seg_tty_base    = 0xF2000000;       /* controler TTY */
+seg_tty_base    = 0xF4000000;       /* controler TTY */
 seg_fbf_base    = 0xF3000000;       /* controler FBF */
-seg_ioc_base    = 0xF4000000;       /* controler IOC */
-seg_mmc_base    = 0xFF000000;       /* config    MMC */
+seg_ioc_base    = 0xF2000000;       /* controler IOC */
+seg_nic_base    = 0xF7000000;       /* controler NIC */
+seg_cma_base    = 0xF8000000;       /* controler CMA */
+seg_pic_base    = 0xF9000000;       /* controler PIC */
+seg_mmc_base    = 0xE0000000;       /* config    MMC */
 
 
Index: /trunk/softs/soft_sort_giet/hard_config.h
===================================================================
--- /trunk/softs/soft_sort_giet/hard_config.h	(revision 628)
+++ /trunk/softs/soft_sort_giet/hard_config.h	(revision 629)
@@ -14,10 +14,12 @@
 #define	 NB_PROCS_MAX        4
 
+#define  USE_EXT_IO          1
+
 #define	 NB_DMA_CHANNELS     0
-#define	 NB_TTY_CHANNELS     (NB_PROCS_MAX * X_SIZE * Y_SIZE)
 #define	 NB_HBA_CHANNELS     0
 #define	 NB_NIC_CHANNELS     0
 #define	 NB_CMA_CHANNELS     0
 
+#define	 NB_TTY_CHANNELS     4
 
 #endif //_HARD_CONFIG_H
Index: /trunk/softs/soft_sort_giet/ldscript
===================================================================
--- /trunk/softs/soft_sort_giet/ldscript	(revision 628)
+++ /trunk/softs/soft_sort_giet/ldscript	(revision 629)
@@ -1,5 +1,5 @@
 /**********************************************************
 	File : ldscript 
-	Author : Cesar Fuguet
+	Author : Alain Greiner
 	Date : January 2014
 **********************************************************/
@@ -23,8 +23,11 @@
 
 seg_xcu_base    = 0xF0000000;       /* controler XCU */
-seg_tty_base    = 0xF2000000;       /* controler TTY */
+seg_tty_base    = 0xF4000000;       /* controler TTY */
 seg_fbf_base    = 0xF3000000;       /* controler FBF */
-seg_ioc_base    = 0xF4000000;       /* controler IOC */
-seg_mmc_base    = 0xFF000000;       /* config    MMC */
+seg_ioc_base    = 0xF2000000;       /* controler IOC */
+seg_nic_base    = 0xF7000000;       /* controler NIC */
+seg_cma_base    = 0xF8000000;       /* controler CMA */
+seg_pic_base    = 0xF9000000;       /* controler PIC */
+seg_mmc_base    = 0xE0000000;       /* config    MMC */
 
 
Index: /trunk/softs/soft_sort_giet/main.c
===================================================================
--- /trunk/softs/soft_sort_giet/main.c	(revision 628)
+++ /trunk/softs/soft_sort_giet/main.c	(revision 629)
@@ -57,11 +57,11 @@
     /* Hello World */
 
-    task0_printf("\n[ PROC %d\t] Starting SORT application\n", proc_id);
-
-    task0_printf("[ PROC %d\t] MESH %d x %d x %d processors\n",
-                 proc_id, X_SIZE, Y_SIZE, NB_PROCS_MAX);
-
-    /**************************************************************************/
-    /* Barriers Inititialitatin */
+    task0_printf("\n[ PROC_%d_%d_%d ] Starting SORT application\n",x,y,lid);
+
+    task0_printf("[ PROC_%d_%d_%d ] MESH %d x %d x %d processors\n",
+                 x,y,lid, X_SIZE, Y_SIZE, NB_PROCS_MAX);
+
+    /**************************************************************************/
+    /* Barriers Initialisation */
 
     if (thread_id == 0)
@@ -69,10 +69,10 @@
         for (i = 0; i < __builtin_ctz(total_procs); i++)
         {
-            printf("[ PROC %d\t] Initializing barrier %d with %d\n",
-                proc_id, i, total_procs >> i);
+            printf("[ PROC_%d_%d_%d ] Initializing barrier %d with %d\n",
+                x,y,lid, i, total_procs >> i);
 
             _barrier_init(i, total_procs >> i);
         }
-
+        printf("\n");
         asm volatile ("sync");
         init_ok = 1;
@@ -80,5 +80,5 @@
 
     /**************************************************************************/
-    /* Array Inititialitatin */
+    /* Array Initialisation */
 
     for (i = IPP * thread_id; i < IPP * (thread_id + 1); i++)
@@ -93,7 +93,7 @@
     /* Parallel sorting of array pieces */
 
-    printf("[ PROC %d\t] Stage 0: Processor Sorting...\n\r", proc_id);
+    printf("[ PROC_%d_%d_%d ] Stage 0: Starting...\n\r", x,y,lid);
     bubbleSort(array0, IPP, IPP * thread_id);
-    printf("[ PROC %d\t] Stage 0: Finishing...\n\r", proc_id);
+    printf("[ PROC_%d_%d_%d ] Stage 0: Finishing...\n\r", x,y,lid);
 
     for (i = 0; i < __builtin_ctz(total_procs); i++)
@@ -104,5 +104,5 @@
         if((thread_id % (2 << i)) != 0) _exit();
 
-        printf("[ PROC %d\t] Stage %d: Starting...\n\r", proc_id, i+1);
+        printf("[ PROC_%d_%d_%d ] Stage %d: Starting...\n\r", x,y,lid, i+1);
 
         if((i % 2) == 0)
@@ -124,5 +124,5 @@
                 );
 
-        printf("[ PROC %d\t] Stage %d: Finishing...\n\r", proc_id, i+1);
+        printf("[ PROC_%d_%d_%d ] Stage %d: Finishing...\n\r", x,y,lid, i+1);
     }
 
@@ -147,5 +147,5 @@
         if (success)
         {
-            printf("[ PROC %d\t] Success!!\n\r", proc_id);
+            printf("[ PROC_%d_%d_%d ] Success!!\n\r", x,y,lid);
         }
         else
Index: /trunk/softs/soft_transpose_giet/ldscript
===================================================================
--- /trunk/softs/soft_transpose_giet/ldscript	(revision 628)
+++ /trunk/softs/soft_transpose_giet/ldscript	(revision 629)
@@ -10,21 +10,24 @@
 peripherals are not present in the architecture */
 
-seg_reset_base  = 0x10000000;       /* le code de boot */
+seg_reset_base  = 0x00000000;       /* boot code */
 
-seg_kcode_base  = 0x00001000;       /* le code du système */
-seg_kdata_base  = 0x00010000;       /* les donnees du système */
-seg_kunc_base   = 0x00020000;       /* les données non cachées du système */
+seg_kcode_base  = 0x00010000;       /* kernel code */
+seg_kdata_base  = 0x00020000;       /* kernel cacheable data */
+seg_kunc_base   = 0x00030000;       /* kernel uncacheable data */
 
-seg_code_base   = 0x00030000;       /* le code utilisateur */ 
-seg_data_base   = 0x00040000;       /* les données utilisateur */
+seg_code_base   = 0x00040000;       /* application code */ 
+seg_data_base   = 0x00050000;       /* application data */
 
-seg_heap_base   = 0x00100000;       /* le tas utilisateur */
-seg_stack_base  = 0x00400000;       /* la pile utilisateur */
+seg_heap_base   = 0x00100000;       /* heaps for application tasks */
+seg_stack_base  = 0x00300000;       /* stacks */
 
-seg_xcu_base    = 0xF0000000;       /* controleur XCU */
-seg_dma_base    = 0xF1000000;       /* controleur DMA */
-seg_tty_base    = 0xF2000000;       /* controleur TTY */
-seg_fbf_base    = 0xF3000000;       /* controleur FBF */
-seg_ioc_base    = 0xF4000000;       /* controleur IOC */
+seg_xcu_base    = 0xF0000000;       /* controler XCU */
+seg_tty_base    = 0xF4000000;       /* controler TTY */
+seg_fbf_base    = 0xF3000000;       /* controler FBF */
+seg_ioc_base    = 0xF2000000;       /* controler IOC */
+seg_nic_base    = 0xF7000000;       /* controler NIC */
+seg_cma_base    = 0xF8000000;       /* controler CMA */
+seg_pic_base    = 0xF9000000;       /* controler PIC */
+seg_mmc_base    = 0xE0000000;       /* config    MMC */
 
 
Index: /trunk/softs/soft_transpose_giet/main.c
===================================================================
--- /trunk/softs/soft_transpose_giet/main.c	(revision 628)
+++ /trunk/softs/soft_transpose_giet/main.c	(revision 629)
@@ -1,217 +1,269 @@
 
+#include "hard_config.h"
 #include "stdio.h"
 #include "limits.h"
 #include "../giet_tsar/block_device.h"
 
-#define NL              512
-#define NP              512
-#define NB_IMAGES       1
-#define NB_CLUSTER_MAX  256
-
-#define PRINTF(...)      ({ if (proc_id == 0) { tty_printf(__VA_ARGS__); } })
-
-//#define DISPLAY_ONLY
-
-///////////////////////////////////////////
+#define NL              128
+#define NP              128
+#define NB_IMAGES       5
+
+#define PRINTF(...)      ({ if (lpid == 0) { _tty_printf(__VA_ARGS__); } })
+
+#define DISPLAY_OK
+
 // tricks to read parameters from ldscript
-///////////////////////////////////////////
-
-struct plaf;
-
-extern struct plouf seg_ioc_base;
+extern struct plaf seg_ioc_base;
 extern struct plaf seg_heap_base;
-extern struct plaf NB_PROCS;
-extern struct plaf NB_CLUSTERS;
+
+// global variables stored in seg_data (cluster 0)
+
+// instrumentation counters for each processor
+unsigned int LOAD_START[256][4];
+unsigned int LOAD_END  [256][4];
+unsigned int TRSP_START[256][4];
+unsigned int TRSP_END  [256][4];
+unsigned int DISP_START[256][4];
+unsigned int DISP_END  [256][4];
+
+// checksum variables
+unsigned check_line_before[NL];
+unsigned check_line_after[NL];
 
 /////////////
-void main(){
-   unsigned int frame = 0;
-   unsigned int date  = 0;
-
-   unsigned int c; // cluster index for loops
-   unsigned int l; // line index for loops
-   unsigned int p; // pixel index for loops
-
-   unsigned int proc_id       = procid();                      // processor id
-   unsigned int nlocal_procs  = (unsigned int) &NB_PROCS;      // number of processors per cluster
-   unsigned int nclusters     = (unsigned int) &NB_CLUSTERS;   // number of clusters
-   unsigned int local_id      = proc_id % nlocal_procs;        // local processor id
-   unsigned int cluster_id    = proc_id / nlocal_procs;        // cluster id
-   unsigned int base          = (unsigned int) &seg_heap_base; // base address for shared buffers
-   unsigned int increment     = 0x80000000 / nclusters * 2;    // cluster increment
-   unsigned int nglobal_procs = nclusters * nlocal_procs;      // number of tasks
-   unsigned int npixels       = NP * NL;                       // number of pixel per frame
-   
-   unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
-   unsigned int block_size    = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
-   unsigned int nblocks       = npixels / block_size;   // number of blocks per frame
-
-   PRINTF("\n *** Entering main at cycle %d ***\n\n", proctime());
+void main()
+{
+    unsigned int image = 0;
+
+    unsigned int l;                                             // line index for loops
+    unsigned int p;                                             // pixel index for loops
+
+    unsigned int * ioc_address = (unsigned int *) &seg_ioc_base;
+    unsigned int block_size    = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
+
+    unsigned int proc_id     = _procid();                       // processor id
+    unsigned int nclusters   = X_SIZE*Y_SIZE;                   // number of clusters
+    unsigned int lpid        = proc_id % NB_PROCS_MAX;          // local processor id
+    unsigned int cluster_xy  = proc_id / NB_PROCS_MAX;          // cluster index (8 bits format)
+    unsigned int x           = cluster_xy >> Y_WIDTH;           // x coordinate
+    unsigned int y           = cluster_xy & ((1<<Y_WIDTH)-1);   // y coordinate
+    unsigned int ntasks      = nclusters * NB_PROCS_MAX;        // number of tasks
+    unsigned int npixels     = NP * NL;                         // number of pixel per image
+    unsigned int nblocks     = npixels / block_size;            // number of blocks per image
+
+    // task_id is a "continuous" index for the the task running on processor (x,y,lpid)
+    unsigned int task_id = (((x * Y_SIZE) + y) * NB_PROCS_MAX) + lpid;
+
+    // cluster_id is a "continuous" index for cluster(x,y)
+    unsigned int cluster_id  = (x * Y_SIZE) + y;               
+
+    PRINTF("\n *** Proc 0 in cluster [%d,%d] enters main at cycle %d ***\n\n", 
+           x, y, _proctime());
 
    //  parameters checking
-   if ((nlocal_procs != 1) && (nlocal_procs != 2) && (nlocal_procs != 4)){
-      PRINTF("NB_PROCS must be 1, 2 or 4\n");
-      exit(1);
+   if ((NB_PROCS_MAX != 1) && (NB_PROCS_MAX != 2) && (NB_PROCS_MAX != 4))
+   {
+      PRINTF("NB_PROCS_MAX must be 1, 2 or 4\n");
+      _exit();
    }
    if ((nclusters != 1) && (nclusters != 2) && (nclusters != 4) && (nclusters != 8) &&
          (nclusters != 16) && (nclusters != 32) && (nclusters != 64) && (nclusters != 128) &&
-         (nclusters != 256)){
+         (nclusters != 256))
+   {
       PRINTF("NB_CLUSTERS must be a power of 1 between 1 and 256\n");
-      exit(1);
+      _exit();
    }
-   if (nglobal_procs > 1024){
-      PRINTF("NB_PROCS * NB_CLUSTERS cannot be larger than 1024\n");
-      exit(1);
-   }
-   if (proc_id >= nglobal_procs){
-      PRINTF("processor id %d larger than NB_CLUSTERS*NB_PROCS\n", proc_id);
-      exit(1);
-   }
-
-   // Arrays of pointers on the shared, distributed buffers containing the frames 
-   // These arrays are indexed by the cluster index (sized for the worst case : 256 clusters)
-   unsigned char * A[NB_CLUSTER_MAX];
-   unsigned char * B[NB_CLUSTER_MAX];
-
-   // Arrays of pointers on the instrumentation arrays
-   // These arrays are indexed by the cluster index (sized for the worst case : 256 clusters)
-   // each pointer points on the base adress of an array of NPROCS unsigned int
-   unsigned int * LOAD_START[NB_CLUSTER_MAX];
-   unsigned int * LOAD_END[NB_CLUSTER_MAX];
-   unsigned int * TRSP_START[NB_CLUSTER_MAX];
-   unsigned int * TRSP_END[NB_CLUSTER_MAX];
-   unsigned int * DISP_START[NB_CLUSTER_MAX];
-   unsigned int * DISP_END[NB_CLUSTER_MAX];
-
-   // shared buffers address definition 
-   // from the seg_heap_base and increment depending on the cluster index
-   // These arrays of pointers are identical and replicated in the stack of each task 
-   for (c = 0; c < nclusters; c++){
-      A[c]          = (unsigned char *) (base                                  + increment * c);
-      B[c]          = (unsigned char *) (base +     npixels                    + increment * c);
-      LOAD_START[c] = (unsigned int *)  (base + 2 * npixels                    + increment * c);
-      LOAD_END[c]   = (unsigned int *)  (base + 2 * npixels +     nlocal_procs + increment * c);
-      TRSP_START[c] = (unsigned int *)  (base + 2 * npixels + 2 * nlocal_procs + increment * c);
-      TRSP_END[c]   = (unsigned int *)  (base + 2 * npixels + 3 * nlocal_procs + increment * c);
-      DISP_START[c] = (unsigned int *)  (base + 2 * npixels + 4 * nlocal_procs + increment * c);
-      DISP_END[c]   = (unsigned int *)  (base + 2 * npixels + 5 * nlocal_procs + increment * c);
-   }
+
+   // pointers on the distributed buffers containing the images, 
+   // allocated in the heap segment: each buffer contains 256 Kbytes
+   unsigned char* buf_in  = (unsigned char*)&seg_heap_base;
+   unsigned char* buf_out = buf_in + 0x00100000;
 
    PRINTF("NB_CLUSTERS     = %d\n", nclusters); 
-   PRINTF("NB_LOCAL_PROCS  = %d\n", nlocal_procs); 
-   PRINTF("NB_GLOBAL_PROCS = %d\n", nglobal_procs);
+   PRINTF("NB_LOCAL_PROCS  = %d\n", NB_PROCS_MAX); 
+   PRINTF("NB_TASKS        = %d\n", ntasks);
    PRINTF("NB_PIXELS       = %d\n", npixels);
    PRINTF("BLOCK_SIZE      = %d\n", block_size);
    PRINTF("NB_BLOCKS       = %d\n\n", nblocks);
 
-
-   PRINTF("*** Starting barrier init at cycle %d ***\n", proctime());
+   PRINTF("*** Proc 0 in cluster [%d,%d] starts barrier init at cycle %d\n", 
+          x, y, _proctime());
 
    //  barriers initialization
-   barrier_init(0, nglobal_procs);
-   barrier_init(1, nglobal_procs);
-   barrier_init(2, nglobal_procs);
-
-   PRINTF("*** Completing barrier init at cycle %d ***\n", proctime());
-
-   // Main loop (on frames)
-   while (frame < NB_IMAGES){
-      // pseudo parallel load from disk to A[c] buffer : nblocks/nclusters blocks
-      // only task running on processor with (local_id == 0) does it
-
-      if (local_id == 0){
-         int p;
-
-         date = proctime();
-         PRINTF("\n*** Starting load for frame %d at cycle %d\n", frame, date);
+   _barrier_init(0, ntasks);
+   _barrier_init(1, ntasks);
+   _barrier_init(2, ntasks);
+   _barrier_init(3, ntasks);
+
+   PRINTF("*** Proc 0 in cluster [%d,%d] completes barrier init at cycle %d\n",
+          x, y, _proctime());
+
+   // Main loop (on images)
+   while (image < NB_IMAGES)
+   {
+      // pseudo parallel load from disk to buf_in buffer : nblocks/nclusters blocks
+      // only task running on processor with (lpid == 0) does it
+
+      LOAD_START[cluster_id][lpid] = _proctime();
+
+      if (lpid == 0)
+      {
+         _ioc_read( ((image * nblocks) + ((nblocks * cluster_id) / nclusters)), 
+                    buf_in,
+                    (nblocks / nclusters),
+                    cluster_xy );
+
+         PRINTF("\n*** Proc 0 in cluster [%d,%d] starts load for image %d at cycle %d\n",
+                x, y, image, _proctime() );
+
+         _ioc_completed();
+
+         PRINTF("*** Proc 0 in cluster [%d,%d] completes load for image %d at cycle %d\n",
+                x, y, image, _proctime() );
+      }
+
+      LOAD_END[cluster_id][lpid] = _proctime();
+
+      _barrier_wait(0);
+
+      // parallel transpose from buf_in to buf_out buffers
+      // each processor makes the transposition for (NL/ntasks) lines
+      // (p,l) are the pixel coordinates in the source image
+
+      PRINTF("\n*** proc 0 in cluster [%d,%d] starts transpose for image %d at cycle %d\n", 
+             x, y, image, _proctime());
+
+      TRSP_START[cluster_id][lpid] = _proctime();
+
+      unsigned int nlt   = NL / ntasks;                // number of lines per processor
+      unsigned int first = task_id * nlt;              // first line index
+      unsigned int last  = first + nlt;                // last line index
+      unsigned int nlines_clusters = NL / nclusters;   // number of lines per cluster
+      unsigned int npix_clusters   = NP / nclusters;   // number of pixels per cluster
+
+      unsigned int src_cluster;
+      unsigned int src_index;
+      unsigned int dst_cluster;
+      unsigned int dst_index;
+
+      unsigned int word;
+
+      for (l = first; l < last; l++)
+      {
+         PRINTF("    - processing line %d\n", l);
+
+         check_line_before[l] = 0;
          
-         for (p = 0; p < nlocal_procs; p++){
-            LOAD_START[cluster_id][p] = date;
-         }
-         if (ioc_read(frame * nblocks + nblocks * cluster_id / nclusters, A[cluster_id], nblocks / nclusters)){
-            PRINTF("echec ioc_read\n");
-            exit();
-         }
-         if (ioc_completed()){
-            PRINTF("echec ioc_completed\n");
-            exit();
-         }
-
-         date = proctime();
-         PRINTF("*** Completing load for frame %d at cycle %d\n", frame, date);
-         for (p = 0; p < nlocal_procs; p++){
-            LOAD_END[cluster_id][p] = date;
+         // in each iteration we read one word an write four bytes
+         for (p = 0 ; p < NP ; p = p+4)
+         {
+            // read one word, with extended address from local buffer
+            src_cluster = cluster_xy;
+            src_index   = (l % nlines_clusters) * NP + p;
+            word = _word_extended_read( src_cluster, 
+                                        (unsigned int)&buf_in[src_index] );
+
+            unsigned char byte0 = (unsigned char)( word      & 0x000000FF);
+            unsigned char byte1 = (unsigned char)((word>>8)  & 0x000000FF);
+            unsigned char byte2 = (unsigned char)((word>>16) & 0x000000FF);
+            unsigned char byte3 = (unsigned char)((word>>24) & 0x000000FF);
+
+            // compute checksum
+            check_line_before[l] = check_line_before[l] + byte0 + byte1 + byte2 + byte3;
+
+            // write four bytes with extended address to four remote buffers
+            dst_cluster = (((p / npix_clusters) / Y_SIZE) << Y_WIDTH) + 
+                           ((p / npix_clusters) % Y_SIZE);
+            dst_index   = (p % npix_clusters) * NL + l;
+            _byte_extended_write( dst_cluster, 
+                                  (unsigned int)&buf_out[dst_index], 
+                                  byte0 );
+
+            dst_cluster = ((((p+1) / npix_clusters) / Y_SIZE) << Y_WIDTH) + 
+                           (((p+1) / npix_clusters) % Y_SIZE);
+            dst_index   = ((p+1) % npix_clusters) * NL + l;
+            _byte_extended_write( dst_cluster, 
+                                  (unsigned int)&buf_out[dst_index], 
+                                  byte1 );
+
+            dst_cluster = ((((p+2) / npix_clusters) / Y_SIZE) << Y_WIDTH) + 
+                           (((p+2) / npix_clusters) % Y_SIZE);
+            dst_index   = ((p+2) % npix_clusters) * NL + l;
+            _byte_extended_write( dst_cluster, 
+                                  (unsigned int)&buf_out[dst_index], 
+                                  byte2 );
+
+            dst_cluster = ((((p+3) / npix_clusters) / Y_SIZE) << Y_WIDTH) + 
+                           (((p+3) / npix_clusters) % Y_SIZE);
+            dst_index   = ((p+3) % npix_clusters) * NL + l;
+            _byte_extended_write( dst_cluster, 
+                                  (unsigned int)&buf_out[dst_index], 
+                                  byte3 );
          }
       }
 
-      barrier_wait(0);
-
-      // parallel transpose from A to B buffers
-      // each processor makes the transposition for (NL/nglobal_procs) lines
-      // (p,l) are the (x,y) pixel coordinates in the source frame
-
-#ifndef DISPLAY_ONLY
-      date = proctime();
-      PRINTF("\n*** Starting transpose for frame %d at cycle %d\n", frame, date);
-      TRSP_START[cluster_id][local_id] = date;
-
-      unsigned int nlt   = NL / nglobal_procs; // Nombre de ligne Ã  traiter par processeur
-      unsigned int first = proc_id * nlt;      // Index de la premiÃšre ligne Ã  traiter pour le proc courant (celui qui exÃ©cute le code)
-      unsigned int last  = first + nlt;        // Index de la derniÃšre ligne
-      unsigned int nlines_clusters = NL / nclusters; // Nombre de lignes Ã  traiter par cluster
-      unsigned int npix_clusters   = NP / nclusters; // Nombre de pixels par ligne Ã  traiter par cluster
-
-      for (l = first; l < last; l++){
-         PRINTF("    - processing line %d\n", l);
-         for (p = 0; p < NP; p++){
-            unsigned int source_index   = (l % nlines_clusters) * NP + p;
-            unsigned int dest_cluster   = p / npix_clusters;
-            unsigned int dest_index     = (p % npix_clusters) * NL + l;
-            B[dest_cluster][dest_index] = A[cluster_id][source_index];
+      PRINTF("*** proc 0 in cluster [%d,%d] complete transpose for image %d at cycle %d\n", 
+             x, y, image, _proctime() );
+
+      TRSP_END[cluster_id][lpid] = _proctime();
+
+      _barrier_wait(1);
+
+      // optional parallel display from local buf_out to frame buffer
+
+#ifdef DISPLAY_OK
+
+      PRINTF("\n*** proc 0 in cluster [%d,%d] starts display for image %d at cycle %d\n", 
+             x, y, image, _proctime() );
+
+      DISP_START[cluster_id][lpid] = _proctime();
+
+      unsigned int npxt = npixels / ntasks;   // number of pixels per task
+      unsigned int buffer = (unsigned int)buf_out + npxt*lpid;
+
+      _fb_sync_write( npxt * task_id, buffer, npxt, cluster_xy );
+
+      PRINTF("*** Proc 0 in cluster [%d,%d] completes display for image %d at cycle %d\n",
+             x, y, image, _proctime() );
+
+      DISP_END[cluster_id][lpid] = _proctime();
+
+      _barrier_wait(2);
+
+#endif
+
+      // Instrumentation and checksum (done by processor 0 in cluster 0)
+      if (proc_id == 0)
+      { 
+         PRINTF("\n*** Proc [0,0,0] starts checks for image %d at cycle %d\n\n",
+                  image, _proctime() );
+
+         unsigned int success = 1;
+
+         for ( l = 0 ; l < NL ; l++ )
+         {
+            check_line_after[l] = 0;
+
+            for ( p = 0 ; p < NP ; p++ )
+            {
+               // read one byte in remote buffer
+               src_cluster = (((p / npix_clusters) / Y_SIZE) << Y_WIDTH) +
+                             ((p / npix_clusters) % Y_SIZE);
+               src_index   = (p % npix_clusters) * NL + l;
+
+               unsigned char byte = _byte_extended_read( src_cluster,
+                                                         (unsigned int)&buf_out[src_index] );
+
+               check_line_after[l] = check_line_after[l] + byte;
+            }
+
+            PRINTF(" - l = %d / before = %d / after = %d \n",
+                   l, check_line_before[l], check_line_after[l] );
+
+            if ( check_line_before[l] != check_line_after[l] ) success = 0;
          }
-      }
-
-      date = proctime();
-      PRINTF("*** Completing transpose for frame %d at cycle %d\n", frame, date);
-      TRSP_END[cluster_id][local_id] = date;
-      barrier_wait(1);
-#endif
-
-      // parallel display from B[c] to frame buffer 
-      // each processor uses its private dma to display NL*NP/nglobal_procs pixels
-
-      date = proctime();
-      PRINTF("\n*** Starting display for frame %d at cycle %d\n", frame, date);
-      DISP_START[cluster_id][local_id] = date;
-
-      unsigned int npxt = npixels / nglobal_procs;   // number of pixels per proc
-
-#ifndef DISPLAY_ONLY
-      if (fb_write(npxt * proc_id, B[cluster_id] + npxt * local_id, npxt)){
-         PRINTF("[%d]: echec fb_sync_write\n", proc_id);
-         exit();
-      }
-#else
-      if (fb_write(npxt * proc_id, A[cluster_id] + npxt * local_id, npxt)){
-         PRINTF("[%d]: echec fb_sync_write\n", proc_id);
-         exit();
-      }
-#endif
-
-      if (fb_completed()){
-         PRINTF("[%d]: echec fb_completed\n", proc_id);
-         exit();
-      }
-
-      date = proctime();
-      PRINTF("*** Completing display for frame %d at cycle %d\n", frame, date);
-      DISP_END[cluster_id][local_id] = date;
-
-      barrier_wait(2);
-
-      // Instrumentation (done by processor 0 in cluster 0)
-      if (local_id == 0){ 
-         date = proctime();
-         PRINTF("\n*** Starting Instrumentation for frame %d at cycle %d\n\n", frame, date);
+
+         if ( success ) PRINTF("\n*** proc [0,0,0] : CHECKSUM OK \n\n");
+         else           PRINTF("\n*** proc [0,0,0] : CHECKSUM KO \n\n");
 
          int cc, pp;
@@ -229,71 +281,56 @@
          unsigned int max_disp_ended = 0;
 
-         for (cc = 0; cc < nclusters; cc++){
-            for (pp = 0; pp < nlocal_procs; pp++){
-               if (LOAD_START[cc][pp] < min_load_start){
-                  min_load_start = LOAD_START[cc][pp];
-               }
-               if (LOAD_START[cc][pp] > max_load_start){
-                  max_load_start = LOAD_START[cc][pp];
-               }
-               if (LOAD_END[cc][pp] < min_load_ended){
-                  min_load_ended = LOAD_END[cc][pp];
-               }
-               if (LOAD_END[cc][pp] > max_load_ended){
-                  max_load_ended = LOAD_END[cc][pp];
-               }
-
-               if (TRSP_START[cc][pp] < min_trsp_start){
-                  min_trsp_start = TRSP_START[cc][pp];
-               }
-               if (TRSP_START[cc][pp] > max_trsp_start){
-                  max_trsp_start = TRSP_START[cc][pp];
-               }
-               if (TRSP_END[cc][pp] < min_trsp_ended){
-                  min_trsp_ended = TRSP_END[cc][pp];
-               }
-               if (TRSP_END[cc][pp] > max_trsp_ended){
-                  max_trsp_ended = TRSP_END[cc][pp];
-               }
-
-               if (DISP_START[cc][pp] < min_disp_start){
-                  min_disp_start = DISP_START[cc][pp];
-               }
-               if (DISP_START[cc][pp] > max_disp_start){
-                  max_disp_start = DISP_START[cc][pp];
-               }
-               if (DISP_END[cc][pp] < min_disp_ended){
-                  min_disp_ended = DISP_END[cc][pp];
-               }
-               if (DISP_END[cc][pp] > max_disp_ended){
-                  max_disp_ended = DISP_END[cc][pp];
-               }
+         for (cc = 0; cc < nclusters; cc++)
+         {
+            for (pp = 0; pp < NB_PROCS_MAX; pp++)
+            {
+               if (LOAD_START[cc][pp] < min_load_start)  min_load_start = LOAD_START[cc][pp];
+               if (LOAD_START[cc][pp] > max_load_start)  max_load_start = LOAD_START[cc][pp];
+               if (LOAD_END[cc][pp]   < min_load_ended)  min_load_ended = LOAD_END[cc][pp]; 
+               if (LOAD_END[cc][pp]   > max_load_ended)  max_load_ended = LOAD_END[cc][pp];
+               if (TRSP_START[cc][pp] < min_trsp_start)  min_trsp_start = TRSP_START[cc][pp];
+               if (TRSP_START[cc][pp] > max_trsp_start)  max_trsp_start = TRSP_START[cc][pp];
+               if (TRSP_END[cc][pp]   < min_trsp_ended)  min_trsp_ended = TRSP_END[cc][pp];
+               if (TRSP_END[cc][pp]   > max_trsp_ended)  max_trsp_ended = TRSP_END[cc][pp];
+               if (DISP_START[cc][pp] < min_disp_start)  min_disp_start = DISP_START[cc][pp];
+               if (DISP_START[cc][pp] > max_disp_start)  max_disp_start = DISP_START[cc][pp];
+               if (DISP_END[cc][pp]   < min_disp_ended)  min_disp_ended = DISP_END[cc][pp];
+               if (DISP_END[cc][pp]   > max_disp_ended)  max_disp_ended = DISP_END[cc][pp];
             }
          }
 
          PRINTF(" - LOAD_START : min = %d / max = %d / med = %d / delta = %d\n",
-               min_load_start, max_load_start, (min_load_start+max_load_start)/2, max_load_start-min_load_start); 
+               min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
+               max_load_start-min_load_start); 
+
          PRINTF(" - LOAD_END   : min = %d / max = %d / med = %d / delta = %d\n",
-               min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, max_load_ended-min_load_ended); 
+               min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
+               max_load_ended-min_load_ended); 
 
          PRINTF(" - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
-               min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, max_trsp_start-min_trsp_start); 
+               min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
+               max_trsp_start-min_trsp_start); 
+
          PRINTF(" - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-               min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, max_trsp_ended-min_trsp_ended); 
+               min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
+               max_trsp_ended-min_trsp_ended); 
 
          PRINTF(" - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
-               min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, max_disp_start-min_disp_start); 
+               min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
+               max_disp_start-min_disp_start); 
+
          PRINTF(" - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-               min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, max_disp_ended-min_disp_ended); 
-
-         PRINTF(" - BARRIER TRSP/DISP = %d\n", min_disp_start - max_trsp_ended);
+               min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
+               max_disp_ended-min_disp_ended); 
       }
-      frame++;
-
-   } // end while frame      
-
-   PRINTF("*** End of main ***\n");
-
-   while(1);
+
+      image++;
+
+      _barrier_wait( 3 );
+   } // end while image      
+
+
+   _exit();
+
 } // end main()
 
