Index: trunk/hal/tsar_mips32/drivers/soclib_mty.c
===================================================================
--- trunk/hal/tsar_mips32/drivers/soclib_mtty.c	(revision 540)
+++ trunk/hal/tsar_mips32/drivers/soclib_mty.c	(revision 570)
@@ -1,4 +1,4 @@
 /*
- * soclib_mtty.c - soclib tty driver implementation.
+ * soclib_mty.c - soclib mty driver implementation.
  *
  * Author  Alain Greiner (2016,2017,2018)
@@ -26,80 +26,96 @@
 #include <dev_txt.h>
 #include <chdev.h>
-#include <soclib_mtty.h>
-#include <remote_spinlock.h>
+#include <soclib_mty.h>
 #include <thread.h>
 #include <printk.h>
 #include <hal_special.h>
 
-#if (DEBUG_SYS_READ & 1)
-extern uint32_t  enter_tty_cmd_read;
-extern uint32_t  exit_tty_cmd_read;
-
-extern uint32_t  enter_tty_isr_read;
-extern uint32_t  exit_tty_isr_read;
-#endif
-
-#if (DEBUG_SYS_WRITE & 1)
-extern uint32_t  enter_tty_cmd_write;
-extern uint32_t  exit_tty_cmd_write;
-
-extern uint32_t  enter_tty_isr_write;
-extern uint32_t  exit_tty_isr_write;
-#endif
-
 extern   chdev_directory_t    chdev_dir;  // allocated in the kernel_init.c file.
-extern   spinlock_t           txt0_lock;  // Initialized in kernel_init.c
+
 ////////////////////////////////////////////////////////////////////////////////////
-// These global variables implement the MTTY_RX  FIFOs (one per channel)
+// These global variables implement the MTY_RX  FIFOs (one per channel)
 ////////////////////////////////////////////////////////////////////////////////////
-
-__attribute__((section(".kdata")))
-mtty_fifo_t  mtty_rx_fifo[CONFIG_MAX_TXT_CHANNELS];
-
-__attribute__((section(".kdata")))
-mtty_fifo_t  mtty_tx_fifo[CONFIG_MAX_TXT_CHANNELS];
+// Implementation note:
+// We allocate - in each cluster - two arrays of FIFOs containing as many entries
+// as the total number of TXT channels, but all entries are not used in all
+// clusters: for a given cluster K, a given entry corresponding to a given channel
+// and a given direction is only used if the associated chdev is in cluster K.
+// With this policy, the driver can ignore the actual placement of chdevs.
+////////////////////////////////////////////////////////////////////////////////////
+
+__attribute__((section(".kdata")))
+mty_fifo_t  mty_rx_fifo[CONFIG_MAX_TXT_CHANNELS];
+
+__attribute__((section(".kdata")))
+mty_fifo_t  mty_tx_fifo[CONFIG_MAX_TXT_CHANNELS];
+
+////////////////////////////////////////////////////////////////////////////////////
+// These global variables define the physical channel RX and TX state,
+// as required by the virtual channels handling.
+////////////////////////////////////////////////////////////////////////////////////
+// Implementation note:
+// These state variables are required, because the ISR is called twice for each
+// character on the physical channel (for index and value), and does not the same
+// actions for index and value. They are also used to implement the round-robin
+// policy between TX_FIFOs.
+////////////////////////////////////////////////////////////////////////////////////
+
+__attribute__((section(".kdata")))
+bool_t      mty_rx_not_new;                // RX first byte if false
+
+__attribute__((section(".kdata")))
+uint32_t    mty_rx_channel;                // RX virtual channel index
+
+__attribute__((section(".kdata")))
+bool_t      mty_tx_not_new;                // TX first byte if false
+
+__attribute__((section(".kdata")))
+uint32_t    mty_tx_value;                  // TX character ascii value
+
+__attribute__((section(".kdata")))
+uint32_t    mty_tx_last;                   // TX last selected virtual channel
 
 ///////////////////////////////////////
-void soclib_mtty_init( chdev_t * chdev )
+void soclib_mty_init( chdev_t * chdev )
 {
     xptr_t reg_xp;
 
     // initialise function pointers in chdev
-    chdev->cmd = &soclib_mtty_cmd;
-    chdev->isr = &soclib_mtty_isr;
-    chdev->aux = &soclib_mtty_aux;
-
-    // get TTY channel and extended pointer on TTY peripheral base address
-    xptr_t   tty_xp  = chdev->base;
+    chdev->cmd = &soclib_mty_cmd;
+    chdev->isr = &soclib_mty_isr;
+    chdev->aux = &soclib_mty_aux;
+
+    // get MTY channel and extended pointer on MTY peripheral base address
+    xptr_t   mty_xp  = chdev->base;
     uint32_t channel = chdev->channel;
     bool_t   is_rx   = chdev->is_rx;
 
-    // get SOCLIB_TTY device cluster and local pointer
-    cxy_t      tty_cxy = GET_CXY( tty_xp );
-    uint32_t * tty_ptr = GET_PTR( tty_xp );
-
-    // enable interruptions for RX but not for TX
-    reg_xp = XPTR( tty_cxy , tty_ptr + MTTY_CONFIG );
-    hal_remote_sw( reg_xp , MTTY_CONFIG_RX_ENABLE );
+    // get SOCLIB_MTY device cluster and local pointer
+    cxy_t      mty_cxy = GET_CXY( mty_xp );
+    uint32_t * mty_ptr = GET_PTR( mty_xp );
+
+    // enable interruptions for RX 
+    reg_xp = XPTR( mty_cxy , mty_ptr + MTY_CONFIG );
+    hal_remote_s32( reg_xp , MTY_CONFIG_RX_ENABLE );
 
     // reset relevant FIFO
     if( is_rx )
     {
-        mtty_rx_fifo[channel].sts = 0;
-        mtty_rx_fifo[channel].ptr = 0;
-        mtty_rx_fifo[channel].ptw = 0;
+        mty_rx_fifo[channel].sts = 0;
+        mty_rx_fifo[channel].ptr = 0;
+        mty_rx_fifo[channel].ptw = 0;
     }
     else
     {
-        mtty_tx_fifo[channel].sts = 0;
-        mtty_tx_fifo[channel].ptr = 0;
-        mtty_tx_fifo[channel].ptw = 0;
+        mty_tx_fifo[channel].sts = 0;
+        mty_tx_fifo[channel].ptr = 0;
+        mty_tx_fifo[channel].ptw = 0;
     }
-}  // end soclib_mtty_init()
+}  // end soclib_mty_init()
 
 //////////////////////////////////////////////////////////////
-void __attribute__ ((noinline)) soclib_mtty_cmd( xptr_t th_xp )
+void __attribute__ ((noinline)) soclib_mty_cmd( xptr_t th_xp )
 {
-    mtty_fifo_t * fifo;     // MTTY_RX or MTTY_TX FIFO
+    mty_fifo_t * fifo;     // MTY_RX or MTY_TX FIFO
     char         byte;     // byte value
     uint32_t     done;     // number of bytes moved
@@ -110,35 +126,21 @@
 
     // get command arguments
-    uint32_t type     = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.type   ) );
-    xptr_t   buf_xp   = hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.buf_xp ) );
-    uint32_t count    = hal_remote_lw ( XPTR( th_cxy , &th_ptr->txt_cmd.count  ) );
+    uint32_t type     = hal_remote_l32 ( XPTR( th_cxy , &th_ptr->txt_cmd.type   ) );
+    xptr_t   buf_xp   = hal_remote_l64( XPTR( th_cxy , &th_ptr->txt_cmd.buf_xp ) );
+    uint32_t count    = hal_remote_l32 ( XPTR( th_cxy , &th_ptr->txt_cmd.count  ) );
     xptr_t   error_xp = XPTR( th_cxy , &th_ptr->txt_cmd.error );
 
-#if (DEBUG_SYS_READ & 1)
-if( type == TXT_READ) enter_tty_cmd_read = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_SYS_WRITE & 1)
-if( type == TXT_WRITE) enter_tty_cmd_write = (uint32_t)hal_get_cycles();
-#endif
-
     // get TXT device cluster and pointers
-    xptr_t     dev_xp = (xptr_t)hal_remote_lwd( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
+    xptr_t     dev_xp = (xptr_t)hal_remote_l64( XPTR( th_cxy , &th_ptr->txt_cmd.dev_xp ) );
     cxy_t      dev_cxy = GET_CXY( dev_xp );
     chdev_t  * dev_ptr = GET_PTR( dev_xp );
 
-    // get cluster and pointers for SOCLIB_TTY peripheral base segment
-    xptr_t     tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
-    cxy_t      tty_cxy = GET_CXY( tty_xp );
-    uint32_t * tty_ptr = GET_PTR( tty_xp );
-
-    // get TTY channel index and channel base address
-    uint32_t   channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
-    uint32_t * base    = tty_ptr;
+    // get MTY channel index and channel base address
+    uint32_t   channel = hal_remote_l32( XPTR( dev_cxy , &dev_ptr->channel ) );
 
     ///////////////////////
-    if( type == TXT_WRITE )         // write bytes to MTTY_TX FIFO
-    {
-        fifo = &mtty_tx_fifo[channel];
+    if( type == TXT_WRITE )         // write bytes to MTY_TX FIFO
+    {
+        fifo = &mty_tx_fifo[channel];
 
         done = 0;
@@ -146,5 +148,5 @@
         while( done < count )
         {
-            if( fifo->sts < MTTY_FIFO_DEPTH )   // put one byte to FIFO if TX_FIFO not full
+            if( fifo->sts < MTY_FIFO_DEPTH )   // put one byte to FIFO if TX_FIFO not full
             {
                 // get one byte from command buffer
@@ -164,19 +166,9 @@
 
                 // update FIFO state
-                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
+                fifo->ptw = (fifo->ptw + 1) % MTY_FIFO_DEPTH;
                 hal_atomic_add( &fifo->sts , 1 );
 
                 // udate number of bytes moved
                 done++;
-
-                // enable TX_IRQ
-                //      vci_multi_tty devices never raise TX IRQs
-                //      so the following instructions are useless
-                //      and moreover they kernel panic
-                // xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
-                // uint32_t old = hal_remote_lw( config_xp );
-                // uint32_t new = old | MTTY_CONFIG_TX_ENABLE;
-                // hal_remote_atomic_cas( config_xp , old , new );
-                // hal_remote_sw( XPTR( tty_cxy , base + MTTY_CONFIG ) , MTTY_CONFIG_TX_ENABLE );
             }
             else                                // block & deschedule if TX_FIFO full
@@ -186,15 +178,15 @@
 
                 // deschedule
-                sched_yield( "MTTY_TX_FIFO full" ); 
+                sched_yield( "MTY_TX_FIFO full" ); 
             }
         }
 
         // set error status in command and return
-        hal_remote_sw( error_xp , 0 );
+        hal_remote_s32( error_xp , 0 );
     }
     ///////////////////////////
-    else if( type == TXT_READ )       // read bytes from MTTY_RX FIFO   
-    {
-        fifo = &mtty_rx_fifo[channel];
+    else if( type == TXT_READ )       // read bytes from MTY_RX FIFO   
+    {
+        fifo = &mty_rx_fifo[channel];
 
         done = 0;
@@ -214,5 +206,5 @@
 #endif
                 // update FIFO state
-                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
+                fifo->ptr = (fifo->ptr + 1) % MTY_FIFO_DEPTH;
                 hal_atomic_add( &fifo->sts , -1 );
 
@@ -229,10 +221,10 @@
     
                 // deschedule
-                sched_yield( "MTTY_RX_FIFO empty" );
+                sched_yield( "MTY_RX_FIFO empty" );
             }
         }  // end while
 
         // set error status in command
-        hal_remote_sw( error_xp , 0 );
+        hal_remote_s32( error_xp , 0 );
     }
     else
@@ -241,20 +233,12 @@
     }
 
-#if (DEBUG_SYS_READ & 1)
-if( type == TXT_READ ) exit_tty_cmd_read = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_SYS_WRITE & 1)
-if( type == TXT_WRITE ) exit_tty_cmd_write = (uint32_t)hal_get_cycles();
-#endif
-
-}  // end soclib_mtty_cmd()
+}  // end soclib_mty_cmd()
 
 /////////////////////////////////////////////////////////////////
-void __attribute__ ((noinline)) soclib_mtty_isr( chdev_t * chdev )
+void __attribute__ ((noinline)) soclib_mty_isr( chdev_t * chdev )
 {
     thread_t   * server;            // pointer on TXT chdev server thread
     lid_t        server_lid;        // local index of core running the server thread
-    uint32_t     channel;           // TXT chdev channel
+    uint32_t     channel;           // TXT chdev channel (virtual channel index)
     bool_t       is_rx;             // TXT chdev direction
     char         byte;              // byte value
@@ -263,104 +247,69 @@
     process_t  * owner_ptr;         // local pointer on TXT owner process
     pid_t        owner_pid;         // TXT owner process identifier
-    mtty_fifo_t * fifo;              // pointer on MTTY_TX or MTTY_RX FIFO
-    cxy_t        tty_cxy;           // soclib_mtty cluster
-    uint32_t   * tty_ptr;           // soclib_mtty segment base address
-    uint32_t   * base;              // soclib_mtty channel base address
-    xptr_t       status_xp;         // extended pointer on MTTY_STATUS register
-    xptr_t       write_xp;          // extended pointer on MTTY_WRITE register
-    xptr_t       read_xp;           // extended pointer on MTTY_READ register
+    mty_fifo_t * fifo;              // pointer on MTY_TX or MTY_RX FIFO
+    cxy_t        mty_cxy;           // soclib_mty cluster
+    uint32_t   * mty_ptr;           // soclib_mty segment base address
+    xptr_t       status_xp;         // extended pointer on MTY_STATUS register
+    xptr_t       write_xp;          // extended pointer on MTY_WRITE register
+    xptr_t       read_xp;           // extended pointer on MTY_READ register
     xptr_t       parent_xp;         // extended pointer on parent process
     cxy_t        parent_cxy;        // parent process cluster
     process_t  * parent_ptr;        // local pointer on parent process
-    xptr_t       children_lock_xp;  // extended pointer on children processes lock
     thread_t   * parent_main_ptr;   // extended pointer on parent process main thread
     xptr_t       parent_main_xp;    // local pointer on parent process main thread
+    uint32_t     n;                 // index in loop
+    bool_t       found;
+
+#if DEBUG_HAL_TXT_RX
+uint32_t rx_cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_HAL_TXT_TX
+uint32_t tx_cycle = (uint32_t)hal_get_cycles();
+#endif
 
     // get TXT chdev channel, direction and server thread
-    channel    = chdev->channel;
     is_rx      = chdev->is_rx;
     server     = chdev->server;
     server_lid = server->core->lid;
 
-#if (DEBUG_SYS_READ & 1)
-if( is_rx ) enter_tty_isr_read = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_SYS_WRITE & 1)
-if( is_rx == 0 ) enter_tty_isr_write = (uint32_t)hal_get_cycles();
-#endif
-
-#if DEBUG_HAL_TXT_RX
-uint32_t rx_cycle = (uint32_t)hal_get_cycles();
-#endif
-
-#if DEBUG_HAL_TXT_TX
-uint32_t tx_cycle = (uint32_t)hal_get_cycles();
-#endif
-
-    // get SOCLIB_TTY peripheral cluster and local pointer
-    tty_cxy = GET_CXY( chdev->base );
-    tty_ptr = GET_PTR( chdev->base );
-
-    // get channel base address
-    base    = tty_ptr;
-
-    // get extended pointer on TTY registers
-    status_xp = XPTR( tty_cxy , base + MTTY_STATUS );
-    write_xp  = XPTR( tty_cxy , base + MTTY_WRITE );
-    read_xp   = XPTR( tty_cxy , base + MTTY_READ );
+    // get SOCLIB_MTY peripheral cluster and local pointer
+    mty_cxy = GET_CXY( chdev->base );
+    mty_ptr = GET_PTR( chdev->base );
+
+    // get extended pointer on MTY registers
+    status_xp = XPTR( mty_cxy , mty_ptr + MTY_STATUS );
+    write_xp  = XPTR( mty_cxy , mty_ptr + MTY_WRITE );
+    read_xp   = XPTR( mty_cxy , mty_ptr + MTY_READ );
 
     /////////////////////////// handle RX //////////////////////
     if( is_rx )
     {
-        fifo = &mtty_rx_fifo[channel];
-
-        // try to move bytes until MTTY_READ register empty
-        while( hal_remote_lw( status_xp ) & MTTY_STATUS_RX_FULL )   
+        // check one byte available in MTY_READ register
+        if( hal_remote_l32( status_xp ) & MTY_STATUS_RX_FULL )   
         {
-            // get one byte from MTTY_READ register & acknowledge RX_IRQ
+            // get one byte from MTY_READ register & acknowledge RX_IRQ
             byte = (char)hal_remote_lb( read_xp );
 
-            // Ignore Carriage Returns
-            if( byte == 0xD )
-            {
-                continue;
-            }
-
-            // This is the MTTY multiplexing
-            // When a extended ASCII char are received (typing Ctrl-Shift-U then 100+n for example on the terminal)
-            // Two characters are received : 0xFFFFFFc4 then 0xFFFFFF80 + n
-            // When this second char is received, it is considered a metachar that determines the tty dest number
-            // Thus, if you want to make tty 5 the new target, type Ctrl+Shift+U then 105
-            // Now all keystrokes IRQs will be handled by the server DEV thread
-            // associated to RX channel number 5
-            if( (byte & 0xFF) > 0x80 && (byte & 0xFF) <= 0x89 )
-            {
-                // Disable MTTY IRQ for the core owning
-                // the current channel's server DEV thread
-                dev_pic_disable_irq( server_lid, XPTR( local_cxy , chdev ) );
-                
-                int         tty_destnb  = (int)(byte & 0xFF) - 0x80;
-                chdev_t *   new_chdev   = chdev_dir.txt_rx[tty_destnb];
-                lid_t       new_lid     = new_chdev->server->core->lid;
-
-                // Bind MTTY IRQ to the core owning the new channel's server DEV thread
-                dev_pic_bind_irq( new_lid , new_chdev );                
-
-                // Enable MTTY IRQ for the core owning
-                // the new channel's server DEV thread
-                dev_pic_enable_irq( new_lid , XPTR( local_cxy , new_chdev ) );
-
-                channel    = new_chdev->channel;
-                is_rx      = new_chdev->is_rx;
-                server     = new_chdev->server;
-                server_lid = new_lid;
-                fifo = &mtty_rx_fifo[channel];
-                continue;
-            }
-
-            // filter special character ^Z  => block TXT owner process
-            if( byte == 0x1A ) 
-            {
+            // test physical RX channel state
+            if( mty_rx_not_new == false )      // get first byte (virtual channel index)
+            {
+                // register virtual channel index
+                mty_rx_channel = (uint32_t)byte;
+
+                // update physical RX channel state
+                mty_rx_not_new = true;
+            }
+            else                               // get second byte (character value)
+            {
+                // get virtual channel index registered
+                channel = mty_rx_channel;
+
+                // get destination TX_FIFO
+                fifo = &mty_rx_fifo[channel];
+
+                // filter special character ^Z  => block TXT owner process
+                if( byte == 0x1A ) 
+                {
 
 #if DEBUG_HAL_TXT_RX
@@ -368,57 +317,54 @@
 printk("\n[DBG] %s : read ^Z character from TXT%d\n", __FUNCTION__, channel );
 #endif
-                // get pointers on TXT owner process in owner cluster
-                owner_xp  = process_txt_get_owner( channel );
+                    // get pointers on TXT owner process in owner cluster
+                    owner_xp  = process_txt_get_owner( channel );
                
-                // check process exist
-                assert( (owner_xp != XPTR_NULL) , __FUNCTION__, 
-                "TXT owner process not found\n" );
-
-                // get relevant infos on TXT owner process
-                owner_cxy = GET_CXY( owner_xp );
-                owner_ptr = GET_PTR( owner_xp );
-                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
-
-                // block TXT owner process only if it is not the INIT process 
-                if( owner_pid != 1 )
+                    // check process exist
+                    assert( (owner_xp != XPTR_NULL) , __FUNCTION__, 
+                    "TXT owner process not found\n" );
+
+                    // get relevant infos on TXT owner process
+                    owner_cxy = GET_CXY( owner_xp );
+                    owner_ptr = GET_PTR( owner_xp );
+                    owner_pid = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->pid ) );
+
+                    // block TXT owner process only if it is not the INIT process 
+                    if( owner_pid != 1 )
+                    {
+                        // get parent process descriptor pointers
+                        parent_xp = hal_remote_l64( XPTR( owner_cxy , 
+                                                    &owner_ptr->parent_xp ) );
+                        parent_cxy = GET_CXY( parent_xp );
+                        parent_ptr = GET_PTR( parent_xp );
+
+                        // get pointers on the parent process main thread
+                        parent_main_ptr = hal_remote_lpt( XPTR(parent_cxy,
+                                                          &parent_ptr->th_tbl[0])); 
+                        parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
+
+                        // transfer TXT ownership 
+                        process_txt_transfer_ownership( owner_xp );
+
+                        // block all threads in all clusters, but the main thread
+                        process_sigaction( owner_pid , BLOCK_ALL_THREADS );
+
+                        // block the main thread
+                        xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
+                        thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
+
+                        // atomically update owner process termination state
+                        hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
+                                              PROCESS_TERM_STOP );
+
+                        // take the children lock and unblock the parent process main thread 
+                        thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
+
+                        return;
+                    }
+                }
+
+                // filter special character ^C  => kill TXT owner process
+                if( byte == 0x03 )
                 {
-                    // get parent process descriptor pointers
-                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
-                    parent_cxy = GET_CXY( parent_xp );
-                    parent_ptr = GET_PTR( parent_xp );
-
-                    // get extended pointer on lock protecting children list in parent process
-                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
-
-                    // get pointers on the parent process main thread
-                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
-                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
-
-                    // transfer TXT ownership 
-                    process_txt_transfer_ownership( owner_xp );
-
-                    // block all threads in all clusters, but the main thread
-                    process_sigaction( owner_pid , BLOCK_ALL_THREADS );
-
-                    // block the main thread
-                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
-                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
-
-                    // atomically update owner process termination state
-                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
-                                          PROCESS_TERM_STOP );
-
-                    // take the children lock and unblock the parent process main thread 
-                    remote_spinlock_lock( children_lock_xp );
-                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
-                    remote_spinlock_unlock( children_lock_xp );
-
-                    return;
-                }
-            }
-
-            // filter special character ^C  => kill TXT owner process
-            if( byte == 0x03 )
-            {
 
 #if DEBUG_HAL_TXT_RX
@@ -426,57 +372,54 @@
 printk("\n[DBG] %s : read ^C character from TXT%d\n", __FUNCTION__, channel );
 #endif
-                // get pointer on TXT owner process in owner cluster
-                owner_xp  = process_txt_get_owner( channel );
-
-                // check process exist
-                assert( (owner_xp != XPTR_NULL) , __FUNCTION__,
-                "TXT owner process not found\n" );
-
-                // get relevant infos on TXT owner process
-                owner_cxy = GET_CXY( owner_xp );
-                owner_ptr = GET_PTR( owner_xp );
-                owner_pid = hal_remote_lw( XPTR( owner_cxy , &owner_ptr->pid ) );
-
-                // kill TXT owner process only if it is not the INIT process
-                if( owner_pid != 1 )
+                    // get pointer on TXT owner process in owner cluster
+                    owner_xp  = process_txt_get_owner( channel );
+
+                    // check process exist
+                    assert( (owner_xp != XPTR_NULL) , __FUNCTION__,
+                    "TXT owner process not found\n" );
+
+                    // get relevant infos on TXT owner process
+                    owner_cxy = GET_CXY( owner_xp );
+                    owner_ptr = GET_PTR( owner_xp );
+                    owner_pid = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->pid ) );
+
+                    // kill TXT owner process only if it is not the INIT process
+                    if( owner_pid != 1 )
+                    {
+                        // get parent process descriptor pointers
+                        parent_xp  = hal_remote_l64( XPTR( owner_cxy,
+                                                     &owner_ptr->parent_xp ) );
+                        parent_cxy = GET_CXY( parent_xp );
+                        parent_ptr = GET_PTR( parent_xp );
+
+                        // get pointers on the parent process main thread
+                        parent_main_ptr = hal_remote_lpt( XPTR( parent_cxy,
+                                                          &parent_ptr->th_tbl[0])); 
+                        parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
+
+                        // remove process from TXT list
+                        process_txt_detach( owner_xp );
+
+                        // mark for delete all thread in all clusters, but the main
+                        process_sigaction( owner_pid , DELETE_ALL_THREADS );
+                
+                        // block main thread
+                        xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
+                        thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
+
+                        // atomically update owner process termination state
+                        hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
+                                              PROCESS_TERM_KILL );
+
+                        // take the children lock and unblock the parent process main thread 
+                        thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
+
+                        return;
+                    }
+                }
+
+                // write byte in RX FIFO if not full / discard byte if full
+                if ( fifo->sts < MTY_FIFO_DEPTH )
                 {
-                    // get parent process descriptor pointers
-                    parent_xp  = hal_remote_lwd( XPTR( owner_cxy , &owner_ptr->parent_xp ) );
-                    parent_cxy = GET_CXY( parent_xp );
-                    parent_ptr = GET_PTR( parent_xp );
-
-                    // get extended pointer on lock protecting children list in parent process
-                    children_lock_xp = XPTR( parent_cxy , &parent_ptr->children_lock ); 
-
-                    // get pointers on the parent process main thread
-                    parent_main_ptr = hal_remote_lpt(XPTR(parent_cxy,&parent_ptr->th_tbl[0])); 
-                    parent_main_xp  = XPTR( parent_cxy , parent_main_ptr );
-
-                    // remove process from TXT list
-                    process_txt_detach( owner_xp );
-
-                    // mark for delete all thread in all clusters, but the main
-                    process_sigaction( owner_pid , DELETE_ALL_THREADS );
-                
-                    // block main thread
-                    xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] );
-                    thread_block( main_xp , THREAD_BLOCKED_GLOBAL );
-
-                    // atomically update owner process termination state
-                    hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) ,
-                                          PROCESS_TERM_KILL );
-
-                    // take the children lock and unblock the parent process main thread 
-                    remote_spinlock_lock( children_lock_xp );
-                    thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT );
-                    remote_spinlock_unlock( children_lock_xp );
-
-                    return;
-                }
-            }
-
-            // write byte in MTTY_RX FIFO if not full / discard byte if full
-            if ( fifo->sts < MTTY_FIFO_DEPTH )
-            {
 
 #if DEBUG_HAL_TXT_RX
@@ -485,27 +428,31 @@
 __FUNCTION__, byte, channel );
 #endif
-                // store byte into FIFO 
-                fifo->data[fifo->ptw] = (char)byte; 
-
-                // avoid race 
-                hal_fence();
-
-                // update RX_FIFO state
-                fifo->ptw = (fifo->ptw + 1) % MTTY_FIFO_DEPTH;
-                hal_atomic_add( &fifo->sts , 1 );
-
-                // unblock TXT_RX server thread 
-                thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
-
-                // send IPI to core running server thread
-                dev_pic_send_ipi( local_cxy , server_lid );
-            }
-            else
-            {
-                printk("\n[WARNING] %s : MTTY_RX_FIFO[%d] full => discard character <%x>\n",
-                __FUNCTION__, channel, (uint32_t)byte );
-            }
-        }  // end while MTTY_READ register full
-
+                    // store byte into FIFO 
+                    fifo->data[fifo->ptw] = (char)byte; 
+
+                    // avoid race 
+                    hal_fence();
+
+                    // update RX_FIFO state
+                    fifo->ptw = (fifo->ptw + 1) % MTY_FIFO_DEPTH;
+                    hal_atomic_add( &fifo->sts , 1 );
+
+                    // unblock TXT_RX server thread 
+                    thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
+
+                    // send IPI to core running server thread
+                    dev_pic_send_ipi( local_cxy , server_lid );
+                }
+                else
+                {
+                    printk("\n[WARNING] %s : MTY_RX_FIFO[%d] full => discard char <%x>\n",
+                    __FUNCTION__, channel, (uint32_t)byte );
+                }
+
+                // update physical RX channel state
+                mty_rx_not_new = true;
+
+            }  // end get character value
+        }  // end if byte available in MTY_READ register
     }  // end RX
 
@@ -513,13 +460,27 @@
     else
     {
-        fifo = &mtty_tx_fifo[channel];
-
-        // try to move bytes until TX_FIFO empty
-        while( fifo->sts > 0 )
+        // test physical TX channel state
+        if( mty_tx_not_new == false )      // send first byte (virtual channel index)
         {
-            // write one byte to MTTY_WRITE register if empty / exit loop if full
-            if( (hal_remote_lw( status_xp ) & MTTY_STATUS_TX_FULL) == 0 ) 
-            {
-                // get one byte from TX_FIFO
+            // scan the set of the TX_FIFO
+            for( n = 0 , found = false ; n < CONFIG_MAX_TXT_CHANNELS ; n++ )
+            {
+                // implement round-robin policy
+                channel = (n + mty_tx_last + 1) % CONFIG_MAX_TXT_CHANNELS;
+
+                // get pointer on TX_FIFO[channel]
+                fifo = &mty_tx_fifo[channel];
+
+                if( fifo->sts > 0 )
+                {
+                    found = true;
+                    break;
+                }
+            }
+
+            // get one byte from TX_FIFO if found and send channel index
+            if( found ) 
+            {
+                // get one byte from selected TX_FIFO
                 byte = fifo->data[fifo->ptr];
 
@@ -530,107 +491,72 @@
 #endif
                 // update TX_FIFO state
-                fifo->ptr = (fifo->ptr + 1) % MTTY_FIFO_DEPTH;
+                fifo->ptr = (fifo->ptr + 1) % MTY_FIFO_DEPTH;
                 hal_atomic_add( &fifo->sts , -1 );
 
-                // write byte to MTTY_WRITE register & acknowledge TX_IRQ
-                hal_remote_sb( write_xp , byte );
+                // update TX physical channel state
+                mty_tx_value   = (uint32_t)byte;
+                mty_tx_not_new = true;
+                mty_tx_last    = channel;
+
+                // write virtual channel index to TX_WRITE register
+                hal_remote_sb( write_xp , (uint8_t)channel );
+
+                // unblock TXT_TX server thread
+                thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
+
+                // send IPI to core running server thread
+                dev_pic_send_ipi( local_cxy , server_lid );
             }
         }
-
-        // disable TX_IRQ 
-        //      vci_multi_tty devices never raise TX IRQs
-        //      so the following instructions are useless
-        //      and moreover they kernel panic
-        // xptr_t config_xp = XPTR( tty_cxy , base + MTTY_CONFIG );
-        // uint32_t old = hal_remote_lw( config_xp );
-        // uint32_t new = old & ~(MTTY_CONFIG_TX_ENABLE);
-        // hal_remote_atomic_cas( config_xp , old , new );
-        // hal_remote_sw( XPTR( tty_cxy , base + MTTY_CONFIG ) , 0 );
-
-        // unblock TXT_TX server thread
-        thread_unblock( XPTR( local_cxy , server ) , THREAD_BLOCKED_ISR );
-
-        // send IPI to core running server thread
-        dev_pic_send_ipi( local_cxy , server_lid );
-
+        else                             // send second byte (character value) 
+        {
+            // write registered character value to TX_WRITE register
+            hal_remote_sb( write_xp , (uint8_t)mty_tx_value );
+
+            // update TX physical channel state
+            mty_tx_not_new = false;
+        }  // end if MTY_WRITE register empty
     }  // end TX
 
     hal_fence();
 
-#if (DEBUG_SYS_READ & 1)
-if( is_rx ) exit_tty_isr_read = (uint32_t)hal_get_cycles();
-#endif
-
-#if (DEBUG_SYS_WRITE & 1)
-if( is_rx == 0 ) exit_tty_isr_write = (uint32_t)hal_get_cycles();
-#endif
-
-}  // end soclib_mtty_isr()
+}  // end soclib_mty_isr()
 
 /////////////////////////////////////////////////////////////
-void __attribute__ ((noinline)) soclib_mtty_aux( void * args )
+void __attribute__ ((noinline)) soclib_mty_aux( void * args )
 {
-    xptr_t     dev_xp = ((txt_sync_args_t *)args)->dev_xp;
-    char     * buffer = ((txt_sync_args_t *)args)->buffer;
-    uint32_t   count  = ((txt_sync_args_t *)args)->count;
-    uint32_t   channel = ((txt_sync_args_t *)args)->channel;
+    uint32_t   i;
+
+    xptr_t       dev_xp  = ((txt_sync_args_t *)args)->dev_xp;
+    const char * buffer  = ((txt_sync_args_t *)args)->buffer;
+    uint32_t     count   = ((txt_sync_args_t *)args)->count;
+    uint32_t     channel = ((txt_sync_args_t *)args)->channel;
     
-    // get TXT0 chdev cluster and local pointer
+    // get chdev cluster and local pointer
     cxy_t     dev_cxy = GET_CXY( dev_xp );
-    chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
-
-    // get extended pointer on TTY channel base address
-    xptr_t tty_xp = (xptr_t)hal_remote_lwd( XPTR( dev_cxy , &dev_ptr->base ) );
-
-    // get TTY channel segment cluster and local pointer
-    cxy_t      tty_cxy = GET_CXY( tty_xp );
-    uint32_t * tty_ptr = (uint32_t *)GET_PTR( tty_xp );
-
-    // get extended pointers on MTTY_WRITE & MTTY_STATUS registers
-    xptr_t write_xp  = XPTR( tty_cxy , tty_ptr + MTTY_WRITE );
-    xptr_t status_xp = XPTR( tty_cxy , tty_ptr + MTTY_STATUS );
-
-    // loop on characters (busy waiting policy)
-    uint32_t   i;
+    chdev_t * dev_ptr = GET_PTR( dev_xp );
+
+    // get extended pointer on MTY channel base address
+    xptr_t mty_xp = (xptr_t)hal_remote_l64( XPTR( dev_cxy , &dev_ptr->base ) );
+
+    // get MTY channel segment cluster and local pointer
+    cxy_t      mty_cxy = GET_CXY( mty_xp );
+    uint32_t * mty_ptr = GET_PTR( mty_xp );
+
+    // get extended pointers on MTY_WRITE & MTY_STATUS registers
+    xptr_t write_xp  = XPTR( mty_cxy , mty_ptr + MTY_WRITE );
+    xptr_t status_xp = XPTR( mty_cxy , mty_ptr + MTY_STATUS );
+
+    // loop on characters (two bytes per character)
     for( i = 0 ; i < count ; i++ )
     {
-        // This is the MTTY multiplexing
-        // Before each character, we send the destination (RX) TTY number for this char.
-        // The two bytes (dest number + char) must be sent consecutively,
-        // so to guarantee this atomicity, we use a lock to prevent other
-        // concurrent server DEV threads to write a byte in between our two bytes
-
-        // Send the destination TTY number
-        // HACK: Remove this on the Lety physical prototype.
-        // This 'if' is here so that the kernel messages in simulation are readable
-        bool_t empty = false;
-        if (channel > 0) {
-            // For examples, "Hello" would appear "0H0e0l0l0o" on the simulation terminal
-            do {
-                // get MTTY_STATUS
-                uint32_t status = hal_remote_lw( status_xp );
-                empty  = ( (status & MTTY_STATUS_TX_FULL) == 0 );
-
-                // transfer one byte if TX buffer empty
-                if ( empty ) {
-                    hal_remote_sb( write_xp , channel + '0' );
-                }
-            } while ( empty == false );
-        }
-
-        // Send the character
-        do {
-            // get MTTY_STATUS
-            uint32_t status = hal_remote_lw( status_xp );
-            empty  = ( (status & MTTY_STATUS_TX_FULL) == 0 );
-
-            // transfer one byte if TX buffer empty
-            if ( empty ) {
-                hal_remote_sb( write_xp , buffer[i] );
-            }
-        } while ( empty == false );
+        // write virtual channel index to MTY_WRITE register
+        hal_remote_sb( write_xp , (uint8_t)channel );
+
+        // write character value to MTY_WRITE register
+        hal_remote_sb( write_xp , buffer[i] );
     }
-}  // end soclib_mtty_aux()
-
-
-
+}  // end soclib_mty_aux()
+
+
+
