Index: soft/giet_vm/sys/irq_handler.c
===================================================================
--- soft/giet_vm/sys/irq_handler.c	(revision 169)
+++ soft/giet_vm/sys/irq_handler.c	(revision 189)
@@ -2,11 +2,11 @@
 // File     : irq_handler.c
 // Date     : 01/04/2012
-// Author   : alain greiner and joel porquet
+// Author   : alain greiner 
 // Copyright (c) UPMC-LIP6
 ///////////////////////////////////////////////////////////////////////////////////
-// The irq_handler.c and irq_handler.h files are part of the GIET nano-kernel.
-// They contain the code of the _int_demux function that handle
-// the ICU (Interupt Controler Unit), and the various ISRs associated
-// to the CoCLib peripherals. 
+// The irq_handler.c and irq_handler.h files are part of the GIET-VM nano-kernel.
+// They contain the code of the _irq_demux() function that access the XICU or
+// ICU component (Interupt Controler Unit), and the various ISRs (Interrupt
+// Service Routine) associated to the peripherals. 
 ///////////////////////////////////////////////////////////////////////////////////
 
@@ -20,103 +20,105 @@
 
 ///////////////////////////////////////////////////////////////////////////////////
-// Initialize the whole interrupt vector with the default ISR
-///////////////////////////////////////////////////////////////////////////////////
-
-__attribute__((section (".kdata"))) _isr_func_t _interrupt_vector[32] = 
-                                                  { [0 ... 31] = &_isr_default };
-
-///////////////////////////////////////////////////////////////////////////////////
-// 	_int_demux()
-// This functions uses an external ICU component (Interrupt Controler Unit)
-// that concentrates up to 32 input interrupts lines. This component
-// can support up to NB_PROCS output IRQ.
+// 	_irq_demux()
+// This function uses the ICU or XICU component (Interrupt Controler Unit)
+// to get the interrupt vector entry. There is one ICU or XICU component per
+// cluster, and this component can support up to NB_PROCS_MAX output IRQs.
+// It returns the highest priority active interrupt index (smaller
+// indexes have the highest priority).
+// Any value larger than 31 means "no active interrupt", and no ISR is executed.
 //
-// This component returns the highest priority active interrupt index (smaller
-// indexes have the highest priority) by reading the ICU_IT_VECTOR register.
-// Any value larger than 31 means "no active interrupt", and the default ISR
-// (that does nothing) is executed.
+// There is one interrupt vector per processor (stored in the scheduler associated
+// to the processor. Each interrupt vector entry contains two 16 bits fields:
+// - isr_id : defines the type of ISR to be executed.
+// - channel_id : defines the specific channel for multi-channels peripherals.
 //
