Index: trunk/softs/giet_tsar/stdio.c
===================================================================
--- trunk/softs/giet_tsar/stdio.c	(revision 626)
+++ 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), 
