source: trunk/softs/giet_tsar/stdio.c @ 629

Last change on this file since 629 was 629, checked in by alain, 9 years ago
  • Updatre the gier_tsar to support the vci_iopic component in the tsar_generic_leti plat-form.
  • Modify the soft_transpose_giet application to make optional the graphic display on frame buffer and to introduce a systematic auto-check
File size: 50.0 KB
Line 
1////////////////////////////////////////////////////////////////////////////////////////
2// File : stdio.c
3// Written by Alain Greiner
4// Date : janvier 2014
5//
6// This file defines various functions that can be used by applications to access
7// peripherals, for the TSAR multi-processors multi_clusters architecture.
8// There is NO separation between application code and system code, as the
9// application are running in kernel mode without system calls.
10// This basic GIET does not support virtual memory, and does not support multi-tasking.
11//
12// The supported peripherals are:
13// - the SoClib multi_tty
14// - The SoCLib frame_buffer
15// - The SoCLib block_device
16//
17// The following parameters must be defined in the hard_config.h file.
18// - X_SIZE          : number of clusters in a row
19// - Y_SIZE          : number of clusters in a column
20// - X_WIDTH         : number of bits for X field in proc_id
21// - Y_WIDTH         : number of bits for Y field in proc_id
22// - NB_PROCS_MAX    : max number of processor per cluster
23// - NB_TTY_CHANNELS : max number of TTY channels
24// - USE_EXT_IO      : use external peripherals if not zero
25//
26// The follobing base addresses must be defined in the ldscript
27// - seg_tty_base
28// - seg_fbf_base
29// - seg_ioc_base
30////////////////////////////////////////////////////////////////////////////////////////
31
32#include "stdio.h"
33
34#if !defined(NB_PROCS_MAX)
35#error: you must define NB_PROCS_MAX in the hard_config.h file
36#endif
37
38#if !defined(USE_EXT_IO)
39#error: you must define USE_EXT_IO in the hard_config.h file
40#endif
41
42#if !defined(X_SIZE)
43#error: you must define X_SIZE in the hard_config.h file
44#endif
45
46#if !defined(Y_SIZE)
47#error: you must define Y_SIZE in the hard_config.h file
48#endif
49
50#if !defined(X_WIDTH)
51#error: you must define X_WIDTH in the hard_config.h file
52#endif
53
54#if (X_WIDTH != 4)
55#error: The X_WIDTH parameter must be equal to 4
56#endif
57
58#if !defined(Y_WIDTH)
59#error: you must define X_WIDTH in the hard_config.h file
60#endif
61
62#if (X_WIDTH != 4)
63#error: The Y_WIDTH parameter must be equal to 4
64#endif
65
66#if !defined(NB_TTY_CHANNELS)
67#error: you must define NB_TTY_CHANNELS in the hard_config.h file
68#endif
69
70
71
72
73#define NB_LOCKS      256
74#define NB_BARRIERS   16
75
76#define in_drivers __attribute__((section (".drivers")))
77#define in_unckdata __attribute__((section (".unckdata")))
78
79//////////////////////////////////////////////////////////////
80// various informations that must be defined in ldscript
81//////////////////////////////////////////////////////////////
82
83struct plouf;
84
85extern struct plouf seg_tty_base;
86extern struct plouf seg_fbf_base;
87extern struct plouf seg_ioc_base;
88extern struct plouf seg_mmc_base;
89
90////////////////////////////////////////////////////////////////////////////////////////
91//  Global uncachable variables for synchronization between drivers and ISRs
92////////////////////////////////////////////////////////////////////////////////////////
93
94in_unckdata int volatile    _ioc_lock    = 0;
95in_unckdata int volatile    _ioc_done    = 0;
96in_unckdata int volatile    _ioc_status;
97
98in_unckdata char volatile   _tty_get_buf[NB_TTY_CHANNELS];
99in_unckdata int volatile    _tty_get_full[NB_TTY_CHANNELS] = { [0 ... NB_TTY_CHANNELS-1] = 0 };
100
101////////////////////////////////////////////////////////////////////////////////////////
102//  Global uncachable variables for inter-task barriers
103////////////////////////////////////////////////////////////////////////////////////////
104
105in_unckdata int volatile    _barrier_value[NB_BARRIERS]  = { [0 ... NB_BARRIERS-1] = 0 };
106in_unckdata int volatile    _barrier_count[NB_BARRIERS]  = { [0 ... NB_BARRIERS-1] = 0 };
107in_unckdata int volatile    _barrier_lock[NB_BARRIERS]   = { [0 ... NB_BARRIERS-1] = 0 };
108
109////////////////////////////////////////////////////////////////////////////////////////
110//  Global uncachable variables for spin_locks using LL/C instructions
111////////////////////////////////////////////////////////////////////////////////////////
112
113in_unckdata int volatile    _spin_lock[NB_LOCKS] =    { [0 ... NB_LOCKS-1] = 0 };
114
115////////////////////////////////////////////////////////////////////////////////////////
116// Memcopy taken from MutekH.
117////////////////////////////////////////////////////////////////////////////////////////
118in_drivers void* _memcpy( void*        _dst, 
119                          const void*  _src, 
120                          unsigned int size )
121{
122    unsigned int *dst = _dst;
123    const unsigned int *src = _src;
124    if ( ! ((unsigned int)dst & 3) && ! ((unsigned int)src & 3) )
125    {
126        while (size > 3) 
127        {
128            *dst++ = *src++;
129            size -= 4;
130        }
131    }
132
133    unsigned char *cdst = (unsigned char*)dst;
134    unsigned char *csrc = (unsigned char*)src;
135
136    while (size--) 
137    {
138        *cdst++ = *csrc++;
139    }
140    return _dst;
141}
142////////////////////////////////////////////////////////////////////////////////////////
143// Memcopy using extended addresses
144////////////////////////////////////////////////////////////////////////////////////////
145in_drivers void  _extended_memcpy( unsigned int dst_cluster,
146                                   unsigned int dst_address,
147                                   unsigned int src_cluster,
148                                   unsigned int src_address,
149                                   unsigned int length )
150{
151    if ( (dst_address & 0x3) || (src_address & 0x3) || (length & 0x3) )
152    {
153        _tty_get_lock( 0 );
154        _tty_puts( "ERROR in _extended_memcpy()" );
155        _tty_release_lock( 0 );
156        _exit();
157    }
158
159    unsigned int i;
160    unsigned int word;
161
162    for ( i = 0 ; i < length ; i = i+4 )
163    {
164        word = _word_extended_read( src_cluster, (src_address + i) );
165        _word_extended_write( dst_cluster, (dst_address + i), word );
166    }
167}
168////////////////////////////////////////////////////////////////////////////////////////
169// Access CP0 and returns processor ident
170// No more than 1024 processors...
171////////////////////////////////////////////////////////////////////////////////////////
172in_drivers unsigned int _procid()
173{
174    unsigned int ret;
175    asm volatile( "mfc0 %0, $15, 1": "=r"(ret) );
176    return (ret & 0x3FF);
177}
178////////////////////////////////////////////////////////////////////////////////////////
179// Access CP0 and returns processor time
180////////////////////////////////////////////////////////////////////////////////////////
181in_drivers unsigned int _proctime()
182{
183    unsigned int ret;
184    asm volatile( "mfc0 %0, $9": "=r"(ret) );
185    return ret;
186}
187////////////////////////////////////////////////////////////////////////////////////////
188// Returns the number of processsors controled by the GIET
189////////////////////////////////////////////////////////////////////////////////////////
190in_drivers unsigned int _procnumber()
191{
192    return (unsigned int)(NB_PROCS_MAX * X_SIZE * Y_SIZE);
193}
194////////////////////////////////////////////////////////////////////////////////////////
195// Returns pseudo-random number
196////////////////////////////////////////////////////////////////////////////////////////
197in_drivers unsigned int _rand()
198{
199    unsigned int x = _proctime();
200    if((x & 0xF) > 7)
201        return (x*x & 0xFFFF);
202    else
203        return (x*x*x & 0xFFFF);
204}
205////////////////////////////////////////////////////////////////////////////////////////
206// Access CP0 and mask IRQs
207////////////////////////////////////////////////////////////////////////////////////////
208in_drivers void _it_mask()
209{
210    int tmp;
211    asm volatile("mfc0  %0, $12"    : "=r" (tmp) );
212    asm volatile("ori   %0, %0, 1"  : "=r" (tmp) );
213    asm volatile("mtc0  %0, $12"    : "=r" (tmp) );
214}
215////////////////////////////////////////////////////////////////////////////////////////
216// Access CP0 and enable IRQs
217////////////////////////////////////////////////////////////////////////////////////////
218in_drivers void _it_enable()
219{
220    int tmp;
221    asm volatile("mfc0  %0, $12"    : "=r" (tmp) );
222    asm volatile("addi  %0, %0, -1" : "=r" (tmp) );
223    asm volatile("mtc0  %0, $12"    : "=r" (tmp) );
224}
225//////////////////////////////////////////////////////////////////////
226// Invalidate all cache lines corresponding to a memory buffer.
227// This is used by the block_device driver.
228/////////////////////////////////////////////////////////////////////////
229in_drivers void _dcache_buf_invalidate(const void * buffer, size_t size)
230{
231    size_t i;
232    size_t dcache_line_size;
233
234    // retrieve dcache line size from config register (bits 12:10)
235    asm volatile("mfc0 %0, $16, 1" : "=r" (dcache_line_size));
236
237    dcache_line_size = 2 << ((dcache_line_size>>10) & 0x7);
238
239    // iterate on lines to invalidate each one of them
240    for ( i=0; i<size; i+=dcache_line_size )
241        asm volatile(" cache %0, %1"
242                :
243                :"i" (0x11), "R" (*((char*)buffer+i)));
244}
245
246////////////////////////////////////////////////////////////////////////////
247// This function makes a physical read access to a 32 bits word in memory,
248// after a temporary paddr extension.
249////////////////////////////////////////////////////////////////////////////
250in_drivers unsigned int _word_extended_read( unsigned int  cluster,
251                                             unsigned int  address )
252{
253    unsigned int value;
254    asm volatile(
255            "li      $3,        0xFFFFFFFE    \n"
256            "mfc0    $2,        $12           \n"
257            "and     $3,        $2, $3        \n"
258            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
259
260            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
261            "lw      %0,        0(%1)         \n"     /* value <= *paddr  */
262            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */
263
264            "li      $3,        0x00000001    \n"
265            "mfc0    $2,        $12           \n"
266            "or      $3,        $3, $2        \n"
267            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
268            : "=r" (value)
269            : "r" (address), "r" (cluster)
270            : "$2", "$3" );
271    return value;
272}
273////////////////////////////////////////////////////////////////////////////
274// This function makes a physical read access to a single byte in memory,
275// after a temporary paddr extension.
276////////////////////////////////////////////////////////////////////////////
277in_drivers unsigned char _byte_extended_read( unsigned int  cluster,
278                                              unsigned int  address )
279{
280    unsigned int value;
281    asm volatile(
282            "li      $3,        0xFFFFFFFE    \n"
283            "mfc0    $2,        $12           \n"
284            "and     $3,        $2, $3        \n"
285            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
286
287            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
288            "lb      %0,        0(%1)         \n"     /* value <= *paddr  */
289            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */
290
291            "li      $3,        0x00000001    \n"
292            "mfc0    $2,        $12           \n"
293            "or      $3,        $3, $2        \n"
294            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
295            : "=r" (value)
296            : "r" (address), "r" (cluster)
297            : "$2", "$3" );
298    return (unsigned char)value;
299}
300////////////////////////////////////////////////////////////////////////////
301// This function makes a physical write access to a 32 bits word in memory,
302// after a temporary DTLB address extension.
303////////////////////////////////////////////////////////////////////////////
304in_drivers void _word_extended_write( unsigned int  cluster, 
305                                      unsigned int  address,
306                                      unsigned int  word ) 
307{
308    asm volatile(
309            "li      $3,        0xFFFFFFFE    \n"
310            "mfc0    $2,        $12           \n"
311            "and     $3,        $2, $3        \n"
312            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
313
314            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
315            "sw      %0,        0(%1)         \n"     /* *paddr <= value  */
316            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */   
317
318            "li      $3,        0x00000001    \n"
319            "mfc0    $2,        $12           \n"
320            "or      $3,        $2, $3        \n"
321            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
322            :
323            : "r" (word), "r" (address), "r" (cluster)
324            : "$2", "$3");
325}
326////////////////////////////////////////////////////////////////////////////
327// This function makes a physical write access to single byte in memory,
328// after a temporary DTLB de-activation and address extension.
329////////////////////////////////////////////////////////////////////////////
330in_drivers void _byte_extended_write( unsigned int  cluster, 
331                                      unsigned int  address,
332                                      unsigned char byte ) 
333{
334    asm volatile(
335            "li      $3,        0xFFFFFFFE    \n"
336            "mfc0    $2,        $12           \n"
337            "and     $3,        $2, $3        \n"
338            "mtc0    $3,        $12           \n"     /* IRQ disabled     */
339
340            "mtc2    %2,        $24           \n"     /* PADDR_EXT <= msb */   
341            "sb      %0,        0(%1)         \n"     /* *paddr <= value  */
342            "mtc2    $0,        $24           \n"     /* PADDR_EXT <= 0   */   
343
344            "li      $3,        0x00000001    \n"
345            "mfc0    $2,        $12           \n"
346            "or      $3,        $2, $3        \n"
347            "mtc0    $3,        $12           \n"     /* IRQ enabled      */
348            :
349            : "r" (byte), "r" (address), "r" (cluster)
350            : "$2", "$3");
351}
352
353///////////////////////////////////////////////////////////////////////////////////////
354// Exit (suicide) after printing message on TTY0
355///////////////////////////////////////////////////////////////////////////////////////
356in_drivers void _exit()
357{
358    unsigned int proc_id = _procid();
359    unsigned int l       = proc_id % NB_PROCS_MAX;
360    unsigned int x       = (proc_id / NB_PROCS_MAX) >> Y_WIDTH;
361    unsigned int y       = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
362
363    _tty_get_lock( 0 );
364    _tty_puts("\n !!! exit proc[");
365    _tty_putd( x );
366    _tty_puts(",");
367    _tty_putd( y );
368    _tty_puts(",");
369    _tty_putd( l );
370    _tty_puts("]  !!!\n");
371    _tty_release_lock( 0 );
372
373    while(1) asm volatile("nop");   // infinite loop...
374}
375
376/////////////////////////////////////////////////////////////////////////
377// convert a 32 bits unsigned int to a string of 10 decimal characters.
378/////////////////////////////////////////////////////////////////////////
379in_drivers void _itoa_dec(unsigned val, char* buf)
380{
381    const char  DecTab[] = "0123456789";
382    unsigned int i;
383    for( i=0 ; i<10 ; i++ )
384    {
385        if( (val!=0) || (i==0) ) buf[9-i] = DecTab[val % 10];
386        else                     buf[9-i] = 0x20;
387        val /= 10;
388    }
389}
390//////////////////////////////////////////////////////////////////////////
391// convert a 32 bits unsigned int to a string of 8 hexadecimal characters.
392///////////////////////////////////////////////////////////////////////////
393in_drivers void _itoa_hex(unsigned int val, char* buf)
394{
395    const char  HexaTab[] = "0123456789ABCD";
396    unsigned int i;
397    for( i=0 ; i<8 ; i++ )
398    {
399        buf[7-i] = HexaTab[val % 16];
400        val /= 16;
401    }
402}
403
404
405///////////////////////////////////////////////////////////////////////////////////////
406// VCI MULTI_TTY
407///////////////////////////////////////////////////////////////////////////////////////
408//  The total number of TTY terminals is defined by NB_TTY_CHANNELS.
409//  - If there is only one terminal, it is supposed to be shared, and used by
410//    all processors: a lock must be taken before display.
411//  - If there is several terminals, and the number of processors is smaller
412//    than the number of terminals, there is one terminal per processor, but
413//    the TTY index is not equal to the proc_id, due to cluster indexing policy:
414//    proc_id = cluster_xy * NB_PROCS_MAX + local_id (with cluster_xy = x << Y_WIDTH + y)
415//    tty_id  = cluster_id * NB_PROCS_MAX + local_id (with cluster_id = x * Y_SIZE + y)
416//  - If the computed tty_id is larger than NB_TTY_CHANNELS, an error is returned.
417///////////////////////////////////////////////////////////////////////////////////////
418//  If USE_EXT_IO is set, we use the TTY controler implemented in cluster_io
419//  (x = X_SIZE-1 / y = Y_SIZE), which requires and extended address access.
420//  If USE_EXT_IO not set, we use the single channel TTY contrÃŽler in cluster (0,0).
421///////////////////////////////////////////////////////////////////////////////////////
422
423///////////////////////////////////////////////////////////////////////////////////////
424// Write one or several characters directly from a fixed length user buffer
425// to the TTY_WRITE register of the TTY controler.
426// The channel index must be checked by the calling function.
427// This is a non blocking call : it test the TTY_STATUS register.
428// If the TTY_STATUS_WRITE bit is set, the transfer stops and the function
429// returns  the number of characters that have been actually written.
430///////////////////////////////////////////////////////////////////////////////////////
431in_drivers int _tty_write( char*           buffer, 
432                           unsigned int    length, 
433                           unsigned int    channel )
434{
435    unsigned int    base       = (unsigned int)&seg_tty_base + channel*TTY_SPAN*4;
436    unsigned int    nwritten   = 0;
437    unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
438    unsigned int    status;
439    unsigned int        i;
440
441    for ( i=0 ; i < length ; i++ )
442    {
443        if( USE_EXT_IO )    // extended addressing to reach cluster_io
444        {
445            status = _word_extended_read( cluster_io, base + TTY_STATUS*4 );
446            if ( (status & 0x2) == 0x2 ) break;
447            else
448            {
449                _byte_extended_write( cluster_io, base + TTY_WRITE*4 , buffer[i] );
450                nwritten++;
451            }
452        }
453        else                // direct addressing to cluster(0,0)
454        {
455            char* tty = (char*)base;
456            if ( (tty[TTY_STATUS*4] & 0x2) == 0x2 )  break;
457            else
458            {
459                tty[TTY_WRITE*4] = buffer[i]; // write character
460                nwritten++;
461            }
462        }
463    }
464
465    return nwritten;
466}
467
468///////////////////////////////////////////////////////////////////////////////////////
469// Fetch one character directly from the TTY_READ register of the TTY controler,
470// and writes this character to the user buffer.
471// The channel index must be checked by the calling function.
472// This is a non blocking call : it returns 0 if the register is empty,
473// and returns 1 if the register is full.
474///////////////////////////////////////////////////////////////////////////////////////
475in_drivers int _tty_read( char*          buffer, 
476                          unsigned int   channel )
477{
478    unsigned int    base       = (unsigned int)&seg_tty_base + channel*TTY_SPAN*4;
479    unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
480    unsigned int    status;
481
482    if( USE_EXT_IO )
483    {
484        status = _word_extended_read( cluster_io, base + TTY_STATUS*4 );
485        if ( (status & 0x1) == 0x1 )
486        {
487            buffer[0] = (char)_word_extended_read( cluster_io, base + TTY_READ*4 );
488            return 1;
489        }
490        else
491        {
492            return 0;
493        }
494    }
495    else
496    {
497        char* tty = (char*)base;
498
499        if((tty[TTY_STATUS*4] & 0x1) == 0x1)
500        {
501            buffer[0] = tty[TTY_READ*4];
502            return 1;
503        }
504        else
505        {
506            return 0;
507        }
508    }
509}
510
511//////////////////////////////////////////////////////////////////////////////
512// This function displays a string on TTY0.
513// The string must be terminated by a NUL character.
514//////////////////////////////////////////////////////////////////////////////
515in_drivers void _tty_puts( char* string )
516{
517    int length = 0;
518    while (string[length] != 0) length++;
519    _tty_write( string, length, 0 );
520}
521
522///////////////////////////////////////////////////////////////////////////////
523// This function displays a 32 bits unsigned int as an hexa string on TTY0.
524///////////////////////////////////////////////////////////////////////////////
525in_drivers void _tty_putx(unsigned int val) 
526{
527    static const char HexaTab[] = "0123456789ABCDEF";
528    char buf[11];
529    unsigned int c;
530
531    buf[0] = '0';
532    buf[1] = 'x';
533    buf[10] = 0;
534
535    for (c = 0; c < 8; c++) 
536    { 
537        buf[9 - c] = HexaTab[val & 0xF];
538        val = val >> 4;
539    }
540    _tty_puts( buf );
541}
542
543///////////////////////////////////////////////////////////////////////////////
544// This function displays a 32 bits unsigned int as a decimal string on TTY0.
545///////////////////////////////////////////////////////////////////////////////
546in_drivers void _tty_putd( unsigned int val ) 
547{
548    static const char DecTab[] = "0123456789";
549    char buf[11];
550    unsigned int i;
551    unsigned int first;
552
553    buf[10] = 0;
554
555    for (i = 0; i < 10; i++) 
556    {
557        if ((val != 0) || (i == 0)) 
558        {
559            buf[9 - i] = DecTab[val % 10];
560            first = 9 - i;
561        }
562        else 
563        {
564            break;
565        }
566        val /= 10;
567    }
568    _tty_puts( &buf[first] );
569}
570
571//////////////////////////////////////////////////////////////////////////////
572// This function try to take the hardwired lock protecting exclusive access
573// to TTY terminal identified by the channel argument.
574// It returns only when the lock has been successfully taken.
575//////////////////////////////////////////////////////////////////////////////
576in_drivers void _tty_get_lock( unsigned int channel )
577{
578    if ( USE_EXT_IO )  // extended addressing to cluster_io
579    {
580        unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
581        unsigned int    address    = (unsigned int)&seg_tty_base
582                                     + ((TTY_CONFIG + channel*TTY_SPAN)*4);
583        while ( _word_extended_read( cluster_io, address ) ) asm volatile("nop");
584    }
585    else               // direct addressing to cluster(0,0)
586    {
587        unsigned int* tty = (unsigned int *) &seg_tty_base;
588        while ( tty[channel * TTY_SPAN + TTY_CONFIG] ) asm volatile("nop"); 
589    }
590}
591
592//////////////////////////////////////////////////////////////////////////////
593// This function releases the hardwired lock protecting exclusive access
594// to TTY terminal identified by the channel argument.
595//////////////////////////////////////////////////////////////////////////////
596in_drivers void _tty_release_lock( unsigned int channel )
597{
598    if ( USE_EXT_IO )  // extended addressing to cluster_io
599    {
600        unsigned int    cluster_io = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
601        unsigned int    address    = (unsigned int)&seg_tty_base
602                                     + ((TTY_CONFIG + channel*TTY_SPAN)*4);
603        _word_extended_write( cluster_io, address, 0 );
604    }
605    else               // direct addressing to cluster(0,0)
606    {
607        unsigned int* tty_address = (unsigned int *) &seg_tty_base;
608        tty_address[channel * TTY_SPAN + TTY_CONFIG] = 0;
609    }
610}
611
612//////////////////////////////////////////////////////////////////////////////
613// This function fetch a single ascii character from a terminal
614// implicitely defined by the processor ID.
615// It is a blocking function.
616//////////////////////////////////////////////////////////////////////////////
617in_drivers void _tty_getc( char* buf )
618{
619    unsigned int proc_id = _procid();
620    unsigned int channel;
621    unsigned int l;
622    unsigned int x;
623    unsigned int y;
624
625    // check TTY channel
626    l           = (proc_id % NB_PROCS_MAX);
627    x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
628    y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
629    channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
630    if (channel >= NB_TTY_CHANNELS )
631    {
632        _tty_get_lock( 0 );
633        _tty_puts( "ERROR in _tty_getc(): TTY index too large\n" );
634        _tty_release_lock( 0 );
635        _exit();
636    }
637
638    while( _tty_read( buf, channel ) == 0 ) asm volatile("nop");
639}
640
641//////////////////////////////////////////////////////////////////////////////
642//  Fetch a string of decimal characters (most significant digit first)
643//  to build a 32 bits unsigned int.
644//  The terminal index is implicitely defined by the processor ID.
645//  This is a blocking function.
646//  The decimal characters are written in a 32 characters buffer
647//  until a <LF> or <CR> character is read.
648//  The <DEL> character is interpreted, and previous characters can be
649//  cancelled. All others characters are ignored.
650//  When the <LF> or <CR> character is received, the string is converted
651//  to an unsigned int value. If the number of decimal digit is too large
652//  for the 32 bits range, the zero value is returned.
653//////////////////////////////////////////////////////////////////////////////
654in_drivers void _tty_getw( unsigned int* word_buffer )
655{
656    char          buf[32];
657    char          byte;
658    char          cancel_string[3] = { 0x08, 0x20, 0x08 };
659    char          zero             = 0x30;
660    unsigned int  save = 0;
661    unsigned int  val = 0;
662    unsigned int  done = 0;
663    unsigned int  overflow = 0;
664    unsigned int  max = 0;
665    unsigned int  proc_id = _procid();
666    unsigned int  i;
667    unsigned int  channel;
668    unsigned int  x;
669    unsigned int  y;
670    unsigned int  l;
671
672    // check TTY channel
673    l           = (proc_id % NB_PROCS_MAX);
674    x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
675    y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
676    channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l;
677    if (channel >= NB_TTY_CHANNELS )
678    {
679        _tty_get_lock( 0 );
680        _tty_puts( "ERROR in _tty_getw(): TTY index too large\n" );
681        _tty_release_lock( 0 );
682        _exit();
683    }
684
685    while( done == 0 )
686    {
687        _tty_read( &byte, channel );
688
689        if (( byte > 0x2F) && (byte < 0x3A))  // decimal character
690        {
691            buf[max] = byte;
692            max++;
693            _tty_write( &byte, 1, channel );
694        }
695        else if ( (byte == 0x0A) || (byte == 0x0D) ) // LF or CR character
696        {
697            done = 1;
698        }
699        else if ( byte == 0x7F )        // DEL character
700        {
701            if (max > 0)
702            {
703                max--;          // cancel the character
704                _tty_write( cancel_string, 3, channel );
705            }
706        }
707    } // end while
708
709    // string conversion
710    for( i=0 ; i<max ; i++ )
711    {
712        val = val*10 + (buf[i] - 0x30);
713        if (val < save) overflow = 1;
714        save = val;
715    }
716    if (overflow == 0)
717    {
718        *word_buffer = val;     // return decimal value
719    }
720    else
721    {
722        for( i=0 ; i<max ; i++)     // cancel the string
723        {
724            _tty_write( cancel_string, 3, channel );
725        }
726        _tty_write( &zero, 1, channel );
727        *word_buffer = 0;       // return 0 value
728    }
729}
730
731//////////////////////////////////////////////////////////////////////////////
732//  This function is a simplified version of the mutek_printf() function.
733//  It takes the TTY lock on the selected channel for exclusive access.
734//  Only a limited number of formats are supported:
735//  - %d : signed decimal
736//  - %u : unsigned decimal
737//  - %x : hexadecimal
738//  - %c : char
739//  - %s : string
740//////////////////////////////////////////////////////////////////////////////
741in_drivers void _tty_printf( char *format, ...)
742{
743    va_list ap;
744    va_start( ap, format );
745
746    unsigned int channel;
747    unsigned int x;
748    unsigned int y;
749    unsigned int proc_id = _procid();
750
751    // compute TTY channel :
752    // if the number of TTY channels is smaller
753    // than the number of clusters, use TTY_0_0
754    // else, TTY channel <= cluster index
755    if ( NB_TTY_CHANNELS < (X_SIZE * Y_SIZE) )
756    {
757        channel = 0;
758    }
759    else
760    {
761        x           = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 
762        y           = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1);
763        channel     = (x * Y_SIZE + y);
764    }
765
766    // take the TTY lock
767    _tty_get_lock( channel );
768
769printf_text:
770
771    while (*format) 
772    {
773        unsigned int i;
774        for (i = 0; format[i] && format[i] != '%'; i++)
775            ;
776        if (i) 
777        {
778            _tty_write( format, i, channel );
779            format += i;
780        }
781        if (*format == '%') 
782        {
783            format++;
784            goto printf_arguments;
785        }
786    } // end while
787
788    va_end( ap );
789
790    // release lock
791    _tty_release_lock( 0 );
792
793    return;
794
795printf_arguments:
796
797    {
798        int                 val = va_arg(ap, long);
799        char                buf[20];
800        char*               pbuf;
801        unsigned int        len = 0;
802        static const char   HexaTab[] = "0123456789ABCDEF";
803        unsigned int        i;
804
805        switch (*format++) {
806            case ('c'):             // char conversion
807                len = 1;
808                buf[0] = val;
809                pbuf = buf;
810                break;
811            case ('d'):             // decimal signed integer
812                if (val < 0) 
813                {
814                    val = -val;
815                    _tty_write( "_" , 1, channel );
816                }
817            case ('u'):             // decimal unsigned integer
818                for( i=0 ; i<10 ; i++) 
819                {
820                    buf[9-i] = HexaTab[val % 10];
821                    if (!(val /= 10)) break;
822                }
823                len =  i+1;
824                pbuf = &buf[9-i];
825                break;
826            case ('x'):             // hexadecimal integer
827                _tty_write( "0x", 2, channel );
828                for( i=0 ; i<8 ; i++) 
829                {
830                    buf[7-i] = HexaTab[val % 16U];
831                    if (!(val /= 16U)) break;
832                }
833                len =  i+1;
834                pbuf = &buf[7-i];
835                break;
836            case ('s'):             // string
837                {
838                    char *str = (char*)val;
839                    while ( str[len] ) len++;
840                    pbuf = (char*)val;
841                }
842                break;
843            default:
844                goto printf_text;
845        } // end switch
846
847        _tty_write( pbuf, len, channel );
848        goto printf_text;
849    }
850} // end printf()
851
852//////////////////////////////////////////////////////////////////////////////////////
853//  These functions are the ISRs that must be executed when an IRQ is activated
854//  by the TTY: _tty_isr_XX is associated to TTY channel [XX].
855//  It save the character in the communication buffer _tty_get_buf[XX],
856//  and set the set/reset variable _tty_get_full[XX].
857//  A character is lost if the buffer is full when the ISR is executed.
858//////////////////////////////////////////////////////////////////////////////////////
859in_drivers void _tty_isr_indexed(size_t index)
860{
861    if ( USE_EXT_IO )   // extended addressing to TTY in cluster_io
862    {
863        unsigned int  cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
864        unsigned int  base    = (unsigned int)&seg_tty_base +
865                                ((index*TTY_SPAN + TTY_READ)*4); 
866
867        _tty_get_buf[index] = (char)_word_extended_read( cluster, base );
868    }
869    else                // direct addressing to TTY in cluster(0,0)
870    {
871        char* tty = (char*)&seg_tty_base + index*TTY_SPAN*4;
872
873        _tty_get_buf[index] = tty[TTY_READ*4];  // save character and reset IRQ
874    }
875    _tty_get_full[index] = 1;               // signals character available
876}
877
878in_drivers void _tty_isr()    { _tty_isr_indexed(0); }
879
880in_drivers void _tty_isr_00() { _tty_isr_indexed(0); }
881in_drivers void _tty_isr_01() { _tty_isr_indexed(1); }
882in_drivers void _tty_isr_02() { _tty_isr_indexed(2); }
883in_drivers void _tty_isr_03() { _tty_isr_indexed(3); }
884in_drivers void _tty_isr_04() { _tty_isr_indexed(4); }
885in_drivers void _tty_isr_05() { _tty_isr_indexed(5); }
886in_drivers void _tty_isr_06() { _tty_isr_indexed(6); }
887in_drivers void _tty_isr_07() { _tty_isr_indexed(7); }
888in_drivers void _tty_isr_08() { _tty_isr_indexed(8); }
889in_drivers void _tty_isr_09() { _tty_isr_indexed(9); }
890in_drivers void _tty_isr_10() { _tty_isr_indexed(10); }
891in_drivers void _tty_isr_11() { _tty_isr_indexed(11); }
892in_drivers void _tty_isr_12() { _tty_isr_indexed(12); }
893in_drivers void _tty_isr_13() { _tty_isr_indexed(13); }
894in_drivers void _tty_isr_14() { _tty_isr_indexed(14); }
895in_drivers void _tty_isr_15() { _tty_isr_indexed(15); }
896in_drivers void _tty_isr_16() { _tty_isr_indexed(16); }
897in_drivers void _tty_isr_17() { _tty_isr_indexed(17); }
898in_drivers void _tty_isr_18() { _tty_isr_indexed(18); }
899in_drivers void _tty_isr_19() { _tty_isr_indexed(19); }
900in_drivers void _tty_isr_20() { _tty_isr_indexed(20); }
901in_drivers void _tty_isr_21() { _tty_isr_indexed(21); }
902in_drivers void _tty_isr_22() { _tty_isr_indexed(22); }
903in_drivers void _tty_isr_23() { _tty_isr_indexed(23); }
904in_drivers void _tty_isr_24() { _tty_isr_indexed(24); }
905in_drivers void _tty_isr_25() { _tty_isr_indexed(25); }
906in_drivers void _tty_isr_26() { _tty_isr_indexed(26); }
907in_drivers void _tty_isr_27() { _tty_isr_indexed(27); }
908in_drivers void _tty_isr_28() { _tty_isr_indexed(28); }
909in_drivers void _tty_isr_29() { _tty_isr_indexed(29); }
910in_drivers void _tty_isr_30() { _tty_isr_indexed(30); }
911in_drivers void _tty_isr_31() { _tty_isr_indexed(31); }
912
913
914//////////////////////////////////////////////////////////////////////////////////////////
915//   BLOCK_DEVICE (IOC)
916//////////////////////////////////////////////////////////////////////////////////////////
917// The functions below use the three variables _ioc_lock _ioc_done,
918// and _ioc_status for synchronisation.
919// - As the IOC component can be used by several programs running in parallel,
920// the _ioc_lock variable guaranties exclusive access to the device.
921// The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
922// and set _ioc_lock to a non zero value.
923// The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock
924// variable until the device is available.
925// - When the tranfer is completed, the ISR routine activated by the IOC IRQ
926// set the _ioc_done variable to a non-zero value. Possible address errors detected
927// by the IOC peripheral are reported by the ISR in the _ioc_status variable.
928// The _ioc_completed() function is polling the _ioc_done variable, waiting for
929// tranfer conpletion. When the completion is signaled, the _ioc_completed() function
930// reset the _ioc_done variable to zero, and releases the _ioc_lock variable.
931///////////////////////////////////////////////////////////////////////////////////////
932//  If USE_EXT_IO is set, we use the IOC controler implemented in cluster_io
933//  (x = X_SIZE-1 / y = Y_SIZE), which requires and extended address access.
934//  If USE_EXT_IO not set, we use the IOC contrÃŽler in cluster (0,0).
935///////////////////////////////////////////////////////////////////////////////////////
936
937///////////////////////////////////////////////////////////////////////////////////////
938// This blocking function is used by the _ioc_read() and _ioc_write() functions
939// to get _ioc_lock using LL/SC.
940///////////////////////////////////////////////////////////////////////////////////////
941in_drivers void _ioc_get_lock()
942{
943    register unsigned int*      plock = (unsigned int*)&_ioc_lock;                     
944
945    asm volatile ("_ioc_llsc:                       \n"
946                  "ll   $2,    0(%0)                \n" // $2 <= _ioc_lock
947                  "bnez $2,    _ioc_llsc            \n" // retry  if busy
948                  "li   $3,    1                    \n" // prepare argument for sc 
949                  "sc   $3,    0(%0)                \n" // try to set _ioc_busy
950                  "beqz $3,    _ioc_llsc            \n" // retry if not atomic
951                  ::"r"(plock):"$2","$3");
952}
953
954//////////////////////////////////////////////////////////////////////////////////////
955// Transfer data from a memory buffer to the block_device.
956// - lba    : first block index on the disk
957// - buffer : base address of the memory buffer
958// - count  : number of blocks to be transfered
959// - ext    : cluster index for the memory buffer
960///////////////////////////////////////////////////////////////////////////////////////
961in_drivers void _ioc_write( size_t   lba, 
962                            void*    buffer, 
963                            size_t   count,
964                            size_t   ext )
965{
966    // get the lock
967    _ioc_get_lock();
968
969    if ( USE_EXT_IO )   // extended addressing to cluster_io
970    {
971        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
972        unsigned int    base    = (unsigned int)&seg_ioc_base;
973
974        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER*4,     (unsigned int)buffer );
975        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER_EXT*4, ext );
976        _word_extended_write( cluster, base + BLOCK_DEVICE_COUNT*4,      count );
977        _word_extended_write( cluster, base + BLOCK_DEVICE_LBA*4,        lba );
978        _word_extended_write( cluster, base + BLOCK_DEVICE_IRQ_ENABLE*4, 1 );
979        _word_extended_write( cluster, base + BLOCK_DEVICE_OP*4,         BLOCK_DEVICE_WRITE );
980    }
981    else                // direct addressing to cluster(0,0)
982    {
983        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
984
985        ioc[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
986        ioc[BLOCK_DEVICE_BUFFER_EXT] = ext;
987        ioc[BLOCK_DEVICE_COUNT]      = count;
988        ioc[BLOCK_DEVICE_LBA]        = lba;
989        ioc[BLOCK_DEVICE_IRQ_ENABLE] = 1;
990        ioc[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_WRITE;
991    }
992}
993
994///////////////////////////////////////////////////////////////////////////////////////
995// Transfer data from a file on the block device to a memory buffer.
996// - lba    : first block index on the disk
997// - buffer : base address of the memory buffer
998// - count  : number of blocks to be transfered
999// - ext    : cluster index for the memory buffer
1000///////////////////////////////////////////////////////////////////////////////////////
1001in_drivers void _ioc_read( size_t   lba, 
1002                           void*    buffer, 
1003                           size_t   count,
1004                           size_t   ext )
1005{
1006    // get the lock
1007    _ioc_get_lock();
1008
1009    if ( USE_EXT_IO )   // extended addressing to cluster_io
1010    {
1011        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
1012        unsigned int    base    = (unsigned int)&seg_ioc_base;
1013
1014        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER*4,     (unsigned int)buffer );
1015        _word_extended_write( cluster, base + BLOCK_DEVICE_BUFFER_EXT*4, ext );
1016        _word_extended_write( cluster, base + BLOCK_DEVICE_COUNT*4,      count );
1017        _word_extended_write( cluster, base + BLOCK_DEVICE_LBA*4,        lba );
1018        _word_extended_write( cluster, base + BLOCK_DEVICE_IRQ_ENABLE*4, 1 );
1019        _word_extended_write( cluster, base + BLOCK_DEVICE_OP*4,         BLOCK_DEVICE_READ );
1020    }
1021    else                // direct addressing to cluster(0,0)
1022    {
1023        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
1024
1025        ioc[BLOCK_DEVICE_BUFFER]     = (unsigned int)buffer;
1026        ioc[BLOCK_DEVICE_BUFFER_EXT] = ext;
1027        ioc[BLOCK_DEVICE_COUNT]      = count;
1028        ioc[BLOCK_DEVICE_LBA]        = lba;
1029        ioc[BLOCK_DEVICE_IRQ_ENABLE] = 1;
1030        ioc[BLOCK_DEVICE_OP]         = BLOCK_DEVICE_READ;
1031    }
1032}
1033
1034///////////////////////////////////////////////////////////////////////////////////////
1035// This blocking function cheks completion of an I/O transfer and reports errors.
1036// It returns 0 if the transfer is successfully completed.
1037// It returns -1 if an error has been reported.
1038///////////////////////////////////////////////////////////////////////////////////////
1039in_drivers void _ioc_completed()
1040{
1041    // waiting for completion
1042    while (_ioc_done == 0)  asm volatile("nop"); 
1043   
1044    // reset synchronisation variables
1045    _ioc_done = 0;
1046    _ioc_lock = 0;
1047
1048    if( (_ioc_status != BLOCK_DEVICE_READ_SUCCESS) &&
1049        (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS) )
1050    {
1051        _tty_get_lock( 0 );
1052        _tty_puts( "ERROR in _ioc_completed()\n");
1053        _tty_release_lock( 0 );
1054        _exit();
1055    }
1056}
1057
1058//////////////////////////////////////////////////////////////////////////////////////
1059//  This ISR must be executed when an IRQ is activated by IOC to signal completion.
1060//  It acknowledge the IRQ using the ioc base address, save the status in _ioc_status,
1061//  and set the _ioc_done variable to signal completion.
1062//  This variable is defined in the drivers.c file.
1063//////////////////////////////////////////////////////////////////////////////////////
1064in_drivers void _ioc_isr()
1065{
1066    if ( USE_EXT_IO )  // extended addressing to cluster_io
1067    {
1068        unsigned int    cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;
1069        unsigned int    base    = (unsigned int)&seg_ioc_base;
1070
1071        _ioc_status = _word_extended_read( cluster, base + BLOCK_DEVICE_STATUS*4 );
1072    }
1073    else               // direct addressing to cluster(à,0)
1074    {
1075        unsigned int* ioc = (unsigned int*)&seg_ioc_base;
1076   
1077        _ioc_status = ioc[BLOCK_DEVICE_STATUS]; // save status & reset IRQ
1078    }
1079    _ioc_done   = 1;       // signals completion
1080}
1081
1082//////////////////////////////////////////////////////////////////////////////////////
1083//  This ISR must be executed when an IRQ is activated by MEMC to signal
1084//  an error detected by the TSAR memory cache after a write transaction.
1085//  It displays an error message on the TTY terminal allocated to the processor
1086//  executing the ISR.
1087//////////////////////////////////////////////////////////////////////////////////////
1088in_drivers void _mmc_isr()
1089{
1090    int*         mmc_address = (int*)&seg_mmc_base;
1091    unsigned int cluster_xy  = _procid() / NB_PROCS_MAX;
1092   
1093    _tty_printf( "WRITE ERROR signaled by Memory Cache in cluster %x\n", cluster_xy );
1094}
1095
1096//////////////////////////////////////////////////////////////////////////////////////
1097//  FRAME_BUFFER
1098//////////////////////////////////////////////////////////////////////////////////////
1099// The _fb_sync_write & _fb_sync_read functions use a memcpy strategy to implement
1100// the transfer between a data buffer and the frame buffer.
1101// They are blocking until completion of the transfer.
1102//////////////////////////////////////////////////////////////////////////////////////
1103
1104//////////////////////////////////////////////////////////////////////////////////////
1105//  _fb_sync_write()
1106// Transfer data from an user buffer to the frame_buffer device with a memcpy.
1107// - offset : offset (in bytes) in the frame buffer
1108// - buffer : base address of the memory buffer
1109// - length : number of bytes to be transfered
1110// - ext    : cluster_xy for the user buffer
1111//////////////////////////////////////////////////////////////////////////////////////
1112in_drivers void _fb_sync_write( unsigned int  offset, 
1113                                unsigned int  buffer, 
1114                                unsigned int  length,
1115                                unsigned int  ext )
1116{
1117    unsigned int  src_address = buffer;
1118    unsigned int  src_cluster = ext;
1119    unsigned int  dst_address = (unsigned int)&seg_fbf_base + offset;
1120    unsigned int  dst_cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;  // cluster_xy for I/O
1121
1122    _extended_memcpy( dst_cluster,
1123                      dst_address,
1124                      src_cluster,
1125                      src_address,
1126                      length );
1127}
1128
1129///////////////////////////////////////////////////////////////////////////////////////
1130//  _fb_sync_read()
1131// Transfer data from the frame_buffer device to an user buffer with a memcpy.
1132// - offset : offset (in bytes) in the frame buffer
1133// - buffer : base address of the memory buffer
1134// - length : number of bytes to be transfered
1135// - ext    : cluster_xy for the user buffer
1136//////////////////////////////////////////////////////////////////////////////////////
1137in_drivers void  _fb_sync_read( unsigned int  offset, 
1138                                unsigned int  buffer, 
1139                                unsigned int  length,
1140                                unsigned int  ext )
1141{
1142    unsigned int  dst_address = buffer;
1143    unsigned int  dst_cluster = ext;
1144    unsigned int  src_address = (unsigned int)&seg_fbf_base + offset;
1145    unsigned int  src_cluster = ((X_SIZE-1)<<Y_WIDTH) + Y_SIZE;  // cluster_xy for I/O
1146
1147    _extended_memcpy( dst_cluster,
1148                      dst_address,
1149                      src_cluster,
1150                      src_address,
1151                      length );
1152}
1153
1154///////////////////////////////////////////////////////////////////////////////////////
1155// Release a software spin-lock
1156///////////////////////////////////////////////////////////////////////////////////////
1157in_drivers void _release_lock(size_t index)
1158
1159{
1160    if( index >= NB_LOCKS ) 
1161    {
1162        _tty_get_lock( 0 );
1163        _tty_puts( "ERROR in _release_lock()" );
1164        _tty_release_lock( 0 );
1165        _exit();
1166    }
1167   
1168    _spin_lock[index] = 0;
1169}
1170
1171///////////////////////////////////////////////////////////////////////////////////////
1172// Try to take a software spin-lock.
1173// This is a blocking call, as there is a busy-waiting loop,
1174// until the lock is granted to the requester.
1175// There is an internal delay of about 100 cycles between
1176// two successive lock read, to avoid bus saturation.
1177///////////////////////////////////////////////////////////////////////////////////////
1178in_drivers void _get_lock(size_t index)
1179{
1180    if( index >= NB_LOCKS )
1181    {
1182        _tty_get_lock( 0 );
1183        _tty_puts( "ERROR in _get_lock()" );
1184        _tty_release_lock( 0 );
1185        _exit();
1186    }
1187
1188    register int   delay = ((_proctime() +_procid()) & 0xF) << 4;
1189    register int * plock = (int *) &_spin_lock[index];                 
1190
1191    asm volatile ("_locks_llsc:                 \n"
1192                  "ll   $2,    0(%0)            \n"     // $2 <= _locks_lock
1193                  "bnez $2,    _locks_delay     \n"     // random delay if busy
1194                  "li   $3,    1            \n"     // prepare argument for sc 
1195                  "sc   $3,    0(%0)            \n"     // try to set _locks_busy
1196                  "bnez $3,    _locks_ok    \n"     // exit if atomic
1197                  "_locks_delay:            \n"
1198                  "move $4,    %1           \n"     // $4 <= delay
1199                  "_locks_loop:             \n"
1200                  "addi $4,    $4,    -1    \n"     // $4 <= $4 - 1
1201                  "beqz $4,    _locks_loop  \n"     // test end delay
1202                  "j           _locks_llsc  \n"     // retry
1203                  "_locks_ok:                   \n"
1204                  ::"r"(plock),"r"(delay):"$2","$3","$4");
1205}
1206
1207
1208//////////////////////////////////////////////////////////////////////////////////////
1209// This function makes a cooperative initialisation of the barrier:
1210// - barrier_count[index] <= N
1211// - barrier_lock[index]  <= 0
1212// All tasks try to initialize the barrier, but the initialisation
1213// is done by only one task, using LL/SC instructions.
1214// This cooperative initialisation is questionnable,
1215// because the barrier can ony be initialised once...
1216//////////////////////////////////////////////////////////////////////////////////////
1217in_drivers void _barrier_init(unsigned int index, unsigned int value)
1218{
1219
1220    register int* pinit         = (int*)&_barrier_value[index];
1221    register int* pcount        = (int*)&_barrier_count[index];
1222    register int* plock         = (int*)&_barrier_lock[index];
1223
1224    if ( index >= NB_BARRIERS )
1225    {
1226        _tty_get_lock( 0 );
1227        _tty_puts( "ERROR in _barrier_init()" );
1228        _tty_release_lock( 0 );
1229        _exit();
1230    }
1231
1232    // parallel initialisation using atomic instructions LL/SC
1233    asm volatile ("_barrier_init_test:                  \n"
1234                  "ll   $2,     0(%0)                   \n"     // read barrier_value
1235                  "bnez $2,     _barrier_init_done      \n"
1236                  "move $3,     %3                              \n"
1237                  "sc   $3,     0(%0)                   \n"     // try to write barrier_value
1238                  "beqz $3,     _barrier_init_test      \n"
1239                  "move $3,     %3                                  \n" 
1240                  "sw   $3,     0(%1)                           \n"     // barrier_count <= barrier_value
1241                  "move $3, $0                      \n" //
1242                  "sw   $3,     0(%2)                           \n"     // barrier_lock <= 0
1243                  "_barrier_init_done:                  \n"
1244                  ::"r"(pinit),"r"(pcount),"r"(plock),"r"(value):"$2","$3");
1245}
1246
1247//////////////////////////////////////////////////////////////////////////////////////
1248// This blocking function uses a busy_wait technics (on the barrier_lock value),
1249// because the GIET does not support dynamic scheduling/descheduling of tasks.
1250// The barrier state is actually defined by two variables:
1251// _barrier_count[index] define the number of particpants that are waiting
1252// _barrier_lock[index] define the bool variable whose value is polled
1253// The last participant change the value of _barrier_lock[index] to release the barrier...
1254// There is at most 16 independant barriers, and an error is returned
1255// if the barrier index is larger than 15.
1256//////////////////////////////////////////////////////////////////////////////////////
1257in_drivers void _barrier_wait(unsigned int index)
1258{
1259    register int*       pcount          = (int*)&_barrier_count[index];         
1260    register int        count;
1261
1262    int                lock             = _barrier_lock[index];         
1263
1264    if ( index >= NB_BARRIERS )
1265    {
1266        _tty_get_lock( 0 );
1267        _tty_puts( "ERROR in _barrier_wait()" );
1268        _tty_release_lock( 0 );
1269        _exit();
1270    }
1271   
1272    // parallel decrement _barrier_count[index] using atomic instructions LL/SC
1273    // input : pointer on _barrier_count[index]
1274    // output : count = _barrier_count[index] (before decrementation)
1275    asm volatile ("_barrier_decrement:                          \n"
1276                  "ll   %0,     0(%1)                           \n"
1277                  "addi $3,     %0,     -1                      \n"
1278                  "sc   $3,     0(%1)                           \n"
1279                  "beqz $3,     _barrier_decrement              \n"
1280                  :"=&r"(count)
1281                  :"r"(pcount)
1282                  :"$2","$3");
1283
1284    // the last task re-initializes the barrier_ count variable
1285    // and the barrier_lock variable, waking up all other waiting tasks
1286
1287    if ( count == 1 )    // last task
1288    {
1289        _barrier_count[index] = _barrier_value[index];
1290        asm volatile( "sync" );
1291        _barrier_lock[index]   = (lock == 0) ? 1 : 0;
1292    }
1293    else                // other tasks
1294    {
1295        while ( lock == _barrier_lock[index] )  asm volatile("nop");
1296    }
1297} 
1298
1299
1300// Local Variables:
1301// tab-width: 4;
1302// c-basic-offset: 4;
1303// c-file-offsets:((innamespace . 0)(inline-open . 0));
1304// indent-tabs-mode: nil;
1305// End:
1306//
1307// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1308
Note: See TracBrowser for help on using the repository browser.