-// 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 
-// during system initialisation.
-///////////////////////////////////////////////////////////////////////////////////
-void _int_demux(void)
-{
-    int				interrupt_index;
-    _isr_func_t		isr;
-    unsigned int	pid = _procid();
-
-    // retrieves the highest priority active interrupt index 
-    if (!_icu_read( pid / NB_PROCS,
-                    pid % NB_PROCS,
+// If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is 
+// a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id   
+///////////////////////////////////////////////////////////////////////////////////
+void _irq_demux()
+{
+    unsigned int    pid = _procid();
+    unsigned int	irq_id;
+
+    // get the highest priority active IRQ index 
+
+#if GIET_USE_XICU
+
+#else
+
+    if ( _icu_read( pid / NB_PROCS_MAX,
+                    pid % NB_PROCS_MAX,
                     ICU_IT_VECTOR,
-                    (unsigned int*)&interrupt_index ) )
+                    &irq_id ) )
     {
-        if (interrupt_index == -1)	// no interrupt is active 
-            return;
-
-        isr = _interrupt_vector[interrupt_index];
-        isr();
-    }
-    else
-    {
-        _puts("\n[GIET ERROR] In _demux function : wrong arguments in _icu_read()\n");
+        _puts("\n[GIET ERROR] wrong _icu_read in _irq_demux() function\n");
         _exit();
     }
+
+#endif
+
+    if ( irq_id < 32 )	// do nothing if no interrupt active 
+    {
+        unsigned int entry      = _get_interrupt_vector_entry(irq_id);
+        unsigned int isr_id     = entry & 0x000000FF;
+        unsigned int channel_id = (entry>>16) & 0x0000FFFF;
+        if      ( isr_id == ISR_SWITCH  ) _isr_switch();
+        else if ( isr_id == ISR_IOC     ) _isr_ioc();
+        else if ( isr_id == ISR_DMA     ) _isr_dma( channel_id );
+        else if ( isr_id == ISR_TTY     ) _isr_tty( channel_id );
+        else if ( isr_id == ISR_TIMER   ) _isr_timer( channel_id );
+        else                              _isr_default();
+    }
 }
 ///////////////////////////////////////////////////////////////////////////////////
 // 	_isr_default()
 // The default ISR is called when no specific ISR has been installed in the
-// interrupt vector. It simply displays a message on TTY0.
+// interrupt vector. It simply displays a message on kernel TTY[0].
 ///////////////////////////////////////////////////////////////////////////////////
 void _isr_default()
 {
-    _puts("\n\n!!! Default ISR !!!\n");
+    _puts("\n\n!!! Strange... Default ISR activated !!!\n");
 }
 
 ///////////////////////////////////////////////////////////////////////////////////
 // 	_isr_dma()
-// This ISR handles up to 8 IRQs generated by 8 independant channels of the
-// multi_dma component. It acknowledges the interrupt and reset the synchronisation
-// variable _dma_busy[i], after copying the status into the _dma_status[i] variable.
-///////////////////////////////////////////////////////////////////////////////////
-void _isr_dma_indexed( unsigned int dma_id )
-{
-    volatile unsigned int* dma_address;
+// This ISR handles all IRQs generated by the multi-channels DMA controlers.
+// The multi_dma components can be distributed in the clusters.
+// The channel_id argument is the global DMA channel index.
+//     channel_id = cluster_id*NB_DMAS_MAX + loc_id
+// - The ISR saves the transfert status in _dma_status[channel_id].
+// - It acknowledges the interrupt to reinitialize the DMA controler.
+// - it resets the synchronisation variable _dma_busy[channel_id].
+///////////////////////////////////////////////////////////////////////////////////
+void _isr_dma( unsigned int channel_id )
+{
+    // compute cluster_id and loc_id
+    unsigned int cluster_id = channel_id / NB_DMAS_MAX;
+    unsigned int loc_id     = channel_id % NB_DMAS_MAX;
 
     // compute DMA channel address
-    dma_address = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN);
+    unsigned int*	dma_address = (unsigned int*)&seg_dma_base + 
+                                  (loc_id * DMA_SPAN) +
+                                  (cluster_id * CLUSTER_SPAN);
 
     // save DMA channel status  
-    _dma_status[dma_id] = dma_address[DMA_LEN]; /* save status */
+    _dma_status[channel_id] = dma_address[DMA_LEN];
 
     // reset DMA channel
-    dma_address[DMA_RESET] = 0;					/* reset IRQ */
+    dma_address[DMA_RESET] = 0;			
 
     // release DMA channel 
-    _dma_busy[dma_id] = 0;                      /* release DMA */
-}
-
-void _isr_dma_0() { _isr_dma_indexed(0); }
-void _isr_dma_1() { _isr_dma_indexed(1); }
-void _isr_dma_2() { _isr_dma_indexed(2); }
-void _isr_dma_3() { _isr_dma_indexed(3); }
-void _isr_dma_4() { _isr_dma_indexed(4); }
-void _isr_dma_5() { _isr_dma_indexed(5); }
-void _isr_dma_6() { _isr_dma_indexed(6); }
-void _isr_dma_7() { _isr_dma_indexed(7); }
+    _dma_done[channel_id] = 1;  
+}
 
 ///////////////////////////////////////////////////////////////////////////////////
 // 	_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.
