Index: soft/giet_vm/sys/drivers.c
===================================================================
--- soft/giet_vm/sys/drivers.c	(revision 160)
+++ soft/giet_vm/sys/drivers.c	(revision 165)
@@ -16,8 +16,11 @@
 //
 // The following global parameters must be defined in the giet_config.h file:
-// - NB_PROCS  : number of PROCS per cluster (if not zero)
-// - NB_DMAS   : number of DMA channels per cluster (if not zero)
-// - NB_TIMERS : number of TIMERS per cluster (if not zero)
-// - NB_TTYS   : number of TTY terminals per cluster (if not zero) 
+// - NB_CLUSTERS  : number of clusters 
+// - NB_PROCS     : number of PROCS per cluster 
+// - NB_TIMERS    : number of TIMERS per cluster
+// - NB_DMAS      : number of DMA channels
+// - NB_TTYS      : number of TTY terminals
+// - NB_TIMERS    : number of TIMERS per cluster
+// - CLUSTER_SPAN : address increment between clusters
 //
 // The following base addresses must be defined in the sys.ld file:
@@ -58,4 +61,21 @@
 #endif
 
+#if (NB_TTYS < 1)
+# error: NB_TTYS cannot be smaller than 1!
+#endif
+
+#if (NB_TIMERS < NB_PROCS)
+# error: NB_TIMERS must be larger or equal to NB_PROCS!
+#endif
+
+#if (NB_PROCS > 8)
+# error: NB_PROCS cannot be larger than 8!
+#endif
+
+#if (NB_DMAS < 1)
+# error: NB_DMAS cannot be 0!
+#endif
+
+
 /////////////////////////////////////////////////////////////////////////////
 // 	Global (uncachable) variables
@@ -71,15 +91,17 @@
 in_unckdata volatile unsigned int  _ioc_lock = 0;
 
-in_unckdata volatile unsigned int  _tty_lock[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
 in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS];
 in_unckdata volatile unsigned char _tty_get_full[NB_TTYS] = { [0 ... NB_TTYS-1] = 0 };
+in_unckdata unsigned int           _tty_put_lock;
 
 //////////////////////////////////////////////////////////////////////////////
 // 	VciMultiTimer driver
 //////////////////////////////////////////////////////////////////////////////
-// The number of independant timers per cluster is defined by the
-// configuration parameter NB_TIMERS.
+// There is one MULTI-TIMER component per cluster.
+// The number of timers per cluster must be larger or equal to the number 
+// processors (NB_TIMERS >= NB_PROCS), because each processor uses a private
+// yimer for context switch.
 // The total number of timers is NB_CLUSTERS * NB_TIMERS
-// The global timer index = cluster_id*NB_TIMER + timer_id
+// The global timer index = cluster_id*NB_TIMERS + timer_id
 //////////////////////////////////////////////////////////////////////////////
 
@@ -87,25 +109,25 @@
 // _timer_write()
 //
-// Write a 32-bit word in a memory mapped register of a timer device. 
-// Returns 0 if success, > 0 if error.
-//////////////////////////////////////////////////////////////////////////////
-unsigned int _timer_write( unsigned int global_timer_index,
+// Write a 32-bit word in a memory mapped register of a timer device,
+// identified by the cluster index and the local timer index. 
+// Returns 0 if success, > 0 if error.
+//////////////////////////////////////////////////////////////////////////////
+unsigned int _timer_write( unsigned int cluster_index,
+                           unsigned int timer_index,
                            unsigned int register_index, 
                            unsigned int value )
 {
-    volatile unsigned int *timer_address;
-
-    unsigned int	cluster_id = global_timer_index / NB_TIMERS;
-    unsigned int	timer_id   = global_timer_index % NB_TIMERS;
-
-    /* parameters checking */
-    if ( register_index >= TIMER_SPAN) 			return 1;
-    if ( global_timer_index >= NB_CLUSTERS*NB_TIMERS ) 	return 1;
+    unsigned int*	timer_address;
+
+    // parameters checking 
+    if ( register_index >= TIMER_SPAN) 		return 1;
+    if ( cluster_index >= NB_CLUSTERS)		return 1;
+    if ( timer_index >= NB_TIMERS )         return 1;
 
     timer_address = (unsigned int*)&seg_timer_base + 
-                    ( cluster_id * CLUSTER_SPAN )  +
-                    ( timer_id * TIMER_SPAN );
-
-    timer_address[register_index] = value; /* write word */
+                    ( cluster_index * CLUSTER_SPAN )  +
+                    ( timer_index * TIMER_SPAN );
+
+    timer_address[register_index] = value; // write word
 
     return 0;
@@ -115,25 +137,25 @@
 // _timer_read()
 //
-// Read a 32-bit word in a memory mapped register of a timer device. 
-// Returns 0 if success, > 0 if error.
-//////////////////////////////////////////////////////////////////////////////
-unsigned int _timer_read(unsigned int global_timer_index,
+// Read a 32-bit word in a memory mapped register of a timer device,
+// identified by the cluster index and the local timer index. 
+// Returns 0 if success, > 0 if error.
+//////////////////////////////////////////////////////////////////////////////
+unsigned int _timer_read(unsigned int cluster_index,
+                         unsigned int timer_index, 
                          unsigned int register_index, 
                          unsigned int *buffer)
 {
-    volatile unsigned int *timer_address;
-
-    unsigned int	cluster_id = global_timer_index / NB_TIMERS;
-    unsigned int	timer_id   = global_timer_index % NB_TIMERS;
-
-    /* parameters checking */
-    if ( register_index >= TIMER_SPAN) 			return 1;
-    if ( global_timer_index >= NB_CLUSTERS*NB_TIMERS ) 	return 1;
+    unsigned int *timer_address;
+
+    // parameters checking
+    if ( register_index >= TIMER_SPAN) 		return 1;
+    if ( cluster_index >= NB_CLUSTERS)		return 1;
+    if ( timer_index >= NB_TIMERS )         return 1;
 
     timer_address = (unsigned int*)&seg_timer_base + 
-                    ( cluster_id * CLUSTER_SPAN )  +
-                    ( timer_id * TIMER_SPAN );
-
-    *buffer = timer_address[register_index]; /* read word */
+                    ( cluster_index * CLUSTER_SPAN )  +
+                    ( timer_index * TIMER_SPAN );
+
+    *buffer = timer_address[register_index]; // read word 
 
     return 0;
@@ -146,5 +168,5 @@
 // The system terminal is TTY[0].
 // The TTYs are allocated to applications by the GIET in the boot phase.
-// The nummber of TTYs allocated to each application, and the TTY used by each
+// The nummber of TTYs allocated to each application, and used by each
 // task can be defined in the mapping_info data structure.
 // For each user task, the tty_id is stored in the context of the task (slot 34),
@@ -152,35 +174,4 @@
 // The TTY address is always computed as : seg_tty_base + tty_id*TTY_SPAN
 ///////////////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////////////
-// tty_get_lock()
-//
-// This blocking function is intended to be used by the _tty_write() function
-// to provide exclusive access to the TTY. It is not used yet, because it appears
-// that it creates livelock situations...
-///////////////////////////////////////////////////////////////////////////////////
-static inline void _tty_get_lock( unsigned int tty_id )
-{
-    register unsigned int delay = (_proctime() & 0xF) << 4;
-    register unsigned int *plock = (unsigned int*)&_tty_lock[tty_id];
-
-    asm volatile (
-            "_tty_llsc:             \n"
-            "ll   $2,    0(%0)      \n" /* $2 <= _tty_lock current value */
-            "bnez $2,    _tty_delay \n" /* delay if _tty_lock already taken */
-            "li   $3,    1          \n" /* $3 <= argument for sc */
-            "sc   $3,    0(%0)      \n" /* try to set _tty_lock */
-            "bnez $3,    _tty_ok    \n" /* exit if atomic */
-            "_tty_delay:            \n"
-            "move $4,    %1         \n" /* $4 <= delay */
-            "_tty_loop:             \n"
-            "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
-            "beqz $4,    _tty_loop  \n" /* test end delay */
-            "j           _tty_llsc  \n" /* retry */
-            "_tty_ok:               \n"
-            :
-            :"r"(plock), "r"(delay)
-            :"$2", "$3", "$4");
-}
 
 //////////////////////////////////////////////////////////////////////////////
@@ -194,5 +185,6 @@
 // The function returns  the number of characters that have been written.
 //////////////////////////////////////////////////////////////////////////////
-unsigned int _tty_write(const char *buffer, unsigned int length)
+unsigned int _tty_write( const char		*buffer, 
+                         unsigned int	length)
 {
     volatile unsigned int *tty_address;
@@ -212,9 +204,9 @@
     for (nwritten = 0; nwritten < length; nwritten++)
     {
-        /* check tty's status */
+        // check tty's status 
         if ((tty_address[TTY_STATUS] & 0x2) == 0x2)
             break;
         else
-            /* write character */
+            // write character 
             tty_address[TTY_WRITE] = (unsigned int)buffer[nwritten];
     }
@@ -226,5 +218,5 @@
 //
 // This non-blocking function uses the TTY_GET_IRQ[tty_id] interrupt and 
-// the associated // kernel buffer, that has been written by the ISR.
+// the associated kernel buffer, that has been written by the ISR.
 // It fetches one single character from the _tty_get_buf[tty_id] kernel
 // buffer, writes this character to the user buffer, and resets the
@@ -232,5 +224,6 @@
 // Returns 0 if the kernel buffer is empty, 1 if the buffer is full.
 //////////////////////////////////////////////////////////////////////////////
-unsigned int _tty_read_irq(char *buffer, unsigned int length)
+unsigned int _tty_read_irq( char			*buffer, 
+                            unsigned int	length)
 {
     unsigned int proc_id;
@@ -262,8 +255,8 @@
 // register of the TTY controler, and writes this character to the user buffer.
 // It doesn't use the TTY_GET_IRQ interrupt and the associated kernel buffer.
-// It doesn't take the lock protecting exclusive access...
 // Returns 0 if the register is empty, 1 if the register is full.
 ////////////////////////////////////////////////////////////////////////////////
-unsigned int _tty_read(char *buffer, unsigned int length)
+unsigned int _tty_read( char			*buffer, 
+                        unsigned int	length)
 {
     volatile unsigned int *tty_address;
@@ -296,20 +289,25 @@
 // _icu_write()
 //
-// Write a 32-bit word in a memory mapped register of the ICU device. The
-// base address is deduced by the proc_id.
-// Returns 0 if success, > 0 if error.
-////////////////////////////////////////////////////////////////////////////////
-unsigned int _icu_write(unsigned int register_index, unsigned int value)
-{
-    volatile unsigned int *icu_address;
-    unsigned int proc_id;
-
-    /* parameters checking */
-    if (register_index >= ICU_END)
-        return 1;
-
-    proc_id = _procid();
-    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
-    icu_address[register_index] = value;   /* write word */
+// Write a 32-bit word in a memory mapped register of the MULTI_ICU device,
+// identified by the cluster index, and a processor local index.
+// Returns 0 if success, > 0 if error.
+////////////////////////////////////////////////////////////////////////////////
+unsigned int _icu_write( unsigned int cluster_index,
+                         unsigned int proc_index,
+                         unsigned int register_index, 
+                         unsigned int value )
+{
+    unsigned int *icu_address;
+
+    // parameters checking 
+    if ( register_index >= ICU_SPAN) 		return 1;
+    if ( cluster_index >= NB_CLUSTERS)		return 1;
+    if ( proc_index >= NB_PROCS )           return 1;
+
+    icu_address = (unsigned int*)&seg_icu_base + 
+                  ( cluster_index * CLUSTER_SPAN )  +
+                  ( proc_index * ICU_SPAN );
+
+    icu_address[register_index] = value;   // write word 
     return 0;
 }
@@ -318,20 +316,25 @@
 // _icu_read()
 //
-// Read a 32-bit word in a memory mapped register of the ICU device. The
-// ICU base address is deduced by the proc_id.
-// Returns 0 if success, > 0 if error.
-////////////////////////////////////////////////////////////////////////////////
-unsigned int _icu_read(unsigned int register_index, unsigned int *buffer)
-{
-    volatile unsigned int *icu_address;
-    unsigned int proc_id;
-
-    /* parameters checking */
-    if (register_index >= ICU_END)
-        return 1;
-
-    proc_id = _procid();
-    icu_address = (unsigned int*)&seg_icu_base + (proc_id * ICU_SPAN);
-    *buffer = icu_address[register_index]; /* read word */
+// Read a 32-bit word in a memory mapped register of the MULTI_ICU device,
+// identified by the cluster index and a processor local index.
+// Returns 0 if success, > 0 if error.
+////////////////////////////////////////////////////////////////////////////////
+unsigned int _icu_read(  unsigned int cluster_index,
+                         unsigned int proc_index,
+                         unsigned int register_index, 
+                         unsigned int* buffer )
+{
+    unsigned int *icu_address;
+
+    // parameters checking 
+    if ( register_index >= ICU_SPAN) 		return 1;
+    if ( cluster_index >= NB_CLUSTERS)		return 1;
+    if ( proc_index >= NB_PROCS )           return 1;
+
+    icu_address = (unsigned int*)&seg_icu_base + 
+                  ( cluster_index * CLUSTER_SPAN )  +
+                  ( proc_index * ICU_SPAN );
+
+    *buffer = icu_address[register_index]; // read word 
     return 0;
 }
@@ -341,5 +344,5 @@
 ////////////////////////////////////////////////////////////////////////////////
 // The Greater Dommon Divider is a -very- simple hardware coprocessor
-// performing the computation of a GCD of two 32 bits integers.
+// performing the computation of the GCD of two 32 bits integers.
 // It has no DMA capability.
 ////////////////////////////////////////////////////////////////////////////////
@@ -351,14 +354,16 @@
 // Returns 0 if success, > 0 if error.
 ////////////////////////////////////////////////////////////////////////////////
-unsigned int _gcd_write(unsigned int register_index, unsigned int value)
+unsigned int _gcd_write( unsigned int register_index, 
+                         unsigned int value)
 {
     volatile unsigned int *gcd_address;
 
-    /* parameters checking */
+    // parameters checking
     if (register_index >= GCD_END)
         return 1;
 
     gcd_address = (unsigned int*)&seg_gcd_base;
-    gcd_address[register_index] = value; /* write word */
+
+    gcd_address[register_index] = value; // write word
     return 0;
 }
@@ -370,14 +375,16 @@
 // Returns 0 if success, > 0 if error.
 ////////////////////////////////////////////////////////////////////////////////
-unsigned int _gcd_read(unsigned int register_index, unsigned int *buffer)
+unsigned int _gcd_read( unsigned int register_index, 
+                        unsigned int *buffer)
 {
     volatile unsigned int *gcd_address;
 
-    /* parameters checking */
+    // parameters checking 
     if (register_index >= GCD_END)
         return 1;
 
     gcd_address = (unsigned int*)&seg_gcd_base;
-    *buffer = gcd_address[register_index]; /* read word */
+
+    *buffer = gcd_address[register_index]; // read word
     return 0;
 }
@@ -386,7 +393,7 @@
 // VciBlockDevice driver
 ////////////////////////////////////////////////////////////////////////////////
-// The VciBlockDevice is a simple external storage contrÃŽler.
+// The VciBlockDevice is a single channel external storage contrÃŽler.
 // The three functions below use the three variables _ioc_lock _ioc_done,  and
-// _ioc_status for synchronsation.
+// _ioc_status for synchronisation.
 // As the IOC component can be used by several programs running in parallel,
 // the _ioc_lock variable guaranties exclusive access to the device.  The
@@ -429,7 +436,8 @@
             "move $4,    %1         \n" /* $4 <= delay */
             "_ioc_loop:             \n"
+            "beqz $4,    _ioc_loop  \n" /* test end delay */
             "addi $4,    $4,    -1  \n" /* $4 <= $4 - 1 */
-            "beqz $4,    _ioc_loop  \n" /* test end delay */
-            "j           _ioc_llsc  \n" /* retry */
+            "j           _ioc_llsc  \n" /* retry ll */
+            "nop                    \n"
             "_ioc_ok:               \n"
             :
