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

Last change on this file since 626 was 626, checked in by cfuguet, 9 years ago

Introducing generic soft_sort_giet application for the
GIET nano-kernel.

It uses the number of clusters and the number of processors
defined in the hard_config.h file to deduce the number of
threads executing the application.

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