Index: /trunk/softs/giet_tsar/block_device.h
===================================================================
--- /trunk/softs/giet_tsar/block_device.h	(revision 158)
+++ /trunk/softs/giet_tsar/block_device.h	(revision 158)
@@ -0,0 +1,67 @@
+/*
+ * SOCLIB_LGPL_HEADER_BEGIN
+ *
+ * This file is part of SoCLib, GNU LGPLv2.1.
+ *
+ * SoCLib is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ *
+ * SoCLib is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with SoCLib; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * SOCLIB_LGPL_HEADER_END
+ *
+ * Copyright (c) UPMC, Lip6, Asim
+ *         Nicolas Pouillon <nipo@ssji.net>, 2007
+ *
+ * Maintainers: nipo
+ */
+#ifndef BLOCK_DEVICE_REGS_H
+#define BLOCK_DEVICE_REGS_H
+
+enum SoclibBlockDeviceRegisters {
+    BLOCK_DEVICE_BUFFER,
+    BLOCK_DEVICE_LBA,
+    BLOCK_DEVICE_COUNT,
+    BLOCK_DEVICE_OP,
+    BLOCK_DEVICE_STATUS,
+    BLOCK_DEVICE_IRQ_ENABLE,
+    BLOCK_DEVICE_SIZE,
+    BLOCK_DEVICE_BLOCK_SIZE,
+};
+
+enum SoclibBlockDeviceOp {
+    BLOCK_DEVICE_NOOP,
+    BLOCK_DEVICE_READ,
+    BLOCK_DEVICE_WRITE,
+};
+
+enum SoclibBlockDeviceStatus {
+    BLOCK_DEVICE_IDLE,
+    BLOCK_DEVICE_BUSY,
+    BLOCK_DEVICE_READ_SUCCESS,
+    BLOCK_DEVICE_WRITE_SUCCESS,
+    BLOCK_DEVICE_READ_ERROR,
+    BLOCK_DEVICE_WRITE_ERROR,
+    BLOCK_DEVICE_ERROR,
+};
+
+#endif /* BLOCK_DEVICE_REGS_H */
+
+// Local Variables:
+// tab-width: 4
+// c-basic-offset: 4
+// c-file-offsets:((innamespace . 0)(inline-open . 0))
+// indent-tabs-mode: nil
+// End:
+
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/dma.h
===================================================================
--- /trunk/softs/giet_tsar/dma.h	(revision 158)
+++ /trunk/softs/giet_tsar/dma.h	(revision 158)
@@ -0,0 +1,31 @@
+#ifndef DMA_REGS_H
+#define DMA_REGS_H
+
+enum SoCLibDmaRegisters {
+    DMA_SRC         = 0,
+    DMA_DST         = 1,
+    DMA_LEN         = 2,
+    DMA_RESET       = 3,
+    DMA_IRQ_DISABLE = 4,
+    /***/
+    DMA_SPAN        = 8,
+};
+
+enum DmaStatusValues {
+    DMA_IDLE        = 0,
+    DMA_SUCCESS     = 1,
+    DMA_READ_ERROR  = 2,
+    DMA_WRITE_ERROR = 3,
+};
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/drivers.c
===================================================================
--- /trunk/softs/giet_tsar/drivers.c	(revision 158)
+++ /trunk/softs/giet_tsar/drivers.c	(revision 158)
@@ -0,0 +1,937 @@
+/****************************************************************************************
+File : drivers.c
+Written by Alain Greiner & Nicolas Pouillon
+Date : december 2010
+
+Basic drivers used by the GIET, that is running
+on the MIPS32 processor architecture.
+
+The supported peripherals are:
+- the SoClib pibus_multi_tty
+- the SocLib pibus_timer
+- the SocLib pibus_dma
+- The SoCLib pibus_icu
+- The SoCLib pibus_gcd
+- The SoCLib pibus_frame_buffer
+- The SoCLib pibus_block_device
+
+The following global parameters must be defined in the ldscript.
+- NB_CLUSTERS : number of clusters 
+- NB_PROCS : number of processor per cluster
+- NB_NTASKS : max number of tasks per processor
+- NB_LOCKS : max number of supported spin_locks
+- NB_TIMERS : max number of timers per processor
+
+The follobing base addresses must be defined in the ldscript
+- seg_icu_base
+- seg_timer_base
+- seg_tty_base
+- seg_gcd_base
+- seg_dma_base
+- seg_locks_base
+- seg_fb_base
+- seg_ioc_base
+****************************************************************************************/
+
+#include "drivers.h"
+#include "icu.h"
+#include "block_device.h"
+#include "dma.h"
+
+struct plouf;
+
+//////////////////////////////////////////////////////////////
+// various informations that must be defined in ldscript
+//////////////////////////////////////////////////////////////
+extern struct plouf seg_icu_base;
+extern struct plouf seg_timer_base;
+extern struct plouf seg_tty_base;
+extern struct plouf seg_gcd_base;
+extern struct plouf seg_dma_base;
+extern struct plouf seg_locks_base;
+extern struct plouf seg_fb_base;
+extern struct plouf seg_ioc_base;
+
+extern struct plouf NB_CLUSTERS;
+extern struct plouf NB_PROCS;
+extern struct plouf NB_TASKS;
+extern struct plouf NB_TIMERS;
+extern struct plouf NB_LOCKS;
+
+#define in_drivers __attribute__((section (".drivers")))
+#define in_unckdata __attribute__((section (".unckdata")))
+
+////////////////////////////////////////////////////////////////////////////////////////
+//  Global uncachable variables for synchronization between drivers and ISRs
+////////////////////////////////////////////////////////////////////////////////////////
+
+in_unckdata int volatile    _dma_status[256];
+in_unckdata int volatile    _dma_busy[256]   =   { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+in_unckdata int volatile    _ioc_lock    = 0;
+in_unckdata int volatile    _ioc_done    = 0;
+in_unckdata int volatile    _ioc_status;
+
+in_unckdata char volatile   _tty_get_buf[256];
+in_unckdata int volatile    _tty_get_full[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+in_unckdata char volatile   _tty_put_buf[256];
+in_unckdata int volatile    _tty_put_full[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+////////////////////////////////////////////////////////////////////////////////////////
+//  Global uncachable variables for inter-task barriers
+////////////////////////////////////////////////////////////////////////////////////////
+
+in_unckdata int volatile    _barrier_initial_value[8] = { 0,0,0,0,0,0,0,0 };
+in_unckdata int volatile    _barrier_count[8]         = { 0,0,0,0,0,0,0,0 };
+
+////////////////////////////////////////////////////////////////////////////////////////
+//  Global uncachable variables for spin_locks using LL/C instructions
+////////////////////////////////////////////////////////////////////////////////////////
+
+in_unckdata int volatile    _spin_lock[256] =    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+                                                   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+////////////////////////////////////////////////////////////////////////////////////////
+//  mempcy()
+// GCC requires this function. Taken from MutekH.
+////////////////////////////////////////////////////////////////////////////////////////
+__attribute((used))
+in_drivers static void *memcpy(void *_dst, const void *_src, unsigned int size)
+{
+    unsigned int *dst = _dst;
+    const unsigned int *src = _src;
+    if ( ! ((unsigned int)dst & 3) && ! ((unsigned int)src & 3) )
+        while (size > 3) {
+            *dst++ = *src++;
+            size -= 4;
+        }
+
+    unsigned char *cdst = (unsigned char*)dst;
+    unsigned char *csrc = (unsigned char*)src;
+
+    while (size--) {
+        *cdst++ = *csrc++;
+    }
+    return _dst;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+//  _procid()
+// Access CP0 and returns processor ident
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned int _procid()
+{
+    unsigned int ret;
+    asm volatile( "mfc0 %0, $15, 1": "=r"(ret) );
+    return (ret & 0xFF);
+}
+////////////////////////////////////////////////////////////////////////////////////////
+//  _segment_increment()
+// Access CP0 to get the procid, and returns the address increment to access 
+// various peripherals (TTY, TIMER, ICU, DMA), in case of multiprocessors architectures.
+// It uses the NB_PROCS and NB_CLUSTERS parameters to compute this increment:
+// - increment  = cluster_id*cluster_increment + local_id*local_increment
+// - cluster_id = procid / NB_PROCS  
+// - local_id   = procid % NB_PROCS 
+// - cluster_increment = 4G / NB_CLUSTERS
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned int _segment_increment(unsigned int local_increment)
+{
+    unsigned int	nprocs   		= (unsigned int)&NB_PROCS;
+    unsigned int	nclusters		= (unsigned int)&NB_CLUSTERS;
+    unsigned int	cluster_increment	= (0x80000000/nclusters)*2;
+    unsigned int	pid			= _procid();
+    return (pid / nprocs)*cluster_increment + (pid % nprocs)*local_increment;
+}
+////////////////////////////////////////////////////////////////////////////////////////
+//  _proctime()
+// Access CP0 and returns processor time
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned int _proctime()
+{
+    unsigned int ret;
+    asm volatile( "mfc0 %0, $9": "=r"(ret) );
+    return ret;
+}
+////////////////////////////////////////////////////////////////////////////////////////
+//  _procnumber()
+// Returns the number of processsors controled by the GIET
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers unsigned int _procnumber()
+{
+    return (unsigned int)&NB_PROCS * (unsigned int)&NB_CLUSTERS;
+}
+////////////////////////////////////////////////////////////////////////////////////////
+//  _it_mask()
+// Access CP0 and mask IRQs
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers void _it_mask()
+{
+    int tmp;
+    asm volatile("mfc0  %0, $12"    : "=r" (tmp) );
+    asm volatile("ori   %0, %0, 1"  : "=r" (tmp) );
+    asm volatile("mtc0  %0, $12"    : "=r" (tmp) );
+}
+////////////////////////////////////////////////////////////////////////////////////////
+//  _it_enable()
+// Access CP0 and enable IRQs
+////////////////////////////////////////////////////////////////////////////////////////
+in_drivers void _it_enable()
+{
+    int tmp;
+    asm volatile("mfc0  %0, $12"    : "=r" (tmp) );
+    asm volatile("addi  %0, %0, -1" : "=r" (tmp) );
+    asm volatile("mtc0  %0, $12"    : "=r" (tmp) );
+}
+//////////////////////////////////////////////////////////////////////
+//  _dcache_buf_invalidate()
+// Invalidate all cache lines corresponding to a memory buffer.
+// This is used by the block_device driver.
+/////////////////////////////////////////////////////////////////////////
+in_drivers void _dcache_buf_invalidate(const void * buffer, size_t size)
+{
+    size_t i;
+    size_t dcache_line_size;
+
+    // retrieve dcache line size from config register (bits 12:10)
+    asm volatile("mfc0 %0, $16, 1" : "=r" (dcache_line_size));
+
+    dcache_line_size = 2 << ((dcache_line_size>>10) & 0x7);
+
+    // iterate on lines to invalidate each one of them
+    for ( i=0; i<size; i+=dcache_line_size )
+        asm volatile(" cache %0, %1"
+                :
+                :"i" (0x11), "R" (*((char*)buffer+i)));
+}
+
+/////////////////////////////////////////////////////////////////////////
+//  _itoa_dec()
+// convert a 32 bits unsigned int to a string of 10 decimal characters.
+/////////////////////////////////////////////////////////////////////////
+in_drivers void _itoa_dec(unsigned val, char* buf)
+{
+    const char  DecTab[] = "0123456789";
+    unsigned int i;
+    for( i=0 ; i<10 ; i++ )
+    {
+        if( (val!=0) || (i==0) ) buf[9-i] = DecTab[val % 10];
+        else                     buf[9-i] = 0x20;
+        val /= 10;
+    }
+}
+//////////////////////////////////////////////////////////////////////////
+//  _itoa_hex()
+// convert a 32 bits unsigned int to a string of 8 hexadecimal characters.
+///////////////////////////////////////////////////////////////////////////
+in_drivers void _itoa_hex(int val, char* buf)
+{
+    const char  HexaTab[] = "0123456789ABCD";
+    unsigned int i;
+    for( i=0 ; i<8 ; i++ )
+    {
+        buf[7-i] = HexaTab[val % 16];
+        val /= 16;
+    }
+}
+///////////////////////////////////////////////////////////////////////////////////////
+// MULTI_TIMER component
+// Each processor can handle up to NB_TIMERS independant timers.
+// The segment base address is defined as
+//         seg_timer_base + segment_increment(NB_TIMERS*16) + index*16
+///////////////////////////////////////////////////////////////////////////////////////
+//  _timer_write()
+// Write a 32 bits word in a memory mapped register of the MULTI_TIMER
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _timer_write(size_t timer_index, size_t register_index, int value)
+{
+    int*    		timer_address;
+    size_t           	ntimers 	= (size_t)&NB_TIMERS;
+    unsigned int     	base      	= (unsigned int)&seg_timer_base;
+    unsigned int     	increment 	= _segment_increment(ntimers*TIMER_SPAN*4); 
+
+    if( timer_index >= ntimers) 	return -1;
+    if( register_index >= TIMER_SPAN ) 	return -1;
+
+    timer_address = (int*)(base + increment + timer_index*TIMER_SPAN*4);
+    timer_address[register_index] = value;          // write word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _timer_read()
+// Read a 32 bits word in a memory mapped register of the MULTI_TIMER
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _timer_read(size_t timer_index, size_t register_index, int* buffer)
+{
+    int*    		timer_address;
+    size_t           	ntimers 	= (size_t)&NB_TIMERS;
+    unsigned int     	base      	= (unsigned int)&seg_timer_base;
+    unsigned int     	increment 	= _segment_increment(ntimers*TIMER_SPAN*4); 
+
+    if( timer_index >= ntimers) 	return -1;
+    if( register_index >= TIMER_SPAN ) 	return -1;
+
+    if( timer_index >= ntimers) return -1;
+    if( register_index >= TIMER_SPAN ) return -1;
+
+    timer_address = (int*)(base + increment + timer_index*TIMER_SPAN*4);
+    *buffer = timer_address[register_index];        // read word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  MULTI_TTY COMPONENT
+// The total number of TTYs is equal to NB_CLUSTERS * NB_PROCS * NB_TASKS.
+// - tty_address = seg_tty_base + _segment_increment(NB_TASKS*16) + task_id*16
+// - tty_index   = proc_id*NB_TASKS + task_id
+///////////////////////////////////////////////////////////////////////////////////////
+//  _tty_write()
+// Write one or several characters directly from a fixed length user buffer
+// to the TTY_WRITE register of the TTY controler.
+// It doesn't use the TTY_PUT_IRQ interrupt and the associated kernel buffer.
+// 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
+// returns  the number of characters that have been actually written.
+// It returns -1 in case of error (proc_id or task index too large)
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _tty_write(char* buffer, int length)
+{
+    char*   		tty_address;
+    size_t  		ntasks 		= (size_t)&NB_TASKS;
+    size_t  		nprocs 		= (size_t)&NB_PROCS;
+    size_t		nclusters	= (size_t)&NB_CLUSTERS;
+    unsigned int    	base		= (unsigned int)&seg_tty_base;
+    unsigned int	increment 	= _segment_increment(ntasks*TTY_SPAN*4);
+    size_t  		pid 		= _procid();
+    size_t		tid		= _current_task_array[pid];
+    int     		nwritten 	= 0;
+    int     		i;
+
+    if( tid >= ntasks )   		return -1;
+    if( pid >= nprocs*nclusters )   	return -1;
+
+    tty_address = (char*)(base + increment + tid*TTY_SPAN*4);
+
+    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++;
+        }
+    }
+    return nwritten;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _tty_read()
+// Fetch one character directly from the TTY_READ 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.
+// This is a non blocking call : it returns 0 if the register is empty,
+// and returns 1 if the register is full.
+// It returns -1 in case of error (proc_id or task_id too large or length != 1)
+// The length argument is not used in this implementation, and has been
+// introduced for future implementations.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _tty_read(char* buffer, int length)
+{
+    char*   		tty_address;
+    size_t  		ntasks 		= (size_t)&NB_TASKS;
+    size_t  		nprocs 		= (size_t)&NB_PROCS;
+    size_t  		nclusters	= (size_t)&NB_CLUSTERS;
+    unsigned int    	base		= (unsigned int)&seg_tty_base;
+    unsigned int	increment 	= _segment_increment(ntasks*TTY_SPAN*4);
+    size_t  		pid 		= _procid();
+    size_t		tid		= _current_task_array[pid];
+
+    if( length != 1)      		return -1;
+    if( pid >= nprocs*nclusters )   	return -1;
+    if( tid >= ntasks )   		return -1;
+    
+    tty_address = (char*)(base + increment + tid*TTY_SPAN*4);
+
+    if((tty_address[TTY_STATUS*4] & 0x1) == 0x1)
+    {
+        buffer[0] = tty_address[TTY_READ*4];
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _tty_read_irq()
+// iAS it uses the TTY_GET_IRQ interrupt and the associated kernel buffer,
+// that has been written by the ISR, this function does not access the TTY registers.
+// It fetch one single character from the _tty_get_buf[tty_index] kernel buffer, writes 
+// this character to the user buffer, and reset the _tty_get_full[tty_index] buffer.
+// This is a non blocking call : it returns 0 if the kernel buffer is empty,
+// and returns 1 if the buffer is full.
+// It returns -1 in case of error (proc_id or task_id too large, or length != 1)
+// The length argument is not used in this implementation, and has been
+// introduced for future implementations.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _tty_read_irq(char* buffer, int length)
+{
+    int     pid 	= _procid();
+    int     tid		= _current_task_array[pid];
+    int     ntasks 	= (int)&NB_TASKS;
+    int     nprocs 	= (int)&NB_PROCS;
+    int     nclusters	= (int)&NB_CLUSTERS;
+    int     tty_index;
+
+    if( length != 1)      		return -1;
+    if( pid >= nprocs*nclusters )   	return -1;
+    if( tid >= ntasks )   		return -1;
+
+    tty_index = pid*ntasks + tid;
+    if( _tty_get_full[tty_index] == 0 ) return 0;
+
+    *buffer = _tty_get_buf[tty_index];
+    _tty_get_full[tty_index] = 0;
+    return 1;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _exit()
+// Exit (suicide) after printing message on  a TTY terminal.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int  _exit()
+{
+    char buf[] = "\n\n!!!  Exit  Processor          !!!\n";
+    int pid = _procid();
+
+    buf[24] = '0';
+    buf[25] = 'x';
+    buf[26] = (char)((pid>>8) & 0xF) + 0x30;
+    buf[27] = (char)((pid>>4) & 0xF) + 0x30;
+    buf[28] = (char)(pid & 0xF)      + 0x30;
+    _tty_write(buf, 36);
+
+    while(1) asm volatile("nop");   // infinite loop...
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+//  _icu_write()
+// Write a 32 bits word in a memory mapped register of the ICU peripheral
+// The base address is defined by the processor ID
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _icu_write(size_t register_index, int value)
+{
+    int*    		icu_address;
+    unsigned int	base = (int)&seg_icu_base;
+    unsigned int	increment = _segment_increment(ICU_SPAN*4);
+
+    if( register_index >= ICU_SPAN ) return -1;
+
+    icu_address = (int*)(base + increment);
+    icu_address[register_index] = value;   // write word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _icu_read()
+// Read a 32 bits word in a memory mapped register of the ICU peripheral
+// The ICU base address is defined by the processor ID
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _icu_read(size_t register_index, int* buffer)
+{
+    int*    		icu_address;
+    unsigned int	base = (int)&seg_icu_base;
+    unsigned int	increment = _segment_increment(ICU_SPAN*4);
+
+    if( register_index >= ICU_SPAN ) return -1;
+
+    icu_address = (int*)(base + increment);
+    *buffer = icu_address[register_index]; 	// read word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _gcd_write()
+// Write a 32 bits word in a memory mapped register of the GCD coprocessor
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _gcd_write(size_t register_index, int value)
+{
+    int*    gcd_address;
+    if( register_index >= 4 ) return -1;
+
+    gcd_address = (int*)&seg_gcd_base;
+    gcd_address[register_index] = value;            // write word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _gcd_read()
+// Read a 32 bits word in a memory mapped register of the GCD coprocessor
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _gcd_read(size_t register_index, int* buffer)
+{
+    int*    gcd_address;
+    if( register_index >= 4 ) return -1;
+
+    gcd_address = (int*)&seg_gcd_base;
+    *buffer = gcd_address[register_index];          // read word
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _locks_write()
+// Release a software spin-lock 
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _locks_write(size_t index)
+
+{
+    int     max = (int)&NB_LOCKS;
+    if( index >= max ) return -1;
+
+    _spin_lock[index] = 0;
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _locks_read()
+// Try to take a software spin-lock.
+// This is a blocking call, as there is a busy-waiting loop,
+// until the lock is granted to the requester.
+// There is an internal delay of about 100 cycles between
+// two successive lock read, to avoid bus saturation.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _locks_read(size_t index)
+{
+    int     max = (int)&NB_LOCKS;
+    if( index >= max ) return -1;
+
+    register int	delay = ( (_proctime() + _procid() ) & 0xF) << 4;
+    register int*	plock = (int*)&_spin_lock[index];			
+
+    asm volatile ("_locks_llsc:		        \n"
+                  "ll   $2,    0(%0)		\n" 	// $2 <= _locks_lock
+                  "bnez $2,    _locks_delay	\n" 	// random delay if busy
+                  "li   $3,    1   		\n" 	// prepare argument for sc  
+                  "sc   $3,    0(%0)       	\n" 	// try to set _locks_busy
+                  "bnez $3,    _locks_ok     	\n" 	// exit if atomic 
+                  "_locks_delay:		\n"
+                  "move $4,    %1		\n"	// $4 <= delay
+                  "_locks_loop:			\n"
+                  "addi $4,    $4,    -1	\n"	// $4 <= $4 - 1
+                  "beqz $4,    _locks_loop	\n"	// test end delay
+                  "j           _locks_llsc    	\n"	// retry
+                  "_locks_ok:			\n"
+                  ::"r"(plock),"r"(delay):"$2","$3","$4");
+    return 0;
+}
+//////////////////////////////////////////////////////////////////////////////////////////
+//  I/O BLOCK_DEVICE
+// The three functions below use the three variables _ioc_lock _ioc_done, 
+// and _ioc_status for synchronsation.
+// - As the IOC component can be used by several programs running in parallel,
+// the _ioc_lock variable guaranties exclusive access to the device.
+// The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
+// and set _ioc_lock to a non zero value. 
+// The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock
+// variable until the device is available.
+// - When the tranfer is completed, the ISR routine activated by the IOC IRQ
+// set the _ioc_done variable to a non-zero value. Possible address errors detected
+// by the IOC peripheral are reported by the ISR in the _ioc_status variable.
+// The _ioc_completed() function is polling the _ioc_done variable, waiting for
+// tranfer conpletion. When the completion is signaled, the _ioc_completed() function
+// reset the _ioc_done variable to zero, and releases the _ioc_lock variable.
+// 
+// In a multi-tasks environment, this polling policy must be replaced by a
+// descheduling policy for the requesting process. 
+///////////////////////////////////////////////////////////////////////////////////////
+//  _ioc_get_lock()
+// This blocking function is used by the _ioc_read() and _ioc_write() functions 
+// to get _ioc_lock using LL/SC.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers void _ioc_get_lock()
+{
+    register unsigned int	delay = (_proctime() & 0xF) << 4;
+    register unsigned int*	plock = (unsigned int*)&_ioc_lock;			
+
+    asm volatile ("_ioc_llsc:			        \n"
+                  "ll   $2,    0(%0)		    \n"	// $2 <= _ioc_lock
+                  "bnez $2,    _ioc_delay	    \n" // random delay if busy
+                  "li   $3,    1   			    \n"	// prepare argument for sc  
+                  "sc   $3,    0(%0)       	    \n" // try to set _ioc_busy
+                  "bnez $3,    _ioc_ok     	    \n" // exit if atomic 
+                  "_ioc_delay:				    \n"
+                  "move $4,    %1			    \n"	// $4 <= delay
+                  "_ioc_loop:				    \n"
+                  "addi $4,    $4,    -1	    \n"	// $4 <= $4 - 1
+                  "beqz $4,    _ioc_loop	    \n"	// test end delay
+                  "j           _ioc_llsc    	\n"	// retry
+                  "_ioc_ok:			            \n"
+                  ::"r"(plock),"r"(delay):"$2","$3","$4");
+}
+//////////////////////////////////////////////////////////////////////////////////////
+//  _ioc_write()
+// Transfer data from a memory buffer to a file on the block_device.
+// - lba    : first block index on the disk
+// - buffer : base address of the memory buffer
+// - count  : number of blocks to be transfered
+// The source buffer must be in user address space.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _ioc_write(size_t lba, void* buffer, size_t count)
+{
+    volatile unsigned int*    	ioc_address = (unsigned int*)&seg_ioc_base;
+
+    // buffer must be in user space
+//  size_t block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
+//  if( ( (size_t)buffer + block_size*count ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer                    ) >= 0x80000000 ) return -1;
+
+    // get the lock
+    _ioc_get_lock();
+
+    // block_device configuration
+    ioc_address[BLOCK_DEVICE_BUFFER] = (int)buffer;
+    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;
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _ioc_read()
+// Transfer data from a file on the block device to a memory buffer.
+// - lba    : first block index on the disk
+// - 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.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _ioc_read(size_t lba, void* buffer, size_t count)
+{
+    volatile unsigned int*    	ioc_address = (unsigned int*)&seg_ioc_base;
+
+    // buffer must be in user space
+//  size_t block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
+//  if( ( (size_t)buffer + block_size*count ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer                    ) >= 0x80000000 ) return -1;
+
+    // get the lock
+    _ioc_get_lock();
+
+    // block_device configuration
+    ioc_address[BLOCK_DEVICE_BUFFER] = (int)buffer;
+    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;
+
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _ioc_completed()
+// This blocking function cheks completion of an I/O transfer and reports errors.
+// It returns 0 if the transfer is successfully completed.
+// It returns -1 if an error has been reported.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _ioc_completed()
+{
+    // waiting for completion
+    while (_ioc_done == 0) { asm volatile("nop"); }
+    
+    // reset synchronisation variables
+    _ioc_done = 0;
+    _ioc_lock = 0;
+
+    // return errors
+    if((_ioc_status != BLOCK_DEVICE_READ_SUCCESS) &&
+            (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS))    return -1;
+    else                        				            return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//  FRAME_BUFFER
+// The _fb_sync_write & _fb_sync_read functions use a memcpy strategy to implement 
+// the transfer between a data buffer (user space) and the frame buffer (kernel space).
+// 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
+// - buffer : base address of the memory buffer
+// - length : number of bytes to be transfered
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int  _fb_sync_write(size_t offset, void* buffer, size_t length)
+{
+    volatile char*  fb = (char*)(void*)&seg_fb_base + offset;
+    char*       ub = buffer;
+    size_t      i;
+
+    // buffer must be in user space
+//  if( ( (size_t)buffer + length ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer          ) >= 0x80000000 ) return -1;
+
+    // memory copy
+    for(i=0 ; i<length ; i++) fb[i] = ub[i];
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _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
+// - buffer : base address of the memory buffer
+// - length : number of bytes to be transfered
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int  _fb_sync_read(size_t offset, void* buffer, size_t length)
+{
+    volatile char*  fb = (char*)(void*)&seg_fb_base + offset;
+    char*       ub = buffer;
+    size_t      i;
+
+    // buffer must be in user space
+//  if( ( (size_t)buffer + length ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer          ) >= 0x80000000 ) return -1;
+
+    // memory copy
+    for(i=0 ; i<length ; i++) ub[i] = fb[i];
+    return 0;
+}
+//////////////////////////////////////////////////////////////////////////////////////
+// The _fb_write() and _fb_read() functions use the MULTI_DMA
+// coprocessor to transfer data between the user buffer and the frame buffer.
+// The _fb_completed() function, use a polling policy to test
+// the global variables _dma_busy[i] and detect the transfer completion.
+// As each processor can have it's private DMA, there is up to 256 _dma_busy[i]
+// set/reset variables that are indexed by the proc_id.
+// The _dma_busy variable is reset by the ISR associated to the DMA IRQ.
+///////////////////////////////////////////////////////////////////////////////////////
+//  _fb_write()
+// Transfer data from an user buffer to the frame_buffer device using DMA.
+// - offset : offset (in bytes) in the frame buffer
+// - buffer : base address of the memory buffer
+// - length : number of bytes to be transfered
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int  _fb_write(size_t offset, void* buffer, size_t length)
+{
+    int*   		dma_address;
+    unsigned int    	base   		= (unsigned int)&seg_dma_base;
+    unsigned int    	increment	= _segment_increment(DMA_SPAN*4);
+    char*  		fb		= (char*)&seg_fb_base + offset;
+    unsigned int    	delay 		= (_proctime() & 0xF) << 4;
+    unsigned int	pid		= _procid();
+    unsigned int    	i;
+
+
+    // checking buffer boundaries (bytes)
+//  if( ( (size_t)buffer + length ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer          ) >= 0x80000000 ) return -1;
+
+    // waiting until DMA device is available
+    while (_dma_busy[pid] != 0)
+    {
+        for( i=0 ; i<delay ; i++)   // busy waiting
+        {                           // with a pseudo random
+            asm volatile("nop");    // delay between bus accesses
+        }
+    }
+    _dma_busy[pid] = 1;
+
+    dma_address = (int*)(base + increment);
+ 
+    // DMA configuration
+    dma_address[DMA_IRQ_DISABLE] = 0;
+    dma_address[DMA_SRC] 	= (int)buffer;
+    dma_address[DMA_DST] 	= (int)fb;
+    dma_address[DMA_LEN] 	= (int)length;
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _fb_read()
+// Transfer data from the frame_buffer device to an user buffer using DMA.
+// - offset     : offset (in bytes) in the frame buffer
+// - buffer : base address of the memory buffer
+// - length : number of bytes to be transfered
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int  _fb_read(size_t offset, void* buffer, size_t length)
+{
+    int*		dma_address;
+    unsigned int    	base		= (unsigned int)&seg_dma_base; 
+    unsigned int    	increment	= _segment_increment(DMA_SPAN*4);
+    char*  		fb    		= (char*)&seg_fb_base + offset;
+    unsigned int    	delay 		= (_proctime() & 0xF) << 4;
+    unsigned int	pid		= _procid();
+    unsigned int    	i;
+
+    // checking buffer boundaries (bytes)
+//  if( ( (size_t)buffer + length ) >= 0x80000000 ) return -1;
+//  if( ( (size_t)buffer          ) >= 0x80000000 ) return -1;
+
+    // waiting until DMA device is available
+    while (_dma_busy[pid] != 0)
+    {
+        for( i=0 ; i<delay ; i++)   // busy waiting
+        {                           // with a pseudo random
+            asm volatile("nop");    // delay between bus accesses
+        }
+    }
+    _dma_busy[pid] = 1;
+
+    dma_address = (int*)(base + increment);
+
+    // DMA configuration
+    dma_address[DMA_IRQ_DISABLE] = 0;
+    dma_address[DMA_SRC] 	= (int)fb;
+    dma_address[DMA_DST] 	= (int)buffer;
+    dma_address[DMA_LEN] 	= (int)length;
+    return 0;
+}
+///////////////////////////////////////////////////////////////////////////////////////
+//  _fb_completed()
+// This blocking function cheks completion of a DMA transfer to or fom the frame buffer.
+// The MIPS32 wait instruction stall the processor until the next interrupt.
+// It returns 0 if the transfer is successfully completed
+// It returns -1 if an error has been reported.
+///////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _fb_completed()
+{
+    unsigned int	pid = _procid();
+
+    while (_dma_busy[pid] != 0)
+    {
+        asm volatile("nop");
+    }
+    if(_dma_status[pid] == DMA_SUCCESS)  return 0;
+    else                                 return _dma_status[pid];
+}
+//////////////////////////////////////////////////////////////////////////////////////
+// _barrier_init()
+// This function makes a cooperative initialisation of the barrier:
+// Several tasks can try to initialize the barrier, but the initialisation 
+// is done by only one task, using LL/SC instructions.
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _barrier_init(unsigned int index, unsigned int value)
+{
+
+    register int* pinit 	= (int*)&_barrier_initial_value[index];
+    register int* pcount 	= (int*)&_barrier_count[index];
+
+    if ( index > 7 )	return 1;
+
+    // parallel initialisation using atomic instructions LL/SC
+    asm volatile ("_barrier_init_test:          	\n"
+                  "ll   $2,     0(%0)           	\n"	// read initial value
+                  "bnez $2,     _barrier_init_done	\n"
+                  "move $3,     %2			\n"
+                  "sc   $3,     0(%0)    	      	\n"	// try to write initial value
+                  "beqz $3,     _barrier_init_test	\n"
+                  "move $3,	%2			\n"
+                  "sw   $3,	0(%1)			\n"	// write count
+                  "_barrier_init_done:			\n"
+                  ::"r"(pinit),"r"(pcount),"r"(value):"$2","$3");
+    return 0 ;
+}
+//////////////////////////////////////////////////////////////////////////////////////
+// 	_barrier_wait()
+// This blocking function uses a busy_wait technics (on the counter value), 
+// because the GIET does not support dynamic scheduling/descheduling of tasks. 
+// In the busy waiting state, each task uses a pseudo-random delay between 
+// two successive read of the barrier counter in order to avoid bus saturation.
+// the average delay is about 1000 cycles.
+// There is at most 8 independant barriers, and an error is returned
+// if the barrier index is larger than 7.
+//////////////////////////////////////////////////////////////////////////////////////
+in_drivers int _barrier_wait(unsigned int index)
+{
+    register int* 	pcount 		= (int*)&_barrier_count[index];		
+    register int 	maxcount 	= _barrier_initial_value[index]; 
+    register int  	count;
+
+    if ( index > 7 )	return 1;
+
+    // parallel decrement barrier counter using atomic instructions LL/SC
+    // input : pointer on the barrier counter 
+    // output : counter value 
+    asm volatile ("_barrier_decrement:          		\n"
+                  "ll   %0,     0(%1)           		\n"
+                  "addi $3,     %0,     -1      		\n"
+                  "sc   $3,     0(%1)           		\n"
+                  "beqz $3,     _barrier_decrement		\n"
+                  :"=r"(count):"r"(pcount):"$2","$3");
+
+    // the last task re-initializes the barrier counter 
+    // to the max value, waking up all other waiting tasks
+
+    if ( count == 1 ) 	 // last task
+    {
+        *pcount = maxcount;
+        return 0;
+    }
+    else 		// other tasks
+    {
+        while ( *pcount != maxcount ) 	{ }	// busy waiting 
+        return 0 ;
+    }
+} 
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/drivers.h
===================================================================
--- /trunk/softs/giet_tsar/drivers.h	(revision 158)
+++ /trunk/softs/giet_tsar/drivers.h	(revision 158)
@@ -0,0 +1,108 @@
+/****************************************************************************************
+    File : drivers.h
+    Written by Alain Greiner & Nicolas Pouillon
+    Date : september 2009
+
+    These system calls are used by the MIPS GIET, that is running
+    on the MIPS32 processor architecture.
+
+    The supported peripherals are:
+    - the SoClib vci_multi_tty
+    - the SocLib vci_multi_timer
+    - the SocLib vci_dma
+    - The SoCLib vci_icu
+    - The SoCLib vci_gcd
+    - The SoCLib vci_frame_buffer
+    - The SoCLib vci_block_device
+****************************************************************************************/
+
+#ifndef _DRIVERS_H_
+#define _DRIVERS_H_
+
+#include "tty.h"
+#include "dma.h"
+#include "gcd.h"
+#include "timer.h"
+#include "icu.h"
+#include "block_device.h"
+
+typedef unsigned int    size_t;
+
+// global variables defined in giet.s
+
+extern  unsigned int    _task_context_array[];
+extern  unsigned int    _current_task_array[];
+extern  unsigned int    _task_number_array[];
+
+// function defined in giet.s
+
+void _ctx_switch();
+
+// global variables defined in drivers.c
+
+extern  int volatile	_dma_status[];
+extern  int volatile	_dma_busy[];
+
+extern  int volatile	_ioc_lock;
+extern  int volatile	_ioc_done;
+extern  int volatile	_ioc_status;
+
+extern  char volatile	_tty_get_buf[];
+extern  int volatile	_tty_get_full[];
+
+extern  char volatile	_tty_put_buf[];
+extern  int volatile	_tty_put_full[];
+
+// functions defined in drivers.c
+
+unsigned int 	_procid();
+unsigned int 	_proctime();
+unsigned int 	_procnumber();
+
+unsigned int 	_segment_increment();
+
+void _itoa_dec(unsigned int val, char* buf);
+void _itoa_hex(int val, char* buf);
+
+int _exit();
+
+int _timer_write(size_t timer_index, size_t register_index, int value);
+int _timer_read(size_t timer_index, size_t register_index, int* buffer);
+
+int _tty_write(char* buffer, int length);
+int _tty_read(char* buffer, int length);
+
+int _io_write(size_t lba, void* buffer, size_t count);
+int _io_read(size_t lba, void* buffer, size_t count);
+int _io_completed();
+
+int _icu_write(size_t register_index, int  value);
+int _icu_read(size_t register_index, int*  buffer);
+
+int _gcd_write(size_t register_index, int  value);
+int _gcd_read(size_t register_index, int*  buffer);
+
+int _locks_write(size_t lock_index);
+int _locks_read(size_t lock_index);
+
+int _fb_sync_write(size_t offset, void* buffer, size_t length);
+int _fb_sync_read(size_t offset, void* buffer, size_t length);
+
+int _fb_write(size_t offset, void* buffer, size_t length);
+int _fb_read(size_t offset, void* buffer, size_t length);
+int _fb_completed();
+
+int _barrier_init(size_t index, size_t count);
+int _barrier_wait(size_t index);
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/gcd.h
===================================================================
--- /trunk/softs/giet_tsar/gcd.h	(revision 158)
+++ /trunk/softs/giet_tsar/gcd.h	(revision 158)
@@ -0,0 +1,23 @@
+#ifndef GCD_REGS_H
+#define GCD_REGS_H
+
+enum SoclibLcdRegisters {
+    GCD_OPA = 0,
+    GCD_OPB = 1,
+    GCD_START  = 2,
+    GCD_STATUS = 3,
+    /**/
+    GCD_SPAN  = 4,
+};
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/giet.s
===================================================================
--- /trunk/softs/giet_tsar/giet.s	(revision 158)
+++ /trunk/softs/giet_tsar/giet.s	(revision 158)
@@ -0,0 +1,726 @@
+/*********************************************************************************
+*    File : giet.s
+*    Author : Franck Wajsburt & Alain Greiner & Joel Porquet
+*    Date : 2009 - 2010
+**********************************************************************************
+*    Interruption/Exception/Trap Handler for MIPS32 processor
+*    The base address of the segment containing this code
+*    MUST be 0x80000000, in order to have the entry point
+*    at address 0x80000180 !!!
+*    All messages are printed on the TTY defined by the processor ID.
+**********************************************************************************
+*    History :
+*    15/09/2009 : The GIET entry point has been modified to comply with
+*        the MIPS32 specification : 0x80000180
+*    5/10/2009  : The syscall handler has been modified to comply with the
+*        MIPS32 specification : the value stored in EPC register is the
+*        syscall instruction address => it must be incremented by 4
+*        to obtain the return address.
+*    15/10/2009 : The Interrupt handler has been modified to comply with the
+*        VCI_ICU specification : The IRQ index is obtained by a read
+*        to (icu_base_address + 16).
+*    26/10/2009 : The interrupt handler has been modified to support
+*        multi-processors architectures with one ICU per processor.
+*        Finally, the mfc0 instruction uses now the select parameter
+*        to comply with the MIPS32 specification when accessing the
+*        processor_id (mtfc0 $x, $15, 1)
+*    08/11/2009 : The syscall handler has been extended to support 32 values
+*        for the syscall index, and to enable interrupts when processing
+*        a system call.
+*        Five new syscalls have been introduced to access the frame buffer
+*        Three new syscalls have been introduced to access the block device
+*        The two syscalls associated to the DMA have been removed.
+*    18/11/2009 : The syscall handler has been modified to save the SR in
+*        the stack before enabling interrupts.
+*    15/03/2010 : replace the itoa_print assembler function by the itoa_hex()
+*        function defined in the syscalls.c file.
+*    10/04/2010 : modify the interrupt handler to use the new ICU component
+*        supporting up to 8 output IRQs for 8 processors.
+*        The active IRQ index is obtained as ICU[32*PROC_ID+16].
+*    12/09/2010 : The ctx_switch functionhas been included in this file to
+*        simplify the compilation process.
+*   25/09/2010 : add '.end' directive to end the _giet function
+*        and modify the 'sharp' comment character into the regular "slash
+*        asterix ... asterix slash" comment syntax
+*   27/09/2010 : respect stack convention with 4 minimum slots before calling
+*        C functions
+*   28/09/2010 : Save all the non-persistant registers in the int_handler
+*   02/02/2011 : Introduce the "segment_increment" parameter in the interrupt
+*        handler to support clusterised multi-processing.
+*        Introducing the barrier_init() & barrier_wait() system calls.
+*   04/04/2011 : introducing the system call proc_num() 
+*   12/04/2011 : modifying the _int_handler to support the XICU component in
+*        multi_clusters/multi-processors architectures:
+*        the XICU base address depends the cluster_id and the PRIO register
+*        address depends on the local_id.
+**********************************************************************************/
+
+    .section .giet,"ax",@progbits
+    .align 2
+    .global _interrupt_vector    # makes interrupt_vector an external symbol 
+
+    .extern seg_icu_base
+    .extern seg_tty_base
+    .extern NB_CLUSTERS
+    .extern NB_PROCS
+
+    .extern isr_default
+
+    .extern _procid
+    .extern _proctime
+    .extern _tty_write
+    .extern _tty_read
+    .extern _tty_read_irq
+    .extern _timer_write
+    .extern _timer_read
+    .extern _icu_write
+    .extern _icu_read
+    .extern _gcd_write
+    .extern _gcd_read
+    .extern _locks_read
+    .extern _locks_write
+    .extern _exit
+    .extern _fb_sync_write
+    .extern _fb_sync_read
+    .extern _fb_write
+    .extern _fb_read
+    .extern _fb_completed
+    .extern _ioc_write
+    .extern _ioc_read
+    .extern _ioc_completed
+    .extern _itoa_hex
+    .extern _barrier_init
+    .extern _barrier_wait
+
+    .ent _giet
+
+/***************************************************************
+*    Cause Table (indexed by the Cause register)
+***************************************************************/
+tab_causes:
+    .word _int_handler  # 0000 : external interrupt 
+    .word _cause_ukn    # 0001 : undefined exception 
+    .word _cause_ukn    # 0010 : undefined exception 
+    .word _cause_ukn    # 0011 : undefined exception 
+    .word _cause_adel   # 0100 : illegal address read exception 
+    .word _cause_ades   # 0101 : illegal address write exception 
+    .word _cause_ibe    # 0110 : instruction bus error exception 
+    .word _cause_dbe    # 0111 : data bus error exception 
+    .word _sys_handler  # 1000 : system call 
+    .word _cause_bp     # 1001 : breakpoint exception 
+    .word _cause_ri     # 1010 : illegal codop exception 
+    .word _cause_cpu    # 1011 : illegal coprocessor access 
+    .word _cause_ovf    # 1100 : arithmetic overflow exception 
+    .word _cause_ukn    # 1101 : undefined exception 
+    .word _cause_ukn    # 1110 : undefined exception 
+    .word _cause_ukn    # 1111 : undefined exception 
+
+    .space 320
+
+/***************************************************************
+*    Entry point (at address 0x80000180)
+***************************************************************/
+_giet:
+    mfc0    $27,    $13             # Cause Register analysis 
+    lui     $26,    0x8000          # $26 <= tab_causes 
+    andi    $27,    $27,    0x3c
+    addu    $26,    $26,    $27
+    lw      $26,    ($26)
+    jr      $26                     # Jump indexed by CR 
+    .end _giet
+
+/****************************************************************
+*   System Call Handler
+* A system call is handled as a special function call.
+*   - $2 contains the system call index (< 16).
+*   - $3 is used to store the syscall address
+*   - $4, $5, $6, $7 contain the arguments values.
+*   - The return address (EPC) iand the SR are saved in the stack.
+*   - Interrupts are enabled before branching to the syscall.
+*   - All syscalls must return to the syscall handler.
+*   - $2, $3, $4, $5, $6, $7 as well as $26 & $27 can be modified.
+*
+* In case of undefined system call, an error message displays
+* the value of EPC on the TTY corresponding to the processor,
+* and the user program is killed.
+****************************************************************/
+_sys_handler:
+    addiu   $29,    $29,    -24     # 2 slots for SR&EPC, 4 slots for args passing 
+    mfc0    $26,    $12             # load SR 
+    sw      $26,    16($29)         # save it in the stack 
+    mfc0    $27,    $14             # load EPC 
+    addiu   $27,    $27,    4       # increment EPC for return address 
+    sw      $27,    20($29)         # save it in the stack 
+
+    andi    $26,    $2,     0x1F    # $26 <= syscall index (i < 32) 
+    sll     $26,    $26,    2       # $26 <= index * 4 
+    la      $27,    tab_syscalls    # $27 <= &tab_syscalls[0] 
+    addu    $27,    $27,    $26     # $27 <= &tab_syscalls[i] 
+    lw      $3,     0($27)          # $3  <= syscall address 
+
+    li      $27,    0xFFFFFFED      # Mask for UM & EXL bits 
+    mfc0    $26,    $12             # $26 <= SR 
+    and     $26,    $26,    $27     # UM = 0 / EXL = 0 
+    mtc0    $26,    $12             # interrupt enabled 
+    jalr    $3                      # jump to the proper syscall 
+    mtc0    $0,     $12             # interrupt disbled 
+
+    lw      $26,    16($29)         # load SR from stack 
+    mtc0    $26,    $12             # restore SR 
+    lw      $26,    20($29)         # load EPC from stack 
+    mtc0    $26,    $14             # restore EPC 
+    addiu   $29,    $29,     24     # restore stack pointer 
+    eret                            # exit GIET 
+
+_sys_ukn:                           # undefined system call 
+    la      $4,     msg_uknsyscall  # $4 <= message address 
+    li      $5,    36               # $5 <= message length 
+    jal     _tty_write              # print unknown message 
+
+    la      $4,     msg_epc         # $4 <= message address 
+    li      $5,    8                # $5 <= message length 
+    jal     _tty_write              # print EPC message 
+
+    mfc0    $4,     $14             # $4 <= EPC 
+    la      $5,     itoa_buffer     # $5 <= buffer address 
+    addiu   $5,     $5,     2       # skip the 0x prefix 
+    jal     _itoa_hex               # fill the buffer 
+
+    la      $4,     itoa_buffer     # $4 <= buffer address 
+    li      $5,     10              # $5 <= buffer length 
+    jal     _tty_write              # print EPC value 
+
+    j       _exit                   # end of program 
+
+itoa_buffer: .ascii "0x00000000"
+
+    .align 2
+
+/****************************************************************
+* System Call Table (indexed by syscall index) 
+****************************************************************/
+tab_syscalls:
+    .word _procid           # 0x00 
+    .word _proctime         # 0x01 
+    .word _tty_write        # 0x02 
+    .word _tty_read         # 0x03 
+    .word _timer_write      # 0x04 
+    .word _timer_read       # 0x05 
+    .word _gcd_write        # 0x06 
+    .word _gcd_read         # 0x07 
+    .word _icu_write        # 0x08 
+    .word _icu_read         # 0x09 
+    .word _tty_read_irq     # 0x0A 
+    .word _sys_ukn          # 0x0B 
+    .word _locks_write      # 0x0C 
+    .word _locks_read       # 0x0D 
+    .word _exit             # 0x0E 
+    .word _procnumber       # 0x0F 
+    .word _fb_sync_write    # 0x10 
+    .word _fb_sync_read     # 0x11 
+    .word _fb_write         # 0x12 
+    .word _fb_read          # 0x13 
+    .word _fb_completed     # 0x14 
+    .word _ioc_write        # 0x15 
+    .word _ioc_read         # 0x16 
+    .word _ioc_completed    # 0x17 
+    .word _barrier_init     # 0x18 
+    .word _barrier_wait     # 0x19 
+    .word _sys_ukn          # 0x1A 
+    .word _sys_ukn          # 0x1B 
+    .word _sys_ukn          # 0x1C 
+    .word _sys_ukn          # 0x1D 
+    .word _sys_ukn          # 0x1E 
+    .word _sys_ukn          # 0x1F 
+
+/******************************************************************
+*    Interrupt Handler
+* This simple interrupt handler cannot be interrupted.
+* It uses an external ICU component (Interrupt Controler Unit)
+* that concentrates up to 32 interrupts lines to a single IRQ
+* line that can be connected to any of the 6 MIPS IT inputs.
+* This component returns the highest priority active interrupt index
+* (smaller indexes have the highest priority).
+*
+* In case of a multi-clusters architecture, it exist one ICU 
+* per cluster. The base address of the ICU segment depends on both
+* the cluster_id and the proc_id:
+* - icu_base_address = seg_icu_base + (32 * local_id) +
+*                    (cluster_increment * cluster _id)
+* - cluster_id = proc_id / NB_PROCS 
+* - local_id = proc_id % NB_PROCS
+* - cluster_increment = 4G / NB_CLUSTERS
+*
+* The interrupt handler reads the XICU PRIO register,
+* using the offset 16.
+* This component returns the highest priority interrupt index
+* (smaller indexes have the highest priority).
+* Any value larger than 31 means "no active interrupt", and
+* the default ISR (that does nothing) is executed.
+* The interrupt vector (32 ISR addresses array stored at
+* _interrupt_vector address) is initialised with the default
+* ISR address. The actual ISR addresses are supposed to be written
+* in the interrupt vector array by the boot code.
+* All non persistant registers, such as $1 to $15, and $24 to $25,
+* as well as register $31 and EPC, are saved in the interrupted
+* program stack, before calling the Interrupt Service Routine.
+* These registers can be used by the ISR code.
+*******************************************************************/
+_int_handler:
+    addiu   $29,    $29,    -23*4   # stack space reservation 
+    .set noat
+    sw      $1,     4*4($29)        # save $1 
+    .set at
+    sw      $2,     4*5($29)        # save $2 
+    sw      $3,     4*6($29)        # save $3 
+    sw      $4,     4*7($29)        # save $4 
+    sw      $5,     4*8($29)        # save $5 
+    sw      $6,     4*9($29)        # save $6 
+    sw      $7,     4*10($29)       # save $7 
+    sw      $8,     4*11($29)       # save $8 
+    sw      $9,     4*12($29)       # save $9 
+    sw      $10,    4*13($29)       # save $10 
+    sw      $11,    4*14($29)       # save $11 
+    sw      $12,    4*15($29)       # save $12 
+    sw      $13,    4*16($29)       # save $13 
+    sw      $14,    4*17($29)       # save $14 
+    sw      $15,    4*18($29)       # save $15 
+    sw      $24,    4*19($29)       # save $24 
+    sw      $25,    4*20($29)       # save $25 
+    sw      $31,    4*21($29)       # save $31 
+    mfc0    $27,    $14
+    sw      $27,    4*22($29)       # save EPC 
+
+    # XICU PRIO register address computation (depending on cluster_id & local_id)
+    mfc0    $10,    $15,    1       # $10 <= proc_id 
+    andi    $10,    $10,    0x3FF   # at most 1024 processors 
+    la      $11,    NB_PROCS        # $11 <= NB_PROCS 
+    divu    $10,    $11
+    mflo    $12                     # $12 <= cluster_id 
+    mfhi    $13                     # $13 <= local_id 
+    la      $11,    NB_CLUSTERS     # $11 <= NB_CLUSTERS 
+    li      $14,    0x80000000	    
+    divu    $14,    $11
+    mflo    $15	
+    sll     $15,    $15,    1       # $15 <= cluster_increment = 4G / NB_CLUSTERS 
+    multu   $15,    $12
+    mflo    $6	                    # $6 <= cluster_increment * cluster_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_icu_base    
+    addu    $26,    $9,     $27     # $26 <= seg_icu_base + PRIO offset + local_id*4 
+    addu    $26,    $26,    $6      # $26 <= seg_icu_base + increment*cluster_id + PRIO offset + local_id*4 
+
+    # XICU access and interrupt vector access
+    lw      $26,    ($26)           # $26 <= PRIO register value 
+    andi    $27,    $26,    0x2     # test bit HWI active
+    beq     $27,    $0,     restore # do nothing if no active IRQ 
+    srl     $26,    $26,    14      # $26 <= $26 >> 14 
+    andi    $26,    $26,    0x7C    # $26 <= interrupt_index * 4 
+    la      $27,    _interrupt_vector
+    addu    $26,    $26,    $27
+    lw      $26,    ($26)           # read ISR address 
+    jalr    $26                     # call ISR 
+restore:
+    .set noat
+    lw      $1,     4*4($29)        # restore $1 
+    .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      $27,    4*22($29)       # return address (EPC) 
+    addiu   $29,    $29,    23*4    # restore stack pointer 
+    mtc0    $27,    $14             # restore EPC 
+    eret                            # exit GIET 
+
+/* The default ISR is called when no specific ISR has been installed in the
+ interrupt vector. It simply displays a message on TTY 0. */
+
+isr_default:
+    addiu   $29,    $29,    -20     # get space in stack 
+    sw      $31,    16($29)         # to save the return address 
+    la      $4,     msg_default     # $4 <= string address 
+    addi    $5,     $0,     36      # $5 <= string length 
+    jal     _tty_write              # print 
+    lw      $31,    16($29)         # restore return address 
+    addiu   $29,    $29,    20      # free space 
+    jr      $31                     # returns to interrupt handler 
+
+/*****************************************************
+ Interrupt Vector Table (indexed by interrupt index)
+  32 words corresponding to 32 ISR addresses 
+******************************************************/
+_interrupt_vector:
+    .word isr_default   # ISR 0 
+    .word isr_default   # ISR 1 
+    .word isr_default   # ISR 2 
+    .word isr_default   # ISR 3 
+    .word isr_default   # ISR 4 
+    .word isr_default   # ISR 5 
+    .word isr_default   # ISR 6 
+    .word isr_default   # ISR 7 
+    .word isr_default   # ISR 8 
+    .word isr_default   # ISR 9 
+    .word isr_default   # ISR 10 
+    .word isr_default   # ISR 11 
+    .word isr_default   # ISR 12 
+    .word isr_default   # ISR 13 
+    .word isr_default   # ISR 14 
+    .word isr_default   # ISR 15 
+    .word isr_default   # ISR 16 
+    .word isr_default   # ISR 17 
+    .word isr_default   # ISR 18 
+    .word isr_default   # ISR 19 
+    .word isr_default   # ISR 20 
+    .word isr_default   # ISR 21 
+    .word isr_default   # ISR 22 
+    .word isr_default   # ISR 23 
+    .word isr_default   # ISR 24 
+    .word isr_default   # ISR 25 
+    .word isr_default   # ISR 26 
+    .word isr_default   # ISR 27 
+    .word isr_default   # ISR 28 
+    .word isr_default   # ISR 29 
+    .word isr_default   # ISR 30 
+    .word isr_default   # ISR 31 
+
+/***********************************************************
+*    Exception Handler
+* Same code for all fatal exceptions :
+* Print the exception type and the values of EPC & BAR
+* on the TTY correspondintg to the processor PROCID,
+* and the user program is killed.
+***********************************************************/
+_cause_bp:
+_cause_ukn:
+_cause_ri:
+_cause_ovf:
+_cause_adel:
+_cause_ades:
+_cause_ibe:
+_cause_dbe:
+_cause_cpu:
+    mfc0    $26,    $13             # $26 <= CR 
+    andi    $26,    $26,    0x3C    # $26 <= _cause_index * 4 
+    la      $27,    mess_causes     # mess_cause table base address 
+    addu    $27,    $26,    $27     # pointer on the message base address 
+
+    lw      $4,     ($27)           # $4 <= message address 
+    li      $5,     36              # $5 <= message length 
+    jal     _tty_write              # print message cause 
+
+    la      $4,     msg_epc         # $4 <= message address 
+    li      $5,     8               # $5 <= message length 
+    jal     _tty_write              # print message EPC 
+
+    mfc0    $4,     $14             # $4 <= EPC value 
+    la      $5,     itoa_buffer     # $5 <= buffer address 
+    addiu   $5,     $5,     2       # skip 0x prefix 
+    jal     _itoa_hex               # fill buffer 
+
+    la      $4,     itoa_buffer     # $4 <= buffer address 
+    li      $5,     10              # $5 <= buffer length 
+    jal     _tty_write              # print EPC value 
+
+    la      $4,     msg_bar         # $4 <= mesage address 
+    li      $5,     8               # $5 <= message length 
+    jal     _tty_write              # print message BAR 
+
+    mfc0    $4,     $8              # $4 <= BAR value 
+    la      $5,     itoa_buffer     # $5 <= buffer address 
+    addiu   $5,     $5,     2       # skip 0x prefix 
+    jal     _itoa_hex               # fill buffer 
+
+    la      $4,     itoa_buffer     # $4 <= mesage address 
+    li      $5,     10              # $5 <= message length 
+    jal     _tty_write              # print BAR value 
+
+    j       _exit                   # end program 
+
+# Exceptions Messages table (indexed by CAUSE)  
+mess_causes:
+    .word msg_ukncause
+    .word msg_ukncause
+    .word msg_ukncause
+    .word msg_ukncause
+    .word msg_adel
+    .word msg_ades
+    .word msg_ibe
+    .word msg_dbe
+    .word msg_ukncause
+    .word msg_bp
+    .word msg_ri
+    .word msg_cpu
+    .word msg_ovf
+    .word msg_ukncause
+    .word msg_ukncause
+    .word msg_ukncause
+
+/*****************************************************************
+*    All messages
+* Messages length are fixed : 8 or 36 characters...
+*****************************************************************/
+msg_bar:        .asciiz "\nBAR  = "
+msg_epc:        .asciiz "\nEPC  = "
+msg_default:    .asciiz "\n\n  !!! Default ISR  !!!           \n"
+msg_uknsyscall: .asciiz "\n\n  !!! Undefined System Call !!!  \n"
+msg_ukncause:   .asciiz "\n\nException : strange unknown cause\n"
+msg_adel:       .asciiz "\n\nException : illegal read address \n"
+msg_ades:       .asciiz "\n\nException : illegal write address\n"
+msg_ibe:        .asciiz "\n\nException : inst bus error       \n"
+msg_dbe:        .asciiz "\n\nException : data bus error       \n"
+msg_bp:         .asciiz "\n\nException : breakpoint           \n"
+msg_ri:         .asciiz "\n\nException : reserved instruction \n"
+msg_ovf:        .asciiz "\n\nException : arithmetic overflow  \n"
+msg_cpu:        .asciiz "\n\nException : illegal coproc access\n"
+    .align 2
+
+
+/***************************************************************************
+*        _ctx_switch
+*   The _ctx_switch function performs a context switch between the
+*   current task and another task.
+*   It can be used in a multi-processor architecture, with the assumption
+*   that the tasks are statically allocated to processors.
+*   The max number of processorsi is 8, and the max number of tasks is 4.
+*   The scheduling policy is very simple : For each processor, the task index
+*   is incremented,  modulo the number of tasks allocated to the processor.
+*
+*   It has no argument, and no return value.
+*
+*   It uses three global variables:
+*    - _current_task_array :  an array of 8 task index:
+*      (index of the task actually running on each processor)
+*    - _task_number_array : an array of 8 numbers:
+*      (the number of tasks allocated to each processor)
+*       - _task_context_array : an array of 32 task contexts:
+*      (at most 8 processors / each processor can run up to 4 tasks)
+*   A task context is an array of 64 words = 256 bytes.
+*   It is indexed by m = (proc_id*4 + task_id)
+*   It contains copies of the processor registers.
+*   As much as possible a register is stored at the index defined by its number
+*   ( for example, $8 is saved in ctx[8]).
+*   The exception are :
+*   $0 is not saved since always 0
+*   $26, $27 are not saved since not used by the task
+*
+*   0*4(ctx) SR    8*4(ctx) $8    16*4(ctx) $16   24*4(ctx) $24   32*4(ctx) EPC
+*   1*4(ctx) $1    9*4(ctx) $9    17*4(ctx) $17   25*4(ctx) $25   33*4(ctx) CR
+*   2*4(ctx) $2   10*4(ctx) $10   18*4(ctx) $18   26*4(ctx) LO    34*4(ctx) reserved
+*   3*4(ctx) $3   11*4(ctx) $11   19*4(ctx) $19   27*4(ctx) HI    35*4(ctx) reserved
+*   4*4(ctx) $4   12*4(ctx) $12   20*4(ctx) $20   28*4(ctx) $28   36*4(ctx) reserved
+*   5*4(ctx) $5   13*4(ctx) $13   21*4(ctx) $21   29*4(ctx) $29   37*4(ctx) reserved
+*   6*4(ctx) $6   14*4(ctx) $14   22*4(ctx) $22   30*4(ctx) $30   38*4(ctx) reserved
+*   7*4(ctx) $7   15*4(ctx) $15   23*4(ctx) $23   31*4(ctx) $31   39*4(ctx) reserved
+*
+*   The return address contained in $31 is saved in the _current task context
+*   (in the ctx[31] slot), and the function actually returns to the address contained
+*   in the ctx[31] slot of the new task context.
+*
+*   Caution : This function is intended to be used with periodic interrupts.
+*   It can be directly called by the OS, but interrupts must be disabled before calling.
+***************************************************************************************/
+
+    .section .ksave
+
+    .global _task_context_array # initialised in reset.s 
+    .global _current_task_array # initialised in reset.s 
+    .global _task_number_array  # initialised in reset.s 
+
+_task_context_array:    # 32 contexts : indexed by (proc_id*4 + task_id) 
+    .space  8192
+
+_current_task_array:    # 8 words : indexed by the proc_id 
+    .word   0           # _current_task_array[0] <= 0 
+    .word   0           # _current_task_array[1] <= 0 
+    .word   0           # _current_task_array[2] <= 0 
+    .word   0           # _current_task_array[3] <= 0 
+    .word   0           # _current_task_array[4] <= 0 
+    .word   0           # _current_task_array[5] <= 0 
+    .word   0           # _current_task_array[6] <= 0 
+    .word   0           # _current_task_array[7] <= 0 
+
+_task_number_array:     # 8 words : indexed by the proc_id 
+    .word   1           # _task_number_array[0] <= 1 
+    .word   1           # _task_number_array[1] <= 1 
+    .word   1           # _task_number_array[2] <= 1 
+    .word   1           # _task_number_array[3] <= 1 
+    .word   1           # _task_number_array[4] <= 1 
+    .word   1           # _task_number_array[5] <= 1 
+    .word   1           # _task_number_array[6] <= 1 
+    .word   1           # _task_number_array[7] <= 1 
+
+/***************************************************************************************/
+
+    .section .switch
+
+    .global _ctx_switch # makes it an external symbol 
+    .align  2
+
+_ctx_switch:
+
+    # test if more than one task on the processor 
+
+    mfc0    $26,    $15,    1
+    andi    $26,    $26,    0x7         # $26 <= proc_id 
+    sll     $26,    $26,    2           # $26 <= 4*proc_id 
+    la      $27,    _task_number_array  # $27 <= base address of _task_number_array 
+    addu    $27,    $27,    $26         # $27 <= _task_number_array + 4*proc_id 
+    lw      $27,    ($27)               # $27 <= task number 
+    addi    $26,    $27,    -1          # $26 <= _task_number - 1 
+    bnez    $26,    do_it               # 0 if only one task 
+    jr      $31                         # return 
+
+    # save _current task context 
+
+do_it:
+    mfc0    $26,    $15,    1
+    andi    $26,    $26,    0x7         # $26 <= proc_id 
+    sll     $26,    $26,    2           # $26 <= 4*proc_id 
+    la      $27,    _current_task_array # $27 <= base address of _current_task_array 
+    addu    $27,    $27,    $26         # $27 <= _current_task_array + 4*proc_id 
+    lw      $26,    ($27)               # $26 <= current task index 
+    sll     $26,    $26,    8           # $26 <= 256*task_id 
+    la      $27,    _task_context_array # $27 <= base address of context array 
+    addu    $27,    $27,    $26         # $27 <= _task_context_array + 256*task_id 
+    mfc0    $26,    $15,    1
+    andi    $26,    $26,    0x7         # $26 <= proc_id 
+    sll     $26,    $26,    10          # $26 <= 1024*proc_id 
+    addu    $27,    $27,    $26         # $27 <= taxk_context_array + 256*(proc_id*4 + task_id) 
+
+    mfc0    $26,    $12         # $26 <= SR 
+    sw      $26,    0*4($27)    # ctx[0] <= SR 
+    .set noat
+    sw      $1,     1*4($27)    # ctx[1] <= $1 
+    .set at
+    sw      $2,     2*4($27)    # ctx[2] <= $2 
+    sw      $3,     3*4($27)    # ctx[3] <= $3 
+    sw      $4,     4*4($27)    # ctx[4] <= $4 
+    sw      $5,     5*4($27)    # ctx[5] <= $5 
+    sw      $6,     6*4($27)    # ctx[6] <= $6 
+    sw      $7,     7*4($27)    # ctx[7] <= $7 
+    sw      $8,     8*4($27)    # ctx[8] <= $8 
+    sw      $9,     9*4($27)    # ctx[9] <= $9 
+    sw      $10,    10*4($27)   # ctx[10] <= $10 
+    sw      $11,    11*4($27)   # ctx[11] <= $11 
+    sw      $12,    12*4($27)   # ctx[12] <= $12 
+    sw      $13,    13*4($27)   # ctx[13] <= $13 
+    sw      $14,    14*4($27)   # ctx[14] <= $14 
+    sw      $15,    15*4($27)   # ctx[15] <= $15 
+    sw      $16,    16*4($27)   # ctx[16] <= $16 
+    sw      $17,    17*4($27)   # ctx[17] <= $17 
+    sw      $18,    18*4($27)   # ctx[18] <= $18 
+    sw      $19,    19*4($27)   # ctx[19] <= $19 
+    sw      $20,    20*4($27)   # ctx[20] <= $20 
+    sw      $21,    21*4($27)   # ctx[21] <= $21 
+    sw      $22,    22*4($27)   # ctx[22] <= $22 
+    sw      $23,    23*4($27)   # ctx[23] <= $23 
+    sw      $24,    24*4($27)   # ctx[24] <= $24 
+    sw      $25,    25*4($27)   # ctx[25] <= $25 
+    mflo    $26
+    sw      $26,    26*4($27)   # ctx[26] <= LO 
+    mfhi    $26
+    sw      $26,    27*4($27)   # ctx[27] <= H1 
+    sw      $28,    28*4($27)   # ctx[28] <= $28 
+    sw      $29,    29*4($27)   # ctx[29] <= $29 
+    sw      $30,    30*4($27)   # ctx[30] <= $30 
+    sw      $31,    31*4($27)   # ctx[31] <= $31 
+    mfc0    $26,    $14
+    sw      $26,    32*4($27)   # ctx[32] <= EPC 
+    mfc0    $26,    $13
+    sw      $26,    33*4($27)   # ctx[33] <= CR 
+
+    # select  the new task 
+
+    mfc0    $15,    $15,    1
+    andi    $15,    $15,    0x7         # $15 <= proc_id 
+    sll     $16,    $15,    2           # $16 <= 4*proc_id 
+    la      $17,    _current_task_array # $17 <= base address of _current_task_array 
+    addu    $17,    $17,    $16         # $17 <= _current_task_array + 4*proc_id 
+    lw      $18,    ($17)               # $18 <= _current task index 
+    la      $19,    _task_number_array  # $19 <= base address of _task_number_array 
+    addu    $19,    $19,    $16         # $19 <= _task_number_array + 4*proc_id 
+    lw      $20,    ($19)               # $20 <= max = number of tasks 
+    addiu   $18,    $18,    1           # $18 <= new task index 
+    sub     $2,     $18,    $20         # test modulo max 
+    bne     $2,     $0,     no_wrap
+    add     $18,    $0,     $0          # $18 <= new task index 
+no_wrap:
+    sw      $18,    ($17)               # update _current_task_array 
+
+    # restore next task context 
+
+    sll     $19,    $18,    8           # $19 <= 256*task_id 
+    la      $27,    _task_context_array # $27 <= base address of context array 
+    addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*task_id 
+    sll     $19,    $15,    10          # $19 <= 1024*proc_id 
+    addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*(proc_id*4 + task_id) 
+
+    lw      $26,    0*4($27)
+    mtc0    $26,    $12                 # restore SR 
+    .set noat
+    lw      $1,     1*4($27)            # restore $1 
+    .set at
+    lw      $2,     2*4($27)            # restore $2 
+    lw      $3,     3*4($27)            # restore $3 
+    lw      $4,     4*4($27)            # restore $4 
+    lw      $5,     5*4($27)            # restore $5 
+    lw      $6,     6*4($27)            # restore $6 
+    lw      $7,     7*4($27)            # restore $7 
+    lw      $8,     8*4($27)            # restore $8 
+    lw      $9,     9*4($27)            # restore $9 
+    lw      $10,    10*4($27)           # restore $10 
+    lw      $11,    11*4($27)           # restore $11 
+    lw      $12,    12*4($27)           # restore $12 
+    lw      $13,    13*4($27)           # restore $13 
+    lw      $14,    14*4($27)           # restore $14 
+    lw      $15,    15*4($27)           # restore $15 
+    lw      $16,    16*4($27)           # restore $16 
+    lw      $17,    17*4($27)           # restore $17 
+    lw      $18,    18*4($27)           # restore $18 
+    lw      $19,    19*4($27)           # restore $19 
+    lw      $20,    20*4($27)           # restore $20 
+    lw      $21,    21*4($27)           # restore $21 
+    lw      $22,    22*4($27)           # restore $22 
+    lw      $23,    23*4($27)           # restore $23 
+    lw      $24,    24*4($27)           # restore $24 
+    lw      $25,    25*4($27)           # restore $25 
+    lw      $26,    26*4($27)
+    mtlo    $26                         # restore LO 
+    lw      $26,    27*4($27)
+    mthi    $26                         # restore HI 
+    lw      $28,    28*4($27)           # restore $28 
+    lw      $29,    29*4($27)           # restore $29 
+    lw      $30,    30*4($27)           # restore $30 
+    lw      $31,    31*4($27)           # restore $31 
+    lw      $26,    32*4($27)
+    mtc0    $26,    $14                 # restore EPC 
+    lw      $26,    33*4($27)
+    mtc0    $26,    $13                 # restore CR 
+
+    jr      $31                         # returns to caller 
+
+/* Local Variables:
+   tab-width: 4;
+   c-basic-offset: 4;
+   c-file-offsets:((innamespace . 0)(inline-open . 0));
+   indent-tabs-mode: nil;
+   End: */
+
+/* vim: set filetype=asm expandtab shiftwidth=4 tabstop=4 softtabstop=4: */
+
Index: /trunk/softs/giet_tsar/icu.h
===================================================================
--- /trunk/softs/giet_tsar/icu.h	(revision 158)
+++ /trunk/softs/giet_tsar/icu.h	(revision 158)
@@ -0,0 +1,24 @@
+#ifndef ICU_REGS_H
+#define ICU_REGS_H
+
+enum SoclibPicRegisters {
+    ICU_INT = 0,
+    ICU_MASK = 1,
+    ICU_MASK_SET = 2,
+    ICU_MASK_CLEAR = 3,
+    ICU_IT_VECTOR = 4,
+    /***/
+    ICU_SPAN = 8,
+};
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/isr.c
===================================================================
--- /trunk/softs/giet_tsar/isr.c	(revision 158)
+++ /trunk/softs/giet_tsar/isr.c	(revision 158)
@@ -0,0 +1,186 @@
+/*************************************************************************************
+   File : isr.c
+   Authors : Alain Greiner
+   Date : april 2011
+
+   These routines must be "intalled" by the boot code in the
+   interrupt vector, depending on the system architecture.
+*************************************************************************************/
+
+#include "isr.h"
+#include "drivers.h"
+
+#define in_isr __attribute__((section (".isr")))
+
+struct plaf;
+
+extern struct plaf seg_dma_base;
+extern struct plaf seg_ioc_base;
+extern struct plaf seg_timer_base;
+extern struct plaf seg_tty_base;
+
+extern struct plaf NB_TIMERS;
+extern struct plaf NB_TASKS;
+
+//////////////////////////////////////////////////////////////////////////////////////
+//  _isr_dma
+//  Each processor controls its own private DMA.
+//  It acknowledge the IRQ using the dma base address depending on the proc_id
+//  as computed by the  _segment_increment() function, writes the transfer
+//  status in the _dma_status[pid] variable, and resets the _dma_busy[pid]
+//  synchrnisation variable to signal completion.
+//  Both variables are defined in the drivers.c file.
+/////////////////////////////////////////////////////////////////////////////////////
+in_isr void _isr_dma()
+{
+    int*		dma_address;
+    unsigned int	base		= (unsigned int)&seg_dma_base;
+    unsigned int	increment 	= _segment_increment(DMA_SPAN*4);
+    size_t		pid		= _procid();
+   
+    dma_address	= (int*)(base + increment);
+    
+    _dma_status[pid]		= dma_address[DMA_LEN];	// save status
+    _dma_busy[pid]		= 0;			// release DMA
+    dma_address[DMA_RESET]	= 0;			// reset IRQ
+}
+//////////////////////////////////////////////////////////////////////////////////////
+//  _isr_ioc
+//  There is only one IOC controler shared by all tasks.
+//  It acknowledge the IRQ using the ioc base address, save the status,
+//  and set the _ioc_done variable to signal completion.
+//  This variable is defined in the drivers.c file.
+//////////////////////////////////////////////////////////////////////////////////////
+in_isr void _isr_ioc()
+{
+    int* ioc_address = (int*)&seg_ioc_base;
+    
+    _ioc_status = ioc_address[BLOCK_DEVICE_STATUS];	// save status & reset IRQ
+    _ioc_done   = 1;					// signals completion
+}
+//////////////////////////////////////////////////////////////////////////////////////
+//  _isr_timer* (* = 0,1,2,3)
+//  A single processor can use up to 4 independant timers.
+//  These 4 ISRs handle up to 4 IRQs generated by 4 independant timers,
+//  connected to a single processor.
+//  It acknowledge the IRQ using the timer base address depending
+//  on both the proc_id and the timer_id (0,1,2,3).
+//  It displays a message on TTY[proc_id,task_id]. 
+//////////////////////////////////////////////////////////////////////////////////////
+in_isr void _isr_timer_indexed(size_t timer_id)
+{
+    int*		timer_address;
+    size_t		ntimers		= (size_t)&NB_TIMERS;
+    unsigned int	base		= (unsigned int)&seg_timer_base;
+    unsigned int	increment 	= _segment_increment(ntimers*TIMER_SPAN*4);
+    int			date 		= (int)_proctime();
+    char		buf[10];
+
+    timer_address = (int*)(base + increment + timer_id*TIMER_SPAN*4);
+
+    timer_address[TIMER_RESETIRQ] = 0;			// reset IRQ
+
+    _itoa_dec(date, buf);				// print message
+    _tty_write("\n!!! interrupt timer0 received at cycle ", 40);
+    _tty_write(buf, 10); 
+    _tty_write("\n\n", 2);
+}
+in_isr void _isr_timer()
+{
+    _isr_timer_indexed(0);
+}
+in_isr void _isr_timer0()
+{
+    _isr_timer_indexed(0);
+}
+in_isr void _isr_timer1()
+{
+    _isr_timer_indexed(1);
+}
+in_isr void _isr_timer2()
+{
+    _isr_timer_indexed(2);
+}
+in_isr void _isr_timer3()
+{
+    _isr_timer_indexed(3);
+}
+//////////////////////////////////////////////////////////////////////////////////////
+//  _isr_tty_get_task* (* = 0,1,2,3)
+//  A single processor can run up to 4 tasks in pseudo-parallelismr,
+//  and each task has is own private terminal.
+//  These 4 ISRs handle up to 4 IRQs associate to 4 independant terminals
+//  connected to a single processor.
+//  It acknowledge the IRQ using the terminal basee address depending
+//  on both the proc_id  and the task_id (0,1,2,3).
+//  There is one communication buffer _tty_get_buf[tty_id] per terminal.
+//  protected by a set/reset variable _tty_get_full[tty_id].
+//  The _tty_get_full[tty_id] synchronisation variable is set
+//  by the ISR, and reset by the OS.
+//  Both variables are defined in the drivers.c file.
+//  To access these buffers, the terminal index is computed as
+//      tty_id = proc_id*ntasks + task_id
+//  A character is lost if the buffer is full when the ISR is executed.
+//////////////////////////////////////////////////////////////////////////////////////
+in_isr void _isr_tty_get_indexed(size_t task_id)
+{
+    char*		tty_address;
+    size_t		ntasks		= (size_t)&NB_TASKS;
+    size_t		tty_id		= _procid()*ntasks + task_id;
+    unsigned int	base		= (unsigned int)&seg_tty_base;
+    unsigned int	increment 	= _segment_increment(ntasks*TTY_SPAN*4);
+
+    tty_address = (char*)(base + increment + task_id*TTY_SPAN*4);
+
+    _tty_get_buf[tty_id] = tty_address[TTY_READ*4];	// save character and reset IRQ
+    _tty_get_full[tty_id] = 1;				// signals character available
+}
+in_isr void _isr_tty_get()
+{
+    _isr_tty_get_indexed(0);
+}
+in_isr void _isr_tty_get_task0()
+{
+    _isr_tty_get_indexed(0);
+}
+in_isr void _isr_tty_get_task1()
+{
+    _isr_tty_get_indexed(1);
+}
+in_isr void _isr_tty_get_task2()
+{
+    _isr_tty_get_indexed(2);
+}
+in_isr void _isr_tty_get_task3()
+{
+    _isr_tty_get_indexed(3);
+}
+//////////////////////////////////////////////////////////////////////////////////////
+//  _isr_switch
+//  This ISR is in charge of context switch.
+//  It handles up to 4 IRQs, corresponding to 4 different processors.
+//  If the processor uses several timers, the context switch is driven
+//  by the IRQ associated to timer0.
+//  It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function.
+//////////////////////////////////////////////////////////////////////////////////////
+in_isr void _isr_switch()
+{
+    int*		timer_address;
+    unsigned int	base		= (unsigned int)&seg_timer_base;
+    unsigned int	increment	= _segment_increment(TIMER_SPAN*4);
+
+    timer_address = (int*)(base + increment);
+
+    timer_address[TIMER_RESETIRQ] = 0;			// reset IRQ
+    _ctx_switch();
+}
+
+/* Local Variables:
+   tab-width: 4;
+   c-basic-offset: 4;
+   c-file-offsets:((innamespace . 0)(inline-open . 0));
+   indent-tabs-mode: nil;
+   End: */
+
+/* vim: set filetype=asm expandtab shiftwidth=4 tabstop=4 softtabstop=4: */
+
Index: /trunk/softs/giet_tsar/isr.h
===================================================================
--- /trunk/softs/giet_tsar/isr.h	(revision 158)
+++ /trunk/softs/giet_tsar/isr.h	(revision 158)
@@ -0,0 +1,24 @@
+/**************************************************************************************
+    File : isr.h
+    Written by Alain Greiner
+    Date : April 2011
+
+    The Interrupt Service Routine (ISR) supported by the GIET are:
+**************************************************************************************/
+
+void _isr_dma();
+
+void _isr_ioc();
+
+void _isr_timer0();
+void _isr_timer1();
+void _isr_timer2();
+void _isr_timer3();
+
+void _isr_tty_get();
+void _isr_tty_get_task0();
+void _isr_tty_get_task1();
+void _isr_tty_get_task2();
+void _isr_tty_get_task3();
+
+void _isr_switch();
Index: /trunk/softs/giet_tsar/stdio.c
===================================================================
--- /trunk/softs/giet_tsar/stdio.c	(revision 158)
+++ /trunk/softs/giet_tsar/stdio.c	(revision 158)
@@ -0,0 +1,833 @@
+/*********************************************************************
+    fichier stdio.c
+    Written Alain greiner & Nicolas Pouillon
+    Date : 19/10/2009
+
+ These function implement the drivers for the SoCLib peripherals.
+ *********************************************************************/
+
+#include <stdarg.h>
+
+#include "stdio.h"
+
+#include "timer.h"
+#include "tty.h"
+#include "gcd.h"
+#include "icu.h"
+#include "dma.h"
+#include "block_device.h"
+
+/*********************************************************************
+  We define a generic C function to implement all system calls.
+ *********************************************************************/
+inline int sys_call( int call_no,
+        int arg_0,
+        int arg_1,
+        int arg_2,
+        int arg_3 )
+{
+    register int reg_no_and_output asm("v0") = call_no;
+    register int reg_a0 asm("a0") = arg_0;
+    register int reg_a1 asm("a1") = arg_1;
+    register int reg_a2 asm("a2") = arg_2;
+    register int reg_a3 asm("a3") = arg_3;
+
+    asm volatile(
+            "syscall"
+            : "=r" (reg_no_and_output)  // arguments de sortie
+            : "r" (reg_a0),         // arguments d'entrée
+            "r" (reg_a1),
+            "r" (reg_a2),
+            "r" (reg_a3),
+            "r" (reg_no_and_output)
+            : "memory",             // ressources modifiees:
+            "at",
+            "v1",
+            "ra",            // Ces registres persistants seront sauvegardes
+            "t0",            // sur la pile par le compilateur
+            "t1",            // seulement s'ils contiennent des donnees
+            "t2",            // calculees par la fonction effectuant le syscall,
+            "t3",            // et que ces valeurs sont reutilisees par cette
+            "t4",            // fonction au retour du syscall.
+            "t5",
+            "t6",
+            "t7",
+            "t8",
+            "t9"
+               );
+    return reg_no_and_output;
+}
+
+/********************************************************************
+  procid()
+  Returns the processor ident.
+ ********************************************************************/
+int procid()
+{
+    return sys_call(SYSCALL_PROCID, 0, 0, 0, 0);
+}
+/********************************************************************
+  proctime()
+  Returns the local processor time.
+ ********************************************************************/
+int proctime()
+{
+    return sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0);
+}
+/********************************************************************
+  procnumber()
+  Returns the number of processors controled by the system.
+ ********************************************************************/
+int procnumber()
+{
+    return sys_call(SYSCALL_PROCNUMBER, 0, 0, 0, 0);
+}
+/********************************************************************
+  exit()
+  Exit the program with a TTY message, and enter an infinite loop...
+ ********************************************************************/
+int exit()
+{
+    int proc_index = procid();
+    return sys_call(SYSCALL_EXIT, proc_index, 0, 0, 0);
+}
+/********************************************************************
+  rand()
+  Returns a pseudo-random value derived from the processor cycle count.
+  This value is comprised between 0 & 65535.
+ ********************************************************************/
+int rand()
+{
+    int x = sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0);
+    if((x & 0xF) > 7)
+        return (x*x & 0xFFFF);
+    else
+        return (x*x*x & 0xFFFF);
+}
+
+/*************************************************************************
+  MULTI-TTY
+ **************************************************************************
+ tty_putc()
+ Display a single ascii character on a terminal.
+ The terminal index is implicitely defined by the processor ID.
+ (and by the task ID in case of multi-tasking)
+ It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer.
+ This function returns 0 in case of success.
+ ******************************i*******************************************/
+int tty_putc(char byte)
+{
+    return sys_call(SYSCALL_TTY_WRITE,
+            (int)(&byte),
+            1,
+            0,0);
+}
+/*************************************************************************
+  tty_puts()
+  Display a string on a terminal.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  The string must be terminated by a NUL character.
+  It doesn't use the TTY_PUT_IRQinterrupt, and the associated kernel buffer.
+  This function returns 0 in case of success.
+ **************************************************************************/
+int tty_puts(char* string)
+{
+    int length = 0;
+    while (string[length] != 0) {
+        length++;
+    }
+    return sys_call(SYSCALL_TTY_WRITE,
+            (int)string,
+            length,
+            0,0);
+}
+/*************************************************************************
+  tty_putw()
+  Display the value of a 32 bits word (decimal characters).
+  The terminal index is implicitely defined by the processor ID.
+  (and by pthe task ID in case of multi-tasking)
+  It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer.
+  This function returns 0 in case of success.
+ **************************************************************************/
+int tty_putw(int val)
+{
+    char buf[10];
+    int i;
+    for( i=0 ; i<10 ; i++ ) {
+        buf[9-i] = (val % 10) + 0x30;
+        val = val / 10;
+    }
+    return sys_call(SYSCALL_TTY_WRITE,
+            (int)buf,
+            10,
+            0,0);
+}
+/********************************************************************
+  tty_getc()
+  Fetch a single ascii character from a terminal.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  It doesn't use the IRQ_GET interrupt, and the associated kernel buffer.
+  It is a blocking function that returns 0 if a valid char is stored
+  in the buffer, and returns -1 in case of error.
+ ********************************************************************/
+int tty_getc(char* buf)
+{
+    int ret = 0;
+    while( ret == 0 )
+    {
+        ret = sys_call(SYSCALL_TTY_READ,
+                (int)buf,
+                1,
+                0,0);
+        if ((ret < 0) || (ret > 1)) return -1;  // return error
+    }
+    return 0;   // return ok
+}
+/********************************************************************
+  tty_getc_irq()
+  Fetch a single ascii character from a terminal.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  It uses the IRQ_GET interrupt, and the associated kernel buffer.
+  It is a blocking function that returns 0 if a valid char is stored
+  in the buffer, and returns -1 in case of error.
+ ********************************************************************/
+int tty_getc_irq(char* buf)
+{
+    int ret = 0;
+    while( ret == 0 )
+    {
+        ret = sys_call(SYSCALL_TTY_READ_IRQ,
+                (int)buf,
+                1,
+                0,0);
+        if ((ret < 0) || (ret > 1)) return -1;  // return error
+    }
+    return 0;   // return ok
+}
+/********************************************************************
+  tty_gets_irq()
+  Fetch a string from a terminal to a bounded length buffer.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer.
+  It is a blocking function that returns 0 if a valid string is stored
+  in the buffer, and returns -1 in case of error.
+  Up to (bufsize - 1) characters (including the non printable
+  characters) will be copied into buffer, and the string is
+  always completed by a NUL character.
+  The <LF> character is interpreted, as the function close
+  the string with a NUL character if <LF> is read.
+  The <DEL> character is interpreted, and the corresponding
+  character(s) are removed from the target buffer.
+ ********************************************************************/
+int tty_gets_irq(char* buf, int bufsize)
+{
+    int ret;
+    unsigned char byte;
+    unsigned int index = 0;
+
+    while( index < (bufsize-1) )
+    {
+        ret = sys_call(SYSCALL_TTY_READ_IRQ,
+                (int)(&byte),
+                1,
+                0,0);
+
+        if ((ret < 0) || (ret > 1)) return -1;  // return error
+
+        else if ( ret == 1 )            // valid character
+        {
+            if ( byte == 0x0A ) break; // LF
+            else if ((byte == 0x7F) && (index>0)) index--; // DEL
+            else
+            {
+                buf[index] = byte;
+                index++;
+            }
+        }
+    } // end while
+    buf[index] = 0;
+    return 0;       // return ok
+}
+/********************************************************************
+  tty_getw_irq()
+  Fetch a string of decimal characters (most significant digit first)
+  to build a 32 bits unsigned int.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  This is a blocking function that returns 0 if a valid unsigned int
+  is stored in the buffer, and returns -1 in case of error.
+  It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer.
+  The non-blocking system function _tty_read_irq is called several times,
+  and the decimal characters are written in a 32 characters buffer
+  until a <LF> character is read.
+  The <DEL> character is interpreted, and previous characters can be
+  cancelled. All others characters are ignored.
+  When the <LF> character is received, the string is converted to
+  an unsigned int value. If the number of decimal digit is too large
+  for the 32 bits range, the zero value is returned.
+ ********************************************************************/
+int tty_getw_irq(int* word_buffer)
+{
+    unsigned char buf[32];
+    unsigned char byte;
+    unsigned int save = 0;
+    unsigned int val = 0;
+    unsigned int done = 0;
+    unsigned int overflow = 0;
+    unsigned int max = 0;
+    unsigned int i;
+    int ret;
+
+    while(done == 0)
+    {
+        ret = sys_call(SYSCALL_TTY_READ_IRQ,
+                (int)(&byte),
+                1,
+                0,0);
+        if ((ret < 0) || (ret > 1)) return -1;  // return error
+
+        if ( ret == 1 )     // get one character
+        {
+            if (( byte > 0x2F) && (byte < 0x3A))  // decimal character
+            {
+                buf[max] = byte;
+                max++;
+                tty_putc(byte);
+            }
+            else if ( (byte == 0x0A) || (byte == 0x0D) ) // LF or CR character
+            {
+                done = 1;
+            }
+            else if ( byte == 0x7F )        // DEL character
+            {
+                if (max > 0)
+                {
+                    max--;          // cancel the character
+                    tty_putc(0x08);
+                    tty_putc(0x20);
+                    tty_putc(0x08);
+                }
+            }
+            if ( max == 32 )            // decimal string overflow
+            {
+                for( i=0 ; i<max ; i++)     // cancel the string
+                {
+                    tty_putc(0x08);
+                    tty_putc(0x20);
+                    tty_putc(0x08);
+                }
+                tty_putc(0x30);
+                *word_buffer = 0;           // return 0 value
+                return 0;
+            }
+        }
+    } // end while
+
+    // string conversion
+    for( i=0 ; i<max ; i++ )
+    {
+        val = val*10 + (buf[i] - 0x30);
+        if (val < save) overflow = 1;
+        save = val;
+    }
+    if (overflow == 0)
+    {
+        *word_buffer = val;     // return decimal value
+    }
+    else
+    {
+        for( i=0 ; i<max ; i++)     // cancel the string
+        {
+            tty_putc(0x08);
+            tty_putc(0x20);
+            tty_putc(0x08);
+        }
+        tty_putc(0x30);
+        *word_buffer = 0;       // return 0 value
+    }
+    return 0;
+}
+/*********************************************************************
+  tty_printf()
+  This function is a simplified version of the mutek_printf() function.
+  The terminal index is implicitely defined by the processor ID.
+  (and by the task ID in case of multi-tasking)
+  It doesn't use the IRQ_PUT interrupt, anf the associated kernel buffer.
+  Only a limited number of formats are supported:
+  - %d : signed decimal
+  - %u : unsigned decimal
+  - %x : hexadecimal
+  - %c : char
+  - %s : string
+ *********************************************************************/
+int tty_printf(char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+
+printf_text:
+
+    while (*format) {
+        unsigned int i;
+        for (i = 0; format[i] && format[i] != '%'; i++)
+            ;
+        if (i) {
+            sys_call(SYSCALL_TTY_WRITE,
+                    (int)format,
+                    i,
+                    0,0);
+            format += i;
+        }
+        if (*format == '%') {
+            format++;
+            goto printf_arguments;
+        }
+    } // end while
+
+    va_end(ap);
+    return 0;
+
+printf_arguments:
+
+    {
+        int         val = va_arg(ap, long);
+        char            buf[20];
+        char*           pbuf;
+        unsigned int        len = 0;
+        static const char   HexaTab[] = "0123456789ABCDEF";
+        unsigned int        i;
+
+        switch (*format++) {
+            case ('c'):             // char conversion
+                len = 1;
+                buf[0] = val;
+                pbuf = buf;
+                break;
+            case ('d'):             // decimal signed integer
+                if (val < 0) {
+                    val = -val;
+                    sys_call(SYSCALL_TTY_WRITE,
+                            (int)"-",
+                            1,
+                            0,0);
+                }
+            case ('u'):             // decimal unsigned integer
+                for( i=0 ; i<10 ; i++) {
+                    buf[9-i] = HexaTab[val % 10];
+                    if (!(val /= 10)) break;
+                }
+                len =  i+1;
+                pbuf = &buf[9-i];
+                break;
+            case ('x'):             // hexadecimal integer
+                sys_call(SYSCALL_TTY_WRITE,
+                        (int)"0x",
+                        2,
+                        0,0);
+                for( i=0 ; i<8 ; i++) {
+                    buf[7-i] = HexaTab[val % 16U];
+                    if (!(val /= 16U)) break;
+                }
+                len =  i+1;
+                pbuf = &buf[7-i];
+                break;
+            case ('s'):             // string
+                {
+                    char *str = (char*)val;
+                    while ( str[len] ) len++;
+                    pbuf = (char*)val;
+                }
+                break;
+            default:
+                goto printf_text;
+        } // end switch
+
+        sys_call(SYSCALL_TTY_WRITE,
+                (int)pbuf,
+                len,
+                0,0);
+        goto printf_text;
+    }
+} // end printf()
+
+/********************************************************************
+  MULTI-TIMER
+  For all system calls, the first argument is the Timer index.
+ *********************************************************************
+ timer_set_mode()
+ The possible values for the TIMER_MODE register are
+ - 0x0 : Timer not activated
+ - 0x1 : Timer activated, but no interrupt is generated
+ - 0x3 : Timer activarted and periodic interrupts generated
+ ********************************************************************/
+int timer_set_mode(int timer_index, int val)
+{
+    return sys_call(SYSCALL_TIMER_WRITE,
+            timer_index,
+            TIMER_MODE,
+            val,
+            0);
+}
+/********************************************************************
+  timer_set_period()
+  Defines the period value for the periodic interrupt.
+ ********************************************************************/
+int timer_set_period(int timer_index, int val)
+{
+    return sys_call(SYSCALL_TIMER_WRITE,
+            timer_index,
+            TIMER_PERIOD,
+            val,
+            0);
+}
+/********************************************************************
+  timer_reset_irq()
+ ********************************************************************/
+int timer_reset_irq(int timer_index)
+{
+    return sys_call(SYSCALL_TIMER_WRITE,
+            timer_index,
+            TIMER_RESETIRQ,
+            0, 0);
+}
+/********************************************************************
+  timer_get_time()
+  returns the current timer value.
+ ********************************************************************/
+int timer_get_time(int timer_index, int* time)
+{
+    return sys_call(SYSCALL_TIMER_READ,
+            timer_index,
+            TIMER_VALUE,
+            (int)time,
+            0);
+}
+
+/********************************************************************
+  GCD COPROCESSOR
+ *********************************************************************
+ gcd_set_opa(int val)
+ Set operand A in the GCD (Greater Common Divider) coprocessor.
+ ********************************************************************/
+int gcd_set_opa(int val)
+{
+    return sys_call(SYSCALL_GCD_WRITE,
+            GCD_OPA,
+            val,
+            0, 0);
+}
+/********************************************************************
+  gcd_set_opb(int val)
+  Set operand B in the GCD (Greater Common Divider) coprocessor.
+ ********************************************************************/
+int gcd_set_opb(int val)
+{
+    return sys_call(SYSCALL_GCD_WRITE,
+            GCD_OPB,
+            val,
+            0, 0);
+}
+/********************************************************************
+  gcd_start()
+  Start computation in the GCD (Greater Common Divider) coprocessor.
+ ********************************************************************/
+int gcd_start(int val)
+{
+    return sys_call(SYSCALL_GCD_WRITE,
+            GCD_START,
+            0, 0, 0);
+}
+/********************************************************************
+  gcd_get_status(int* val)
+  Get status fromn the GCD (Greater Common Divider) coprocessor.
+  The value is nul when the coprocessor is idle (computation completed)
+ ********************************************************************/
+int gcd_get_status(int* val)
+{
+    return sys_call(SYSCALL_GCD_READ,
+            GCD_STATUS,
+            (int)val,
+            0, 0);
+}
+/********************************************************************
+  gcd_get_result(int* val)
+  Get result fromn the GCD (Greater Common Divider) coprocessor.
+ ********************************************************************/
+int gcd_get_result(int* val)
+{
+    return sys_call(SYSCALL_GCD_READ,
+            GCD_OPA,
+            (int)val,
+            0, 0);
+}
+
+/********************************************************************
+  ICU(s)
+ *********************************************************************
+ icu_set_mask()
+ Set some bits in the Interrupt Enable Mask of the ICU component.
+ Each bit set in the written word will be set in the Mask Enable.
+ ********************************************************************/
+int icu_set_mask(int val)
+{
+    return sys_call(SYSCALL_ICU_WRITE,
+            ICU_MASK_SET,
+            val,
+            0, 0);
+}
+/********************************************************************
+  icu_clear_mask()
+  Reset some bits in the Interrupt Enable Mask of the ICU component.
+  Each bit set in the written word will be reset in the Mask Enable.
+ ********************************************************************/
+int icu_clear_mask(int val)
+{
+    return sys_call(SYSCALL_ICU_WRITE,
+            ICU_MASK_CLEAR,
+            val,
+            0, 0);
+}
+/********************************************************************
+  icu_get_mask()
+  Read the Interrupt Enable Mask of the ICU component.
+ ********************************************************************/
+int icu_get_mask(int* buffer)
+{
+    return sys_call(SYSCALL_ICU_READ,
+            ICU_MASK,
+            (int)buffer,
+            0, 0);
+}
+/********************************************************************
+  icu_get_irqs()
+  Read the value of the 32 interrupt lines (IRQ inputs).
+ ********************************************************************/
+int icu_get_irqs(int* buffer)
+{
+    return sys_call(SYSCALL_ICU_READ,
+            ICU_INT,
+            (int)buffer,
+            0, 0);
+}
+/********************************************************************
+  icu_get_index()
+  Read the index of the highest priority active interrupt.
+  (If no active interrupt, -1 is returned).
+ ********************************************************************/
+int icu_get_index(int* buffer)
+{
+    return sys_call(SYSCALL_ICU_READ,
+            ICU_IT_VECTOR,
+            (int)buffer,
+            0, 0);
+}
+
+/********************************************************************
+  LOCKS
+ *********************************************************************
+ lock_acquire()
+ This system call performs a spin-lock acquisition.
+ It is dedicated to the SoCLib LOCKS peripheral.
+ In case of busy waiting, there is a random delay
+ of about 100 cycles between two successive lock read,
+ to avoid bus saturation.
+ ********************************************************************/
+int lock_acquire(int lock_index)
+{
+    return sys_call(SYSCALL_LOCKS_READ,
+            lock_index,
+            0, 0, 0);
+}
+
+/********************************************************************
+  lock_release()
+  You must use this system call to release a spin-lock,
+  as the LOCKS peripheral is in the kernel segment.
+ ********************************************************************/
+int lock_release(int lock_index)
+{
+    return sys_call(SYSCALL_LOCKS_WRITE,
+            lock_index,
+            0, 0, 0);
+}
+
+/********************************************************************
+  I/O BLOCK DEVICE
+ *********************************************************************
+ ioc_write()
+ Transfer data from a memory buffer to a file on the block_device.
+ - lba        : Logical Block Address (first block index)
+ - buffer     : base address of the memory buffer
+ - count      : number of blocks to be transfered
+ This function returns 0 if the transfert can be done.
+ It returns -1 if the buffer is not in user address space.
+ ********************************************************************/
+int ioc_write(size_t lba, void* buffer, size_t count)
+{
+    return sys_call(SYSCALL_IOC_WRITE,
+            lba,
+            (int)buffer,
+            count,
+            0);
+}
+/********************************************************************
+  ioc_read()
+  Transfer data from a file on the block_device to a memory buffer.
+  - lba        : Logical Block Address (first block index)
+  - buffer     : base address of the memory buffer
+  - count      : number of blocks to be transfered
+  This function returns 0 if the transfert can be done.
+  It returns -1 if the buffer is not in user address space.
+ ********************************************************************/
+int ioc_read(size_t lba, void* buffer, size_t count)
+{
+    return sys_call(SYSCALL_IOC_READ,
+            lba,
+            (int)buffer,
+            count,
+            0);
+}
+/********************************************************************
+  ioc_completed()
+  This blocking function returns 0 when the I/O transfer is
+  successfully completed, and returns -1 if an address error
+  has been detected.
+ ********************************************************************/
+int ioc_completed()
+{
+    return sys_call(SYSCALL_IOC_COMPLETED,
+            0, 0, 0, 0);
+}
+
+/********************************************************************
+  FRAME BUFFER
+ *********************************************************************
+ fb_sync_write()
+ This blocking function use a memory copy strategy to transfer data
+ from a user buffer to the frame buffer device in kernel space,
+ - offset     : offset (in bytes) in the frame buffer
+ - buffer     : base address of the memory buffer
+ - length     : number of bytes to be transfered
+ It returns 0 when the transfer is completed.
+ ********************************************************************/
+int fb_sync_write(size_t offset, void* buffer, size_t length)
+{
+    return sys_call(SYSCALL_FB_SYNC_WRITE,
+            offset,
+            (int)buffer,
+            length,
+            0);
+}
+/********************************************************************
+  fb_sync_read()
+  This blocking function use a memory copy strategy to transfer data
+  from the frame buffer device in kernel space to an user buffer.
+  - offset     : offset (in bytes) in the frame buffer
+  - buffer     : base address of the user buffer
+  - length     : number of bytes to be transfered
+  It returns 0 when the transfer is completed.
+ ********************************************************************/
+int fb_sync_read(size_t offset, void* buffer, size_t length)
+{
+    return sys_call(SYSCALL_FB_SYNC_READ,
+            offset,
+            (int)buffer,
+            length,
+            0);
+}
+/********************************************************************
+  fb_write()
+  This non-blocking function use the DMA coprocessor to transfer data
+  from a user buffer to the frame buffer device in kernel space,
+  - offset     : offset (in bytes) in the frame buffer
+  - buffer     : base address of the user buffer
+  - length     : number of bytes to be transfered
+  It returns 0 when the transfer can be started.
+  It returns -1 if the buffer is not in user address space.
+  The transfer completion is signaled by an IRQ, and must be
+  tested by the fb_completed() function.
+ ********************************************************************/
+int fb_write(size_t offset, void* buffer, size_t length)
+{
+    return sys_call(SYSCALL_FB_WRITE,
+            offset,
+            (int)buffer,
+            length,
+            0);
+}
+/********************************************************************
+  fb_read()
+  This non-blocking function use the DMA coprocessor to transfer data
+  from the frame buffer device in kernel space to an user buffer.
+  - offset     : offset (in bytes) in the frame buffer
+  - buffer     : base address of the memory buffer
+  - length     : number of bytes to be transfered
+  It returns 0 when the transfer can be started.
+  It returns -1 if the buffer is not in user address space.
+  The transfer completion is signaled by an IRQ, and must be
+  tested by the fb_completed() function.
+ ********************************************************************/
+int fb_read(size_t offset, void* buffer, size_t length)
+{
+    return sys_call(SYSCALL_FB_READ,
+            offset,
+            (int)buffer,
+            length,
+            0);
+}
+/********************************************************************
+  fb_completed()
+  This blocking function returns when the transfer is completed.
+  It returns 0 if the transfer is successful.
+  It returns -1 if an address error has been detected.
+ ********************************************************************/
+int fb_completed()
+{
+    return sys_call(SYSCALL_FB_COMPLETED,
+            0, 0, 0, 0);
+}
+
+/********************************************************************
+  SYNCHRONISATION BARRIERS
+ *********************************************************************
+  barrier_init()
+  This function initializes the counter for barrier[index].
+  - index     : index of the barrier (between 0 & 7)
+  - count     : number of tasks to be synchronized.
+  The GIET supports up to 8 independant barriers.
+  It returns a non zero value when the barrier index is larger than 7.
+* ********************************************************************/
+int barrier_init(size_t index, size_t count)
+{
+    return sys_call(SYSCALL_BARRIER_INIT,
+            (int)index,
+            (int)count,
+            0, 0);
+}
+/********************************************************************
+  barrier_wait()
+  This blocking function use a busy waiting policy, and returns only
+  when all synchonized asks have reached the barrier.
+  - index     : index of the barrier (between 0 & 7)
+  The GIET supports up to 8 independant barriers.
+  It returns a non zero value when the barrier index is larger than 7.
+ ********************************************************************/
+int barrier_wait(size_t index)
+{
+    return sys_call(SYSCALL_BARRIER_WAIT,
+            (int)index,
+            0, 0, 0);
+}
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/stdio.h
===================================================================
--- /trunk/softs/giet_tsar/stdio.h	(revision 158)
+++ /trunk/softs/giet_tsar/stdio.h	(revision 158)
@@ -0,0 +1,137 @@
+/*********************************************************************************
+    fichier stdio.h
+    Written Alain greiner & Nicolas Pouillon
+    Date : 15/09/2009
+ *********************************************************************************/
+
+#ifndef _STDIO_H_
+#define _STDIO_H_
+
+#define SYSCALL_PROCID          0x00
+#define SYSCALL_PROCTIME        0x01
+#define SYSCALL_TTY_WRITE       0x02
+#define SYSCALL_TTY_READ        0x03
+#define SYSCALL_TIMER_WRITE     0x04
+#define SYSCALL_TIMER_READ      0x05
+#define SYSCALL_GCD_WRITE       0x06
+#define SYSCALL_GCD_READ        0x07
+#define SYSCALL_ICU_WRITE       0x08
+#define SYSCALL_ICU_READ        0x09
+#define SYSCALL_TTY_READ_IRQ    0x0A
+#define SYSCALL_TTY_WRITE_IRQ   0x0B
+#define SYSCALL_LOCKS_WRITE     0x0C
+#define SYSCALL_LOCKS_READ      0x0D
+#define SYSCALL_EXIT            0x0E
+#define SYSCALL_PROCNUMBER      0x0F
+
+#define SYSCALL_FB_SYNC_WRITE   0x10
+#define SYSCALL_FB_SYNC_READ    0x11
+#define SYSCALL_FB_WRITE        0x12
+#define SYSCALL_FB_READ         0x13
+#define SYSCALL_FB_COMPLETED    0x14
+#define SYSCALL_IOC_WRITE       0x15
+#define SYSCALL_IOC_READ        0x16
+#define SYSCALL_IOC_COMPLETED   0x17
+#define SYSCALL_BARRIER_INIT	0x18
+#define SYSCALL_BARRIER_WAIT	0x19
+
+typedef unsigned int size_t;
+
+/****************************************************************
+  this is a generic C function to implement all system calls.
+  - The first argument is the system call index.
+  - The four next arguments are the system call arguments.
+  They will be written in registers $2, $4, $5, $6, $7.
+ ****************************************************************/
+int sys_call(int call_no,
+        int arg_o,
+        int arg_1,
+        int arg_2,
+        int arg_3);
+
+/****************************************************************
+  These functions access the MIPS protected registers
+ ****************************************************************/
+int procid();
+int proctime();
+int procnumber();
+int exit();
+int rand();
+
+/****************************************************************
+  These functions access the MULTI_TTY peripheral
+ ****************************************************************/
+int tty_puts(char* string);
+int tty_putc(char byte);
+int tty_putw(int word);
+int tty_getc(char* byte);
+int tty_getc_irq(char* byte);
+int tty_gets_irq(char* buf, int bufsize);
+int tty_getw_irq(int* word);
+int tty_printf(char* format,...);
+
+/****************************************************************
+  These functions access the MULTI_TIMER peripheral
+ ****************************************************************/
+int timer_set_mode(int timer_index, int mode);
+int timer_set_period(int timer_index, int period);
+int timer_reset_irq(int timer_index);
+int timer_get_time(int timer_index, int* time);
+
+/****************************************************************
+  These functions access the GCD peripheral
+ ****************************************************************/
+int gcd_set_opa(int val);
+int gcd_set_opb(int val);
+int gcd_start();
+int gcd_get_result(int* val);
+int gcd_get_status(int* val);
+
+/****************************************************************
+  These functions access the ICU peripheral
+ ****************************************************************/
+int icu_set_mask(int val);
+int icu_clear_mask(int val);
+int icu_get_mask(int* buffer);
+int icu_get_irqs(int* buffer);
+int icu_get_index(int* buffer);
+
+/****************************************************************
+  These functions access the LOCKS peripheral
+ ****************************************************************/
+int lock_acquire(int lock_index);
+int lock_release(int lock_index);
+
+/****************************************************************
+  These functions access the BLOCK_DEVICE peripheral
+ ****************************************************************/
+int ioc_read(size_t lba, void* buffer, size_t count);
+int ioc_write(size_t lba, void* buffer, size_t count);
+int ioc_completed();
+
+/****************************************************************
+  These functions access the FRAME_BUFFER peripheral
+ ****************************************************************/
+int fb_read(size_t offset, void* buffer, size_t length);
+int fb_write(size_t offset, void* buffer, size_t length);
+int fb_completed();
+int fb_sync_read(size_t offset, void* buffer, size_t length);
+int fb_sync_write(size_t offset, void* buffer, size_t length);
+
+/****************************************************************
+  These functions access the synchronization barriers
+ ****************************************************************/
+int barrier_init(size_t index, size_t count);
+int barrier_wait(size_t index);
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/timer.h
===================================================================
--- /trunk/softs/giet_tsar/timer.h	(revision 158)
+++ /trunk/softs/giet_tsar/timer.h	(revision 158)
@@ -0,0 +1,23 @@
+#ifndef TIMER_REGS_H
+#define TIMER_REGS_H
+
+enum SoclibTimerRegisters {
+    TIMER_VALUE     =   0,
+    TIMER_MODE      =   1,
+    TIMER_PERIOD    =   2,
+    TIMER_RESETIRQ  =   3,
+    /**/
+    TIMER_SPAN      =   4,
+};
+
+#endif /* TIMER_REGS_H */
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/giet_tsar/tty.h
===================================================================
--- /trunk/softs/giet_tsar/tty.h	(revision 158)
+++ /trunk/softs/giet_tsar/tty.h	(revision 158)
@@ -0,0 +1,23 @@
+#ifndef TTY_REGS_H
+#define TTY_REGS_H
+
+enum SoclibTtyRegisters {
+    TTY_WRITE   = 0,
+    TTY_STATUS  = 1,
+    TTY_READ    = 2,
+    TTY_CONFIG  = 3,
+    /**/
+    TTY_SPAN    = 4,
+};
+
+#endif
+
+// Local Variables:
+// tab-width: 4;
+// c-basic-offset: 4;
+// c-file-offsets:((innamespace . 0)(inline-open . 0));
+// indent-tabs-mode: nil;
+// End:
+//
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
+
Index: /trunk/softs/soft_filter_giet/Makefile
===================================================================
--- /trunk/softs/soft_filter_giet/Makefile	(revision 158)
+++ /trunk/softs/soft_filter_giet/Makefile	(revision 158)
@@ -0,0 +1,46 @@
+LD=mipsel-unknown-elf-ld
+CC=mipsel-unknown-elf-gcc
+AS=mipsel-unknown-elf-as
+DU=mipsel-unknown-elf-objdump
+
+OBJS=   reset.o \
+	giet.o \
+	isr.o \
+	drivers.o \
+	stdio.o \
+	main.o
+
+CFLAGS= -Wall -mno-gpopt -ffreestanding -fomit-frame-pointer -mips32 -ggdb
+
+GIET=	/Users/alain/soc/tsar-svn-june-2010/softs/giet_tsar
+
+bin.soft: $(OBJS) ldscript
+	$(LD) -o $@ -T ldscript $(OBJS)
+	$(DU) -D $@ > $@.txt
+
+reset.o: reset.s
+	$(AS) -g -mips32 -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+giet.o: $(GIET)/giet.s
+	$(AS) -g -mips32 -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+isr.o: $(GIET)/isr.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+stdio.o: $(GIET)/stdio.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+drivers.o: $(GIET)/drivers.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+main.o: main.c
+	$(CC) $(CFLAGS) -I$(GIET) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+clean:
+	rm -f *.o bin.soft *.txt core *~ proc* term* temp
Index: /trunk/softs/soft_filter_giet/ldscript
===================================================================
--- /trunk/softs/soft_filter_giet/ldscript	(revision 158)
+++ /trunk/softs/soft_filter_giet/ldscript	(revision 158)
@@ -0,0 +1,90 @@
+/**********************************************************
+	File : ldscript 
+	Author : Alain Greiner
+	Date : March 2011  
+**********************************************************/
+
+/* definition of various hardware parameters.
+These variables are referenced in the drivers.c file,
+and must be defined, even if the corresponding
+peripherals are not present in the architecture */
+
+NB_CLUSTERS		= 4;		/* number of clusters */
+NB_PROCS		= 1;		/* number of processors per cluster */
+NB_TASKS		= 1;		/* number of tasks per processor */
+NB_TIMERS       	= 1;		/* max number of timers per processor */
+NB_LOCKS        	= 8;		/* number of spin_locks */
+
+/* definition of the base address for all segments 
+The peripherals base addresses are referenced by the
+software drivers and must be defined, even if the 
+peripherals are not present in the architecture */
+
+seg_code_base   = 0x00000000;       /* le code utilisateur */ 
+seg_data_base   = 0x00100000;       /* les données utilisateur */
+
+seg_heap_base   = 0x00300000;       /* le tas utilisateur */
+seg_stack_base  = 0x00800000;       /* la pile utilisateur */
+
+seg_kcode_base  = 0x80000000;       /* le code du système */
+seg_kdata_base  = 0x80100000;       /* les donnees du système */
+seg_kunc_base   = 0x80200000;       /* les données non cachées du système */
+
+seg_icu_base    = 0x00F00000;       /* controleur ICU */
+seg_tty_base    = 0x00F10000;       /* controleur TTY */
+seg_dma_base    = 0x00F20000;       /* controleur DMA */
+
+seg_reset_base  = 0xBFC00000;       /* le code de boot */
+seg_fb_base     = 0xBFD00000;       /* controleur FRAME BUFFER */
+seg_ioc_base    = 0xBFF30000;       /* controleur I/O */
+
+seg_timer_base  = 0xBFF40000;       /* controleur TIMER */
+seg_gcd_base    = 0xBFF50000;       /* controleur GCD */
+
+/* Grouping sections into segments */
+
+SECTIONS
+{
+   . = seg_kcode_base;
+   seg_kcode : {
+      *(.giet)
+      *(.switch)
+      *(.drivers)
+      *(.isr)
+   } 
+   . = seg_kdata_base;
+   seg_kdata : {
+      *(.kdata)
+   } 
+   . = seg_kunc_base;
+   seg_kunc : {
+      *(.unckdata)
+   } 
+   . = seg_kdata_base;
+   seg_kdata : {
+      *(.ksave)
+   } 
+   . = seg_code_base;
+   seg_code : {
+      *(.text)
+   } 
+   . = seg_reset_base;
+   seg_reset : {
+      *(.reset)
+   } 
+   . = seg_data_base;
+   seg_data : {
+      *(.rodata)
+      . = ALIGN(4);
+      *(.rodata.*)
+      . = ALIGN(4);
+      *(.data)
+      . = ALIGN(4);
+      *(.sdata)
+      . = ALIGN(4);
+      *(.bss)
+      *(COMMON)
+      *(.sbss)
+   } 
+}
+
Index: /trunk/softs/soft_filter_giet/main.c
===================================================================
--- /trunk/softs/soft_filter_giet/main.c	(revision 158)
+++ /trunk/softs/soft_filter_giet/main.c	(revision 158)
@@ -0,0 +1,415 @@
+#include "stdio.h"
+
+////////////////////////////////////
+// Image parameters
+
+#define PIXEL_SIZE	2
+#define NL		1024
+#define NP		1024
+#define BLOCK_SIZE	1024
+
+#define PRINTF		if(lid==0) tty_printf
+
+#define TA(c,l,p)  (A[c][((NP)*(l))+(p)])
+#define TB(c,p,l)  (B[c][((NL)*(p))+(l)])
+#define TC(c,l,p)  (C[c][((NP)*(l))+(p)])
+#define TD(c,l,p)  (D[c][((NP)*(l))+(p)])
+#define TZ(c,l,p)  (Z[c][((NP)*(l))+(p)])
+
+#define max(x,y) ((x) > (y) ? (x) : (y))
+#define min(x,y) ((x) < (y) ? (x) : (y))
+
+///////////////////////////////////////////
+// tricks to read parameters from ldscript
+///////////////////////////////////////////
+
+struct plaf;
+
+extern struct plaf seg_heap_base;
+extern struct plaf NB_PROCS;
+extern struct plaf NB_CLUSTERS;
+
+/////////////
+void main()
+{
+
+//////////////////////////////////
+// convolution kernel parameters
+// The content of this section is
+// Philips proprietary information.
+///////////////////////////////////
+
+    int	vrange = 17;
+    int	vnorm  = 115;
+    int	vf[35];
+    vf[0]  = 1;
+    vf[1]  = 1;
+    vf[2]  = 2;
+    vf[3]  = 2;
+    vf[4]  = 2;
+    vf[5]  = 2;
+    vf[6]  = 3;
+    vf[7]  = 3;
+    vf[8]  = 3;
+    vf[9]  = 4;
+    vf[10] = 4;
+    vf[11] = 4;
+    vf[12] = 4;
+    vf[13] = 5;
+    vf[14] = 5;
+    vf[15] = 5;
+    vf[16] = 5;
+    vf[17] = 5;
+    vf[18] = 5;
+    vf[19] = 5;
+    vf[20] = 5;
+    vf[21] = 5;
+    vf[22] = 4;
+    vf[23] = 4;
+    vf[24] = 4;
+    vf[25] = 4;
+    vf[26] = 3;
+    vf[27] = 3;
+    vf[28] = 3;
+    vf[29] = 2;
+    vf[30] = 2;
+    vf[31] = 2;
+    vf[32] = 2;
+    vf[33] = 1;
+    vf[34] = 1;
+
+    int hrange = 100;
+    int hnorm  = 201;
+
+    unsigned int date      = 0;
+    unsigned int delta     = 0;
+
+    int c;                                              	// cluster index for loops
+    int l;                                              	// line index for loops
+    int p;                                              	// pixel index for loops
+    int x;                                              	// filter index for loops
+
+    int pid                 = procid();                         // processor id
+    int nprocs              = (int)&NB_PROCS;          		// number of processors per cluster
+    int nclusters           = (int)&NB_CLUSTERS;       		// number of clusters
+    int lid                 = pid%nprocs;                       // local task id
+    int cid                 = pid/nprocs;                       // cluster task id
+    int base                = (unsigned int)&seg_heap_base;     // base address for shared buffers
+    int increment           = (0x80000000 / nclusters) * 2;     // cluster increment
+    int ntasks              = nclusters * nprocs;               // number of tasks
+    int nblocks             = (NP*NL*PIXEL_SIZE)/BLOCK_SIZE;  	// number of blocks per image 
+
+    int lines_per_task      = NL/ntasks;			// number of lines per task
+    int lines_per_cluster   = NL/nclusters;			// number of lines per cluster
+    int pixels_per_task     = NP/ntasks;			// number of columns per task
+    int pixels_per_cluster  = NP/nclusters;			// number of columns per cluster
+
+    int first, last;
+
+    PRINTF("\n*** Processor %d entering main at cycle %d ***\n\n", pid, proctime());
+    
+    //////////////////////////
+    //  parameters checking
+    if( (nprocs != 1) && (nprocs != 2) && (nprocs != 4) )
+    {
+        PRINTF("NB_PROCS must be 1, 2 or 4\n");
+        while(1);
+    }
+    if( (nclusters !=  4) && (nclusters !=  8) && (nclusters != 16) && 
+        (nclusters != 32) && (nclusters != 64) && (nclusters !=128) && (nclusters != 256) )
+    {
+        PRINTF("NB_CLUSTERS must be a power of 2 between 4 and 256\n");
+        while(1);
+    }
+    if( pid >= ntasks )
+    {
+        PRINTF("processor id %d larger than NB_CLUSTERS*NB_PROCS\n", pid);
+        while(1);
+    }
+    if ( NL % nclusters != 0 )
+    {
+        PRINTF("NB_CLUSTERS must be a divider of NL");
+        while(1);
+    }
+    if( NP % nclusters != 0 )
+    {
+        PRINTF("NB_CLUSTERS must be a divider of NP");
+        while(1);
+    }
+
+    //////////////////////////////////////////////////////////////////
+    // Arrays of pointers on the shared, distributed buffers  
+    // containing the images (sized for the worst case : 256 clusters)
+    unsigned short*	A[256];
+    int*		B[256];
+    int*		C[256];
+    int*		D[256];
+    unsigned char*	Z[256];
+    
+    // The shared, distributed buffers addresses are computed
+    // from the seg_heap_base value defined in the ldscript file
+    // and from the cluster increment = 4Gbytes/nclusters.
+    // These arrays of pointers are identical and
+    // replicated in the stack of each task 
+    for( c=0 ; c<nclusters ; c++)
+    {
+        A[c] = (unsigned short*)(base 				+ increment*c);
+        Z[c] = (unsigned char*)	(base + 2*NP*NL/nclusters 	+ increment*c);
+        B[c] = (int*)		(base + 4*NP*NL/nclusters 	+ increment*c);
+        C[c] = (int*)		(base + 8*NP*NL/nclusters 	+ increment*c);
+        D[c] = (int*)		(base + 12*NP*NL/nclusters 	+ increment*c);
+    }
+
+    PRINTF("NCLUSTERS = %d\n", nclusters); 
+    PRINTF("NPROCS    = %d\n\n", nprocs); 
+
+    PRINTF("*** Starting barrier init at cycle %d ***\n", proctime());
+
+    //  barriers initialization
+    barrier_init(0, ntasks);
+    barrier_init(1, ntasks);
+    barrier_init(2, ntasks);
+
+    PRINTF("*** Completing barrier init at cycle %d ***\n", proctime());
+
+    ////////////////////////////////////////////////////////
+    // pseudo parallel load from disk to A[c] buffers
+    // only task running on processor with (lid==0) does it
+    // nblocks/nclusters are loaded in each cluster
+
+    if ( lid == 0 )
+    {
+        delta = proctime() - date;
+        date  = date + delta;
+        PRINTF("\n*** Starting load at cycle %d (%d)\n", date, delta);
+
+        if( ioc_read(nblocks*cid/nclusters, 
+                     A[cid] , 
+                     nblocks/nclusters) )
+        {
+            PRINTF("echec ioc_read\n");
+            while(1);
+        }
+        if ( ioc_completed() )
+        {
+            PRINTF("echec ioc_completed\n");
+            while(1);
+        }
+
+        delta = proctime() - date;
+        date  = date + delta;
+        PRINTF("*** Completing load at cycle %d (%d)\n", date, delta);
+    }
+
+    barrier_wait(0);
+
+    //////////////////////////////////////////////////////////
+    // parallel horizontal filter : 
+    //  B <= transpose(FH(A))
+    //  D <= A - FH(A)
+    // Each task computes (NL/ntasks) lines 
+    // The image must be extended :
+    // if (z<0) 	TA(cid,l,z) == TA(cid,l,0)
+    // if (z>NP-1)	TA(cid,l,z) == TA(cid,l,NP-1)
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("\n*** Starting horizontal filter at cycle %d (%d)\n", date, delta);
+
+    // l = absolute line index / p = absolute pixel index  
+    // first & last define which lines are handled by a given task(cid,lid)
+
+    first = (cid*nprocs + lid)*lines_per_task;
+    last  = first + lines_per_task;
+
+    for ( l=first ; l<last ; l++)
+    {
+        // src_c and src_l are the cluster index and the line index for A & D
+        int src_c = l/lines_per_cluster;
+        int src_l = l%lines_per_cluster;
+
+        // We use the spécific values of the horizontal ep-filter for optimisation:
+        // sum(p) = sum(p-1) + TA[p+hrange] - TA[p-hrange-1]
+        // To minimize the number of tests, the loop on pixels is split in three domains 
+
+        int sum = (hrange+2)*TA(src_c, src_l, 0);
+        for ( x = 1 ; x < hrange ; x++) sum = sum + TA(src_c, src_l, x);
+
+        // first domain : from 0 to hrange
+        for ( p=0 ; p<hrange+1 ; p++)
+        {
+            // dst_c and dst_p are the cluster index and the pixel index for B
+            int dst_c = p/pixels_per_cluster;
+            int dst_p = p%pixels_per_cluster;
+            sum = sum + (int)TA(src_c, src_l, p+hrange) - (int)TA(src_c, src_l, 0);
+            TB(dst_c, dst_p, l) = sum/hnorm;
+            TD(src_c, src_l, p) = (int)TA(src_c, src_l, p) - sum/hnorm;
+        }
+        // second domain : from (hrange+1) to (NP-hrange-1)
+        for ( p = hrange+1 ; p < NP-hrange ; p++)
+        {
+            // dst_c and dst_p are the cluster index and the pixel index for B
+            int dst_c = p/pixels_per_cluster;
+            int dst_p = p%pixels_per_cluster;
+            sum = sum + (int)TA(src_c, src_l, p+hrange) - (int)TA(src_c, src_l, p-hrange-1);
+            TB(dst_c, dst_p, l) = sum/hnorm;
+            TD(src_c, src_l, p) = (int)TA(src_c, src_l, p) - sum/hnorm;
+        }
+        // third domain : from (NP-hrange) to (NP-1)
+        for ( p = NP-hrange ; p < NP ; p++)
+        {
+            // dst_c and dst_p are the cluster index and the pixel index for B
+            int dst_c = p/pixels_per_cluster;
+            int dst_p = p%pixels_per_cluster;
+            sum = sum + (int)TA(src_c, src_l, NP-1) - (int)TA(src_c, src_l, p-hrange-1);
+            TB(dst_c, dst_p, l) = sum/hnorm;
+            TD(src_c, src_l, p) = (int)TA(src_c, src_l, p) - sum/hnorm;
+        }
+
+        PRINTF(" - line %d computed at cycle %d\n", l, proctime());
+    }
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("*** Completing horizontal filter at cycle %d (%d)\n", date, delta);
+
+    barrier_wait(1);
+
+    //////////////////////////////////////////////////////////
+    // parallel vertical filter : 
+    // C <= transpose(FV(B))
+    // Each task computes (NP/ntasks) columns
+    // The image must be extended :
+    // if (l<0) 	TB(cid,p,x) == TB(cid,p,0)
+    // if (l>NL-1)	TB(cid,p,x) == TB(cid,p,NL-1)
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("\n*** starting vertical filter at cycle %d (%d)\n", date, delta);
+
+    // l = absolute line index / p = absolute pixel index
+    // first & last define which pixels are handled by a given task(cid,lid)
+
+    first = (cid*nprocs + lid)*pixels_per_task;
+    last  = first + pixels_per_task;
+
+    for ( p=first ; p<last ; p++)
+    {
+        // src_c and src_p are the cluster index and the pixel index for B
+        int src_c = p/pixels_per_cluster;
+        int src_p = p%pixels_per_cluster;
+
+        for ( l=0 ; l<NL ; l++ )
+        {
+            // dst_c and dst_l are the cluster index and the line index for C
+            int dst_c = l/lines_per_cluster;
+            int dst_l = l%lines_per_cluster;
+
+            int sum = 0;
+            for ( x=0 ; x<(2*vrange + 1) ; x++ )
+            {
+                int     z;
+                if      ( (l-vrange+x) < 0 )            z = 0;
+                else if ( (l-vrange+x) > (NL-1) )       z = NL-1;
+                else                                    z = l-vrange+x;
+                sum = sum + vf[x]*TB(src_c, src_p, z);
+            }
+            TC(dst_c, dst_l, p) = sum/vnorm;
+        }
+
+/**********************************************************************************
+        // We use the specific values of the vertical ep-filter
+        // To minimize the number of tests, the NL lines are split in three domains 
+
+        int sum = 0;
+ 
+        // first domain
+        for ( l = 0 ; l < vrange ; l++)
+        {
+            // dst_c and dst_l are the cluster index and the line index for C
+            int dst_c = l/lines_per_cluster;
+            int dst_l = l%lines_per_cluster;
+
+            for ( x = 0 ; x < (2*vrange+1) ; x++ )
+            {
+                sum = sum + vf[x] * TB(src_c, src_p, max(l-vrange+x,0));
+            }
+            TC(dst_c, dst_l, p) = sum/vnorm;
+        }
+        // second domain
+        for ( l = vrange ; l < NL-vrange ; l++ )
+        {
+            // dst_c and dst_l are the cluster index and the line index for C
+            int dst_c = l/lines_per_cluster;
+            int dst_l = l%lines_per_cluster;
+
+            sum = sum + TB(src_c, src_p, l+4)
+                      + TB(src_c, src_p, l+8)
+                      + TB(src_c, src_p, l+11)
+                      + TB(src_c, src_p, l+15)
+                      + TB(src_c, src_p, l+17)
+                      - TB(src_c, src_p, l-5)
+                      - TB(src_c, src_p, l-9)
+                      - TB(src_c, src_p, l-12)
+                      - TB(src_c, src_p, l-16)
+                      - TB(src_c, src_p, max(l-18,0));
+            TC(dst_c, dst_l, p) = sum/vnorm;
+        }
+        // third domain
+        for ( l = NL-vrange ; l < NL ; l++ )
+        {
+            // dst_c and dst_l are the cluster index and the line index for C
+            int dst_c = l/lines_per_cluster;
+            int dst_l = l%lines_per_cluster;
+
+            sum = sum + TB(src_c, src_p, min(l+5,NL-1))
+                      + TB(src_c, src_p, min(l+9,NL-1))
+                      + TB(src_c, src_p, min(l+12,NL-1))
+                      + TB(src_c, src_p, min(l+16,NL-1))
+                      + TB(src_c, src_p, min(l+18,NL-1))
+                      - TB(src_c, src_p, l-4)
+                      - TB(src_c, src_p, l-8)
+                      - TB(src_c, src_p, l-11)
+                      - TB(src_c, src_p, l-15)
+                      - TB(src_c, src_p, l-17);
+            TC(dst_c, dst_l, p) = sum/vnorm;
+        }
+*****************************************************************************/
+
+        PRINTF(" - column %d computed at cycle %d\n", p, proctime());
+    }
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("*** Completing vertical filter at cycle %d (%d)\n", date, delta);
+
+    barrier_wait(2);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // final computation and parallel display using the distributed DMA
+    // D <= D + C
+    // Each processor use its private DMA channel to display 
+    // the resulting image, line  per line (one byte per pixel).
+    // Eah processor computes & displays (NL/ntasks) lines. 
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("\n*** Starting display at cycle %d (%d)\n", date, delta);
+
+    for ( l = 0 ; l < lines_per_task ; l++)
+    {
+        for ( p = 0 ; p < NP ; p++)
+        {
+           TZ(cid,l,p) = (unsigned char)(((TD(cid,l,p) + TC(cid,l,p))>>8) & 0xFF);
+        }
+        fb_write(NP*(cid*lines_per_cluster+lid*lines_per_task+l), &TZ(cid,l,0), NP);
+    }
+
+    delta = proctime() - date;
+    date  = date + delta;
+    PRINTF("*** Completing display at cycle %d (%d)\n", date, delta);
+
+    while(1);
+
+} // end main()
+
Index: /trunk/softs/soft_filter_giet/reset.s
===================================================================
--- /trunk/softs/soft_filter_giet/reset.s	(revision 158)
+++ /trunk/softs/soft_filter_giet/reset.s	(revision 158)
@@ -0,0 +1,135 @@
+#################################################################################
+#	File : reset.s
+#	Author : Alain Greiner
+#	Date : 15/04/2011
+#################################################################################
+# 	This is a boot code for a generic multi-clusters / multi-processors
+#       TSAR architecture (up to 256 clusters / up to 4  processors per cluster). 
+#       There is one XICU, one TTY, one DMA and one stack segment per cluster.
+#       segment base adresses = base + cluster_segment_increment*cluster_id
+#	- Each processor initializes the stack pointer ($29) depending on pid.
+#	- Only processor 0 initializes the Interrupt vector (TTY, DMA & IOC).
+#       - Each processor initialises its private ICU mask register.
+#	- Each processor initializes the Status Register (SR) 
+#	- Each processor initializes the EPC register, and jumps to the main 
+#	  address in kernel mode...
+#################################################################################
+		
+	.section .reset,"ax",@progbits
+
+	.extern	seg_stack_base
+	.extern	seg_icu_base
+	.extern _interrupt_vector
+	.extern _isr_tty_get
+	.extern _isr_dma
+	.extern _isr_ioc
+
+        .extern NB_PROCS
+        .extern NB_CLUSTERS
+
+	.globl  reset	 			# makes reset an external symbol 
+	.ent	reset
+	.align	2
+
+reset:
+       	.set noreorder
+
+# computes proc_id, local_id, cluster_id, and cluster_increment
+    mfc0    $26,    $15,    1
+    andi    $10,    $26,    0x3FF	# $10 <= proc_id (at most 1024 processors)
+    la      $26,    NB_PROCS		# $26 <= number of processors per cluster
+    divu    $10,    $26
+    mfhi    $11                 	# $11 <= local_id = proc_id % NB_PROCS
+    mflo    $12              		# $12 <= cluster_id = proc_id / NB_PROCS
+    la      $26,    NB_CLUSTERS
+    li      $13,    0x80000000
+    divu    $13,    $26
+    mflo    $14
+    sll     $14,    1			# $14 <= cluster_increment = 4G / NB_CLUSTERS
+    mult    $14,    $12	
+    mflo    $13                 	# $13 <= cluster_id * cluster_increment
+
+# initializes stack pointer depending on both the local_id and the cluster_id
+    la      $27,    seg_stack_base
+    addu    $27,    $27,    $13		# $27 <= seg_stack_base + cluster_id * increment
+    li      $26,    0x10000		# $26 <= 64K
+    addi    $25,    $11,    1		# $25 <= local_id + 1
+    mult    $25,    $26
+    mflo    $24				# $24 <= 64K * (local_id+1)
+    addu    $29,    $27,    $24		# $29 <= seg_stack_base + (cluster_id*increment) + (local_id+1)*64K
+
+# in each cluster, each processor initializes its private XICU mask register
+# in each cluster, the ICU base address depends on the cluster_id
+    la      $20,    seg_icu_base
+    addu    $20,    $20,    $13		# $20 <= seg_icu_base + cluster_id*cluster_increment
+    la      $21,    _reset_switch
+    sll     $22,    $11,    2           # $22 <= local_id*4
+    addu    $23,    $21,    $22         # $23 <= &_reset_switch[local_id*4]
+    lw      $24,    0($23)
+    jr      $24
+    nop
+_reset_proc0:
+    li      $13,    0b010010000000      # offset for MSK_HWI_ENABLE & proc[0]
+    addu    $13,    $20,    $13
+    li      $27,    0x111		# TTY[0] DMA[0] IOC
+    sw      $27,    0($13)              # MASK[0]
+    j       _reset_itvector
+_reset_proc1:
+    li      $13,    0b010010000100      # offset for MSK_HWI_ENABLE & proc[1]
+    addu    $13,    $20,    $13
+    li      $27,    0x022		# TTY[1] DMA[1]
+    sw      $27,    0($13)              # MASK[1]
+    j       _reset_itvector
+_reset_proc2:
+    li      $13,    0b010010001000      # offset for MSK_HWI_ENABLE & proc[2]
+    addu    $13,    $20,    $13
+    li      $27,    0x044		# TTY[2] DMA[2]
+    sw      $27,    0($13)              # MASK[2]
+    j       _reset_itvector
+_reset_proc3:
+    li      $13,    0b010010001100      # offset for MSK_HWI_ENABLE & proc[3]
+    addu    $13,    $20,    $13
+    li      $27,    0x088		# TTY[3] DMA[3]
+    sw      $27,    0($13)              # MASK[3]
+    j       _reset_itvector
+    nop
+
+_reset_switch:
+    .word	_reset_proc0
+    .word	_reset_proc1
+    .word	_reset_proc2
+    .word	_reset_proc3
+
+# only processor 0 in cluster 0 initializes interrupt vector
+
+_reset_itvector:
+    bne	    $10,    $0,    _reset_end
+    nop
+    la      $26,    _interrupt_vector   # interrupt vector address
+    la      $27,    _isr_tty_get 
+    sw      $27,    0($26)              # interrupt_vector[0] <= _isr_tty_get
+    sw      $27,    4($26)              # interrupt_vector[1] <= _isr_tty_get
+    sw      $27,    8($26)              # interrupt_vector[2] <= _isr_tty_get
+    sw      $27,   12($26)              # interrupt_vector[3] <= _isr_tty_get
+    la      $27,    _isr_dma 
+    sw      $27,   16($26)              # interrupt_vector[4] <= _isr_dma
+    sw      $27,   20($26)              # interrupt_vector[5] <= _isr_dma
+    sw      $27,   24($26)              # interrupt_vector[6] <= _isr_dma
+    sw      $27,   28($26)              # interrupt_vector[7] <= _isr_dma
+    la      $27,    _isr_ioc 
+    sw      $27,   32($26)              # interrupt_vector[8] <= _isr_ioc
+
+_reset_end:
+
+# initializes SR register
+    li	    $26,    0x0000FF01		
+    mtc0    $26,    $12			# SR <= kernel mode / IRQ enable 
+
+# jumps to main in kernel mode
+    la	    $26,    main
+    jr      $26
+    nop
+
+    .end	reset
+
+    .set reorder
Index: /trunk/softs/soft_transpose_giet/Makefile
===================================================================
--- /trunk/softs/soft_transpose_giet/Makefile	(revision 158)
+++ /trunk/softs/soft_transpose_giet/Makefile	(revision 158)
@@ -0,0 +1,46 @@
+LD=mipsel-unknown-elf-ld
+CC=mipsel-unknown-elf-gcc
+AS=mipsel-unknown-elf-as
+DU=mipsel-unknown-elf-objdump
+
+OBJS=   reset.o \
+	giet.o \
+	isr.o \
+	drivers.o \
+	stdio.o \
+	main.o
+
+CFLAGS= -Wall -mno-gpopt -ffreestanding -fomit-frame-pointer -mips32 -ggdb
+
+GIET=	/Users/alain/soc/tsar-svn-june-2010/softs/giet_tsar
+
+bin.soft: $(OBJS) ldscript
+	$(LD) -o $@ -T ldscript $(OBJS)
+	$(DU) -D $@ > $@.txt
+
+reset.o: reset.s
+	$(AS) -g -mips32 -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+giet.o: $(GIET)/giet.s
+	$(AS) -g -mips32 -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+isr.o: $(GIET)/isr.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+stdio.o: $(GIET)/stdio.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+drivers.o: $(GIET)/drivers.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+main.o: main.c
+	$(CC) $(CFLAGS) -I$(GIET) -c -o $@ $<
+	$(DU) -D $@ > $@.txt
+
+clean:
+	rm -f *.o bin.soft *.txt core *~ proc* term* temp
Index: /trunk/softs/soft_transpose_giet/ldscript
===================================================================
--- /trunk/softs/soft_transpose_giet/ldscript	(revision 158)
+++ /trunk/softs/soft_transpose_giet/ldscript	(revision 158)
@@ -0,0 +1,90 @@
+/**********************************************************
+	File : ldscript 
+	Author : Alain Greiner
+	Date : March 2011  
+**********************************************************/
+
+/* definition of various hardware parameters.
+These variables are referenced in the drivers.c file,
+and must be defined, even if the corresponding
+peripherals are not present in the architecture */
+
+NB_CLUSTERS		= 4;		/* number of clusters */
+NB_PROCS		= 4;		/* number of processors per cluster */
+NB_TASKS		= 1;		/* number of tasks per processor */
+NB_TIMERS       	= 1;		/* max number of timers per processor */
+NB_LOCKS        	= 8;		/* number of spin_locks */
+
+/* definition of the base address for all segments 
+The peripherals base addresses are referenced by the
+software drivers and must be defined, even if the 
+peripherals are not present in the architecture */
+
+seg_code_base   = 0x00000000;       /* le code utilisateur */ 
+seg_data_base   = 0x00100000;       /* les données utilisateur */
+
+seg_heap_base   = 0x00300000;       /* le tas utilisateur */
+seg_stack_base  = 0x00800000;       /* la pile utilisateur */
+
+seg_kcode_base  = 0x80000000;       /* le code du système */
+seg_kdata_base  = 0x80100000;       /* les donnees du système */
+seg_kunc_base   = 0x80200000;       /* les données non cachées du système */
+
+seg_icu_base    = 0x00F00000;       /* controleur ICU */
+seg_tty_base    = 0x00F10000;       /* controleur TTY */
+seg_dma_base    = 0x00F20000;       /* controleur DMA */
+
+seg_reset_base  = 0xBFC00000;       /* le code de boot */
+seg_fb_base     = 0xBFD00000;       /* controleur FRAME BUFFER */
+seg_ioc_base    = 0xBFF30000;       /* controleur I/O */
+
+seg_timer_base  = 0xBFF40000;       /* controleur TIMER */
+seg_gcd_base    = 0xBFF50000;       /* controleur GCD */
+
+/* Grouping sections into segments */
+
+SECTIONS
+{
+   . = seg_kcode_base;
+   seg_kcode : {
+      *(.giet)
+      *(.switch)
+      *(.drivers)
+      *(.isr)
+   } 
+   . = seg_kdata_base;
+   seg_kdata : {
+      *(.kdata)
+   } 
+   . = seg_kunc_base;
+   seg_kunc : {
+      *(.unckdata)
+   } 
+   . = seg_kdata_base;
+   seg_kdata : {
+      *(.ksave)
+   } 
+   . = seg_code_base;
+   seg_code : {
+      *(.text)
+   } 
+   . = seg_reset_base;
+   seg_reset : {
+      *(.reset)
+   } 
+   . = seg_data_base;
+   seg_data : {
+      *(.rodata)
+      . = ALIGN(4);
+      *(.rodata.*)
+      . = ALIGN(4);
+      *(.data)
+      . = ALIGN(4);
+      *(.sdata)
+      . = ALIGN(4);
+      *(.bss)
+      *(COMMON)
+      *(.sbss)
+   } 
+}
+
Index: /trunk/softs/soft_transpose_giet/main.c
===================================================================
--- /trunk/softs/soft_transpose_giet/main.c	(revision 158)
+++ /trunk/softs/soft_transpose_giet/main.c	(revision 158)
@@ -0,0 +1,188 @@
+#include "stdio.h"
+
+#define NL		128
+#define NP		128
+#define NB_IMAGES	2
+#define BLOCK_SIZE	128 
+
+#define PRINTF		if(local_id == 0) tty_printf
+
+///////////////////////////////////////////
+// tricks to read parameters from ldscript
+///////////////////////////////////////////
+
+struct plaf;
+
+extern struct plaf seg_heap_base;
+extern struct plaf NB_PROCS;
+extern struct plaf NB_CLUSTERS;
+
+/////////////
+void main()
+{
+    unsigned int 	image     = 0;
+    unsigned int 	date      = 0;
+    unsigned int 	delta     = 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	nprocs 	    = (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%nprocs;			// local processor id
+    unsigned int        cluster_id  = proc_id/nprocs;			// 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	ntasks	    = nclusters * nprocs;		// number of tasks
+    unsigned int	nblocks     = (NP*NL) / BLOCK_SIZE;		// number of blocks per image 
+
+    PRINTF("\n *** Entering main at cycle %d ***\n\n", proctime());
+
+    //  parameters checking
+    if( (nprocs != 1) && (nprocs != 2) && (nprocs != 4) )
+    {
+        PRINTF("NB_PROCS 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) )
+    {
+        PRINTF("NB_CLUSTERS must be a power of 2 between 1 and 128\n");
+        exit();
+    }
+    if( ntasks > 128 )
+    {
+        PRINTF("NB_PROCS * NB_CLUSTERS cannot be larger than 128 4\n");
+        exit();
+    }
+    if( proc_id >= ntasks )
+    {
+        PRINTF("processor id %d larger than NB_CLUSTERS*NB_PROCS\n", proc_id);
+    }
+
+    // Arrays of pointers on the shared, distributed buffers  
+    // containing the images (sized for the worst case : 128 clusters)
+    unsigned char*	A[128];
+    unsigned char*	B[128];
+    
+    // shared buffers address definition 
+    // from the seg_heap_base and segment_increment 
+    // values defined in the ldscript file.
+    // 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 + NL*NP + increment*c);
+    }
+
+    PRINTF("NB_CLUSTERS = %d\n", nclusters); 
+    PRINTF("NB_PROCS    = %d\n\n", nprocs); 
+
+    PRINTF("*** starting barrier init at cycle %d ***\n", proctime());
+
+    //  barriers initialization
+    barrier_init(0, ntasks);
+    barrier_init(1, ntasks);
+    barrier_init(2, ntasks);
+
+    PRINTF("*** completing barrier init at cycle %d ***\n", proctime());
+
+    // Main loop (on images)
+    while(image < 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
+
+        delta = proctime() - date;
+        date  = date + delta;
+
+        if ( local_id == 0 )
+        {
+            PRINTF("\n*** Starting load for image %d *** at cycle %d (%d)\n", image, date, delta);
+
+            if( ioc_read(image*nblocks + nblocks*cluster_id/nclusters , A[cluster_id], nblocks/nclusters) )
+            {
+                tty_printf("echec ioc_read\n");
+                exit();
+            }
+            if ( ioc_completed() )
+            {
+                tty_printf("echec ioc_completed\n");
+                exit();
+            }
+            delta = proctime() - date;
+            date  = date + delta;
+            PRINTF("*** Completing load for image %d *** at cycle %d (%d)\n", image, date, delta);
+        }
+
+        barrier_wait(0);
+
+        // parallel transpose from A to B buffers
+	// each processor makes the transposition for (NL/ntasks) lines
+        // (p,l) are the (x,y) pixel coordinates in the source image
+
+        delta = proctime() - date;
+        date  = date + delta;
+
+        PRINTF("\n*** Starting transpose for image %d at cycle %d (%d)\n", image, date, delta);
+
+        unsigned int nlt 	= NL/ntasks;
+        unsigned int first 	= (cluster_id*nprocs + local_id)*nlt;
+        unsigned int last 	= first + nlt;
+
+        for ( l=first ; l<last ; l++)
+        {
+            PRINTF( "    - processing line %d\n", l);
+            for ( p=0 ; p<NP ; p++)
+            {
+                unsigned int source_cluster = l/(NL/nclusters);
+                unsigned int source_index   = (l%(NL/nclusters))*NP + p;
+                unsigned int dest_cluster   = p / (NP/nclusters);
+                unsigned int dest_index     = (p%(NP/nclusters))*NL + l;
+                B[dest_cluster][dest_index] = A[source_cluster][source_index];
+            }
+
+        }
+        delta = proctime() - date;
+        date  = date + delta;
+        PRINTF("*** Completing transpose for image %d *** at cycle %d (%d)\n", image, date, delta);
+
+        barrier_wait(1);
+
+        // parallel display from B[c] to frame buffer 
+        // each processor uses its private dma to display NL*NP/ntasks pixels
+
+        delta = proctime() - date;
+        date  = date + delta;
+
+        PRINTF("\n*** Starting display for image %d at cycle %d (%d)\n", image, date, delta);
+
+        unsigned int npxt = NL*NP/ntasks;	// number of pixels per task
+
+        if ( fb_write(npxt*proc_id, B[cluster_id] + npxt*local_id, npxt) )
+        {
+            PRINTF("echec fb_sync_write\n");
+            exit();
+        }
+        if ( fb_completed() )
+        {
+            PRINTF("echec fb_completed\n");
+            exit();
+        }
+
+        delta = proctime() - date;
+        date  = date + delta;
+        PRINTF("*** Completing display for image %d at cycle %d (%d)\n", image, date, delta);
+
+        barrier_wait(2);
+
+        // next image
+        image++;
+    } // end while image      
+    while(1);
+} // end main()
+
Index: /trunk/softs/soft_transpose_giet/reset.s
===================================================================
--- /trunk/softs/soft_transpose_giet/reset.s	(revision 158)
+++ /trunk/softs/soft_transpose_giet/reset.s	(revision 158)
@@ -0,0 +1,135 @@
+#################################################################################
+#	File : reset.s
+#	Author : Alain Greiner
+#	Date : 15/04/2011
+#################################################################################
+# 	This is a boot code for a generic multi-clusters / multi-processors
+#       TSAR architecture (up to 256 clusters / up to 4  processors per cluster). 
+#       There is one XICU, one TTY, one DMA and one stack segment per cluster.
+#       segment base adresses = base + cluster_segment_increment*cluster_id
+#	- Each processor initializes the stack pointer ($29) depending on pid.
+#	- Only processor 0 initializes the Interrupt vector (TTY, DMA & IOC).
+#       - Each processor initialises its private ICU mask register.
+#	- Each processor initializes the Status Register (SR) 
+#	- Each processor initializes the EPC register, and jumps to the main 
+#	  address in kernel mode...
+#################################################################################
+		
+	.section .reset,"ax",@progbits
+
+	.extern	seg_stack_base
+	.extern	seg_icu_base
+	.extern _interrupt_vector
+	.extern _isr_tty_get
+	.extern _isr_dma
+	.extern _isr_ioc
+
+        .extern NB_PROCS
+        .extern NB_CLUSTERS
+
+	.globl  reset	 			# makes reset an external symbol 
+	.ent	reset
+	.align	2
+
+reset:
+       	.set noreorder
+
+# computes proc_id, local_id, cluster_id, and cluster_increment
+    mfc0    $26,    $15,    1
+    andi    $10,    $26,    0x3FF	# $10 <= proc_id (at most 1024 processors)
+    la      $26,    NB_PROCS		# $26 <= number of processors per cluster
+    divu    $10,    $26
+    mfhi    $11                 	# $11 <= local_id = proc_id % NB_PROCS
+    mflo    $12              		# $12 <= cluster_id = proc_id / NB_PROCS
+    la      $26,    NB_CLUSTERS
+    li      $13,    0x80000000
+    divu    $13,    $26
+    mflo    $14
+    sll     $14,    1			# $14 <= cluster_increment = 4G / NB_CLUSTERS
+    mult    $14,    $12	
+    mflo    $13                 	# $13 <= cluster_id * cluster_increment
+
+# initializes stack pointer depending on both the local_id and the cluster_id
+    la      $27,    seg_stack_base
+    addu    $27,    $27,    $13		# $27 <= seg_stack_base + cluster_id * increment
+    li      $26,    0x10000		# $26 <= 64K
+    addi    $25,    $11,    1		# $25 <= local_id + 1
+    mult    $25,    $26
+    mflo    $24				# $24 <= 64K * (local_id+1)
+    addu    $29,    $27,    $24		# $29 <= seg_stack_base + (cluster_id*increment) + (local_id+1)*64K
+
+# in each cluster, each processor initializes its private XICU mask register
+# in each cluster, the ICU base address depends on the cluster_id
+    la      $20,    seg_icu_base
+    addu    $20,    $20,    $13		# $20 <= seg_icu_base + cluster_id*cluster_increment
+    la      $21,    _reset_switch
+    sll     $22,    $11,    2           # $22 <= local_id*4
+    addu    $23,    $21,    $22         # $23 <= &_reset_switch[local_id*4]
+    lw      $24,    0($23)
+    jr      $24
+    nop
+_reset_proc0:
+    li      $13,    0b010010000000      # offset for MSK_HWI_ENABLE & proc[0]
+    addu    $13,    $20,    $13
+    li      $27,    0x111		# TTY[0] DMA[0] IOC
+    sw      $27,    0($13)              # MASK[0]
+    j       _reset_itvector
+_reset_proc1:
+    li      $13,    0b010010000100      # offset for MSK_HWI_ENABLE & proc[1]
+    addu    $13,    $20,    $13
+    li      $27,    0x022		# TTY[1] DMA[1]
+    sw      $27,    0($13)              # MASK[1]
+    j       _reset_itvector
+_reset_proc2:
+    li      $13,    0b010010001000      # offset for MSK_HWI_ENABLE & proc[2]
+    addu    $13,    $20,    $13
+    li      $27,    0x044		# TTY[2] DMA[2]
+    sw      $27,    0($13)              # MASK[2]
+    j       _reset_itvector
+_reset_proc3:
+    li      $13,    0b010010001100      # offset for MSK_HWI_ENABLE & proc[3]
+    addu    $13,    $20,    $13
+    li      $27,    0x088		# TTY[3] DMA[3]
+    sw      $27,    0($13)              # MASK[3]
+    j       _reset_itvector
+    nop
+
+_reset_switch:
+    .word	_reset_proc0
+    .word	_reset_proc1
+    .word	_reset_proc2
+    .word	_reset_proc3
+
+# only processor 0 in cluster 0 initializes interrupt vector
+
+_reset_itvector:
+    bne	    $10,    $0,    _reset_end
+    nop
+    la      $26,    _interrupt_vector   # interrupt vector address
+    la      $27,    _isr_tty_get 
+    sw      $27,    0($26)              # interrupt_vector[0] <= _isr_tty_get
+    sw      $27,    4($26)              # interrupt_vector[1] <= _isr_tty_get
+    sw      $27,    8($26)              # interrupt_vector[2] <= _isr_tty_get
+    sw      $27,   12($26)              # interrupt_vector[3] <= _isr_tty_get
+    la      $27,    _isr_dma 
+    sw      $27,   16($26)              # interrupt_vector[4] <= _isr_dma
+    sw      $27,   20($26)              # interrupt_vector[5] <= _isr_dma
+    sw      $27,   24($26)              # interrupt_vector[6] <= _isr_dma
+    sw      $27,   28($26)              # interrupt_vector[7] <= _isr_dma
+    la      $27,    _isr_ioc 
+    sw      $27,   32($26)              # interrupt_vector[8] <= _isr_ioc
+
+_reset_end:
+
+# initializes SR register
+    li	    $26,    0x0000FF01		
+    mtc0    $26,    $12			# SR <= kernel mode / IRQ enable 
+
+# jumps to main in kernel mode
+    la	    $26,    main
+    jr      $26
+    nop
+
+    .end	reset
+
+    .set reorder
