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

Last change on this file since 743 was 743, checked in by cfuguet, 10 years ago

giet_tsar:

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