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

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

giet_tsar: using CLUSTER_IO constant in stdio functions

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