+// There is only one IOC controler shared by all tasks. 
+// - The ISR save the status and acknowledge the IRQ.
+// - It sets the _ioc_done variable to signal completion.
 ///////////////////////////////////////////////////////////////////////////////////
 void _isr_ioc()
 {
-    volatile unsigned int* ioc_address;
-
-    ioc_address = (unsigned int*)&seg_ioc_base;
+    unsigned int* ioc_address = (unsigned int*)&seg_ioc_base;
 
     _ioc_status = ioc_address[BLOCK_DEVICE_STATUS]; /* save status & reset IRQ */
@@ -125,88 +127,118 @@
 
 ///////////////////////////////////////////////////////////////////////////////////
-// 	_isr_timer_* (* = 0,1,2,3,4,5,6,7)
-// This ISR handles up to 8 IRQs generated by 8 independant timers.
-// It acknowledges the IRQ on TIMER[*] and displays a message on TTY0
-///////////////////////////////////////////////////////////////////////////////////
-void _isr_timer_indexed(unsigned int timer_id)
-{
-    volatile unsigned int *timer_address;
-
-    timer_address = (unsigned int*)&seg_timer_base + (timer_id * TIMER_SPAN);
-
-    timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */
-
-    _puts("\n\n!!! Interrupt timer received from timer ");
-    _putw( timer_id );
-    _puts(" at cycle ");
-    _putw( _proctime() );
-    _puts("\n\n");
-}
-
-void _isr_timer_0()  { _isr_timer_indexed(0);  }
-void _isr_timer_1()  { _isr_timer_indexed(1);  }
-void _isr_timer_2()  { _isr_timer_indexed(2);  }
-void _isr_timer_3()  { _isr_timer_indexed(3);  }
-void _isr_timer_4()  { _isr_timer_indexed(4);  }
-void _isr_timer_5()  { _isr_timer_indexed(5);  }
-void _isr_timer_6()  { _isr_timer_indexed(6);  }
-void _isr_timer_7()  { _isr_timer_indexed(7);  }
-
-///////////////////////////////////////////////////////////////////////////////////
-// _isr_tty_get_* (* = 0,1,2,3,4,5,6,7,9,10,11,12,13,14,15)
-// The Giet supports up to 16 TTY terminals.
-// These 16 ISRs handle the up to 16 IRQs associated to 16 independant 
-// terminals, signaling that a character is available.
-// There is one communication buffer _tty_get_buf[tty_id] per terminal.
-// The sychronisation variable _tty_get_full[tty_id], is set by the ISR,
+// 	   _isr_timer()
+// This ISR handles the IRQs generated by the "user" timers (the IRQs
+// generated by the "system" timers should be handled by the _isr_switch().
+// These timers are distributed in all clusters, and can be implemented
+// in a vci_multi_timer component, or in a vci_xicu component.
+// The channel_id argument is the global channel index:
+//     channel_id = cluster_id*(NB_TIMERS_MAX+NB_PROCS_MAX) + loc_id 
+// The user timer local index is (loc_id - NB_PROCS_MAX).
+//
+// The ISR acknowledges the IRQ and registers the event in the proper entry
+// of the _timer_event[] array.
+// A log message is displayed on the kernel terminal.
+///////////////////////////////////////////////////////////////////////////////////
+void _isr_timer(unsigned int channel_id)
+{
+
+    unsigned int cluster_id = channel_id / (NB_TIMERS_MAX + NB_PROCS_MAX);
+    unsigned int loc_id     = channel_id % (NB_TIMERS_MAX + NB_PROCS_MAX); 
+
+    if (loc_id < NB_PROCS_MAX )
+    {
+        _puts("[GIET ERROR] Receiving a user timer IRQ for a system timer\n");
+        _puts("             cluster = ");
+        _putw(cluster_id);
+        _puts(" / local_id = ");
+        _putw(loc_id);
+    }
+
+#if GIET_USE_XICU
+
+// TODO
+
+#else
+
+    // compute Timer address
+    unsigned int* timer_address = (unsigned int*)&seg_timer_base +
+                                  (loc_id * TIMER_SPAN) +
+                                  (cluster_id * CLUSTER_SPAN);
+
+    // reset IRQ 
+    timer_address[TIMER_RESETIRQ] = 0;
+
+#endif
+
+#if NB_TIMERS_MAX
+    // register the event
+    _timer_event[(cluster_id*NB_TIMERS_MAX) + (loc_id - NB_PROCS_MAX)] = 1;
+#endif
+
+    // display a message on TTY 0 
+    _puts("[GIET] User Timer IRQ / cluster = ");
+    _putw(cluster_id);
+    _puts(" / timer = ");
+    _putw(loc_id - NB_PROCS_MAX);
+    _puts("\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+//  _isr_tty()
+// This ISR handles the IRQs generated by the multi_tty controler,
+// signaling that a character is available.
+// There is one single multi_tty component controling all TTYs, and the tty_id 
+// argument is the global TTY index.
+// There is one communication buffer _tty_buf[tty_id] per terminal.
+// The sychronisation variable _tty_full[tty_id], is set by the ISR,
 // and reset by the OS.
 // A character is lost if the buffer is full when the ISR is executed.
 ///////////////////////////////////////////////////////////////////////////////////
-void _isr_tty_get_indexed(unsigned int tty_id)
-{
-    volatile unsigned int *tty_address;
-
-    /* compute terminal base address */
-    tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN);
-
-    /* save character and reset IRQ */
+void _isr_tty(unsigned int tty_id)
+{
+    // compute terminal base address 
+    unsigned int *tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN);
+
+    // save character and reset IRQ 
     _tty_get_buf[tty_id] = (unsigned char)tty_address[TTY_READ];
 
-    /* signals character available */
+    // signals character available 
     _tty_get_full[tty_id] = 1;
 }
-
-void _isr_tty_get_0()  { _isr_tty_get_indexed(0);  }
-void _isr_tty_get_1()  { _isr_tty_get_indexed(1);  }
-void _isr_tty_get_2()  { _isr_tty_get_indexed(2);  }
-void _isr_tty_get_3()  { _isr_tty_get_indexed(3);  }
-void _isr_tty_get_4()  { _isr_tty_get_indexed(4);  }
-void _isr_tty_get_5()  { _isr_tty_get_indexed(5);  }
-void _isr_tty_get_6()  { _isr_tty_get_indexed(6);  }
-void _isr_tty_get_7()  { _isr_tty_get_indexed(7);  }
-void _isr_tty_get_8()  { _isr_tty_get_indexed(8);  }
-void _isr_tty_get_9()  { _isr_tty_get_indexed(9);  }
-void _isr_tty_get_10() { _isr_tty_get_indexed(10); }
-void _isr_tty_get_11() { _isr_tty_get_indexed(11); }
-void _isr_tty_get_12() { _isr_tty_get_indexed(12); }
-void _isr_tty_get_13() { _isr_tty_get_indexed(13); }
-void _isr_tty_get_14() { _isr_tty_get_indexed(14); }
-void _isr_tty_get_15() { _isr_tty_get_indexed(15); }
 
 /////////////////////////////////////////////////////////////////////////////////////
 // _isr_switch
-// This ISR is in charge of context switch. 
-// It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function.
+// This ISR is in charge of context switch, and handle the IRQs generated by
+// the "system" timers. 
+// The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
+// that are distributed in all clusters.
+// The ISR acknowledges the IRQ and calls the _ctx_switch() function.
 /////////////////////////////////////////////////////////////////////////////////////
 void _isr_switch()
 {
-    volatile unsigned int *timer_address;
-    unsigned int proc_id;
-
-    proc_id = _procid();
-    timer_address = (unsigned int*)&seg_timer_base + (proc_id * TIMER_SPAN);
-
-    timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */
+    // get cluster index and proc local index
+    unsigned int pid        = _procid();
+    unsigned int loc_id     = pid % NB_PROCS_MAX;
+    unsigned int cluster_id = pid / NB_PROCS_MAX;
+
+#if GIET_USE_XICU
+
+    unsigned int* timer_address = // TODO
+
+#else
+
+    // compute Timer address
+    unsigned int* timer_address = (unsigned int*)&seg_timer_base +
+                                  (loc_id * TIMER_SPAN) +
+                                  (cluster_id * CLUSTER_SPAN);
+
+    // reset IRQ
+    timer_address[TIMER_RESETIRQ] = 0; 
+
+#endif
+
+    // performs the context switch
     _ctx_switch();
-}
-
+
+}
+
