source: soft/giet_vm/giet_libs/mwmr_channel.c @ 731

Last change on this file since 731 was 731, checked in by alain, 9 years ago

Introduce a giet_pthhread_yield() to deschedule the blocking functions
when a channel is empty (read) or full (write).

  • Property svn:executable set to *
File size: 18.3 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : mwmr_channel.c         
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include "mwmr_channel.h"
9#include "giet_config.h"
10#include "stdio.h"
11#include "stdint.h"
12#include "user_lock.h"
13
14//////////////////////////////////////
15void mwmr_init( mwmr_channel_t*  mwmr,
16                uint32_t*        buffer,     // buffer base address
17                uint32_t         width,      // number of words per item
18                uint32_t         nitems )    // max number of items
19{
20
21#if GIET_DEBUG_USER_MWMR
22uint32_t    x;
23uint32_t    y;
24uint32_t    lpid;
25giet_proc_xyp( &x, &y, &lpid );
26giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] initialises mwmr channel %x"
27                "\n buffer = %x / width = %d / nitems = %d\n",
28                x, y, lpid, (uint32_t)mwmr, (uint32_t)buffer, width, nitems );
29#endif
30
31    mwmr->ptw   = 0;
32    mwmr->ptr   = 0;
33    mwmr->sts   = 0;
34    mwmr->width = width;
35    mwmr->depth = width * nitems;
36    mwmr->data  = buffer;
37
38    lock_init( &mwmr->lock );
39}
40
41
42///////////////////////////////////////
43void mwmr_dump( mwmr_channel_t*  mwmr )
44{
45    // get the lock
46    lock_acquire( &mwmr->lock );
47
48    giet_tty_printf("\n[DEBUG MWMR] &fifo = %x / width = %d / depth = %d"
49                    "\n             sts = %d / ptr = %d / ptw = %d\n",
50                    (uint32_t)mwmr, mwmr->width, mwmr->depth,
51                     mwmr->sts, mwmr->ptr, mwmr->ptw );
52    uint32_t line, word, value;
53    for ( line = 0 ; line < ((mwmr->depth)>>2) ; line++ )
54    {
55        giet_tty_printf(" line %d :  ", line );
56        for ( word = 0 ; word < 4 ; word++ )
57        {
58            value = mwmr->data[line*4+word];
59            giet_tty_printf(" %x %x %x %x",
60                            (value    ) & 0xFF,
61                            (value>>8 ) & 0xFF,
62                            (value>>16) & 0xFF,
63                            (value>>24) & 0xFF );
64        }
65        giet_tty_printf("\n");
66    }
67
68    // release the lock
69    lock_release( &mwmr->lock );
70
71}
72
73
74//////////////////////////////////////////////
75uint32_t nb_mwmr_write( mwmr_channel_t*  mwmr, 
76                        uint32_t*        buffer, 
77                        uint32_t         items)
78{
79
80#if GIET_DEBUG_USER_MWMR
81uint32_t    x;
82uint32_t    y;
83uint32_t    lpid;
84giet_proc_xyp( &x, &y, &lpid );
85#endif
86
87    uint32_t n;
88    uint32_t spaces; // number of empty slots (in words)
89    uint32_t nwords; // requested transfer length (in words)
90    uint32_t depth;  // channel depth (in words)
91    uint32_t width;  // channel width (in words)
92    uint32_t sts;    // channel sts
93    uint32_t ptw;    // channel ptw
94
95    if (items == 0) return 0;
96
97    // get the lock
98    lock_acquire( &mwmr->lock );
99
100    // access fifo status
101    depth  = mwmr->depth;
102    width  = mwmr->width;
103    sts    = mwmr->sts;
104    ptw    = mwmr->ptw;
105    spaces = depth - sts;
106    nwords = width * items;
107
108    if (spaces >= nwords) // transfer items, release lock and return
109    { 
110        for (n = 0; n < nwords; n++) 
111        {
112            mwmr->data[ptw] = buffer[n];
113            if ((ptw + 1) == depth)  ptw = 0; 
114            else                     ptw = ptw + 1;
115        }
116        mwmr->sts = mwmr->sts + nwords;
117        mwmr->ptw = ptw;
118
119#if GIET_DEBUG_USER_MWMR
120giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] nb_mwmr_write() for %d words"
121                "\n %d words written / fifo %x / sts = %d\n",
122                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
123#endif
124
125        lock_release( &mwmr->lock );
126        return items;
127    }
128    else if (spaces < width) // release lock and return
129    {
130        lock_release( &mwmr->lock );
131        return 0;
132    }
133    else // transfer as many items as possible, release lock and return
134    {
135        nwords = (spaces / width) * width;    // integer number of items
136        for (n = 0; n < nwords; n++) 
137        {
138            mwmr->data[ptw] = buffer[n];
139            if ((ptw + 1) == depth) ptw = 0;
140            else                    ptw = ptw + 1;
141        }
142        mwmr->sts = sts + nwords;
143        mwmr->ptw = ptw;
144
145#if GIET_DEBUG_USER_MWMR
146giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] nb_mwmr_write() for %d words"
147                "\n %d words written / fifo %x / sts = %d\n",
148                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
149#endif
150
151        lock_release( &mwmr->lock );
152        return (nwords / width);
153    }
154} // end nb_mwmr_write()
155
156
157
158//////////////////////////////////////////////////
159uint32_t nb_mwmr_read( mwmr_channel_t*  mwmr, 
160                       uint32_t*        buffer,
161                       uint32_t         items) 
162{
163
164#if GIET_DEBUG_USER_MWMR
165uint32_t    x;
166uint32_t    y;
167uint32_t    lpid;
168giet_proc_xyp( &x, &y, &lpid );
169#endif
170
171    uint32_t n;
172    uint32_t nwords; // requested transfer length (words)
173    uint32_t depth;  // channel depth (words)
174    uint32_t width;  // channel width (words)
175    uint32_t sts;    // channel sts   (words)
176    uint32_t ptr;    // channel ptr   (words)
177
178    if (items == 0) return 0;
179
180    // get the lock
181    lock_acquire( &mwmr->lock );
182
183    // access fifo status
184    depth  = mwmr->depth;
185    width  = mwmr->width;
186    sts    = mwmr->sts;
187    ptr    = mwmr->ptr;
188    nwords = width * items;
189
190    if (sts >= nwords) // transfer items, release lock and return
191    {
192        for (n = 0; n < nwords; n++) 
193        {
194            buffer[n] = mwmr->data[ptr];
195            if ((ptr + 1) == depth)  ptr = 0;
196            else                     ptr = ptr + 1;
197        }
198        mwmr->sts = mwmr->sts - nwords;
199        mwmr->ptr = ptr;
200
201#if GIET_DEBUG_USER_MWMR
202giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] nb_mwmr_read() for %d words"
203                "\n %d words read / fifo %x / sts = %d\n",
204                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
205#endif
206
207        lock_release( &mwmr->lock );
208        return items;
209    }
210    else if (sts < width) // release lock and return
211    {
212        lock_release( &mwmr->lock );
213        return 0;
214    }
215    else // transfer as many items as possible, release lock and return
216    {
217        nwords = (sts / width) * width; // integer number of items
218        for (n = 0 ; n < nwords ; n++) 
219        {
220            buffer[n] = mwmr->data[ptr];
221            if ((ptr + 1) == depth)  ptr = 0;
222            else                     ptr = ptr + 1;
223        }
224        mwmr->sts = sts - nwords;
225        mwmr->ptr = ptr;
226
227#if GIET_DEBUG_USER_MWMR
228giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] nb_mwmr_read() for %d words"
229                "\n %d words read / fifo %x / sts = %d\n",
230                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
231#endif
232
233        lock_release( &mwmr->lock );
234        return (nwords / width);
235    }
236} // nb_mwmr_read()
237
238
239
240////////////////////////////////////////
241void mwmr_write( mwmr_channel_t*  mwmr, 
242                 uint32_t *       buffer, 
243                 uint32_t         items ) 
244{
245
246#if GIET_DEBUG_USER_MWMR
247uint32_t    x;
248uint32_t    y;
249uint32_t    lpid;
250giet_proc_xyp( &x, &y, &lpid );
251#endif
252
253    uint32_t n;
254    uint32_t spaces; // number of empty slots (in words)
255    uint32_t nwords; // requested transfer length (in words)
256    uint32_t depth;  // channel depth (in words)
257    uint32_t width;  // channel width (in words)
258    uint32_t sts;    // channel sts
259    uint32_t ptw;    // channel ptw
260
261    if (items == 0)  return;
262
263    while (1) 
264    {
265        // get the lock
266        lock_acquire( &mwmr->lock );
267
268        // compute spaces and nwords
269        depth = mwmr->depth;
270        width = mwmr->width;
271        sts  = mwmr->sts;
272        ptw  = mwmr->ptw;
273        spaces = depth - sts;
274        nwords = width * items;
275
276        if (spaces >= nwords) // write nwords, release lock and return
277        {
278            for (n = 0; n < nwords; n++) 
279            {
280                mwmr->data[ptw] = buffer[n];
281                if ((ptw + 1) == depth)  ptw = 0; 
282                else                     ptw = ptw + 1;
283            }
284            mwmr->ptw = ptw;
285            mwmr->sts = sts + nwords;
286
287#if GIET_DEBUG_USER_MWMR
288giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] mwmr_write() for %d words"
289                "\n %d words written / fifo %x / sts = %d\n",
290                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
291#endif
292
293            lock_release( &mwmr->lock );
294            return;
295        }
296        else if (spaces < width) // release lock and retry           
297        {
298            lock_release( &mwmr->lock );
299        }
300        else // write as many items as possible, release lock and retry
301        {
302            nwords = (spaces / width) * width;  // integer number of items
303            for (n = 0; n < nwords; n++) 
304            {
305                mwmr->data[ptw] = buffer[n];
306                if ((ptw + 1) == depth)  ptw = 0; 
307                else                     ptw = ptw + 1;
308            }
309            mwmr->sts = sts + nwords;
310            mwmr->ptw = ptw;
311            buffer = buffer + nwords;
312            items = items - (nwords/width);
313
314#if GIET_DEBUG_USER_MWMR
315giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] mwmr_write() for %d words"
316                "\n %d words written / fifo %x / sts = %d\n",
317                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
318#endif
319
320            lock_release( &mwmr->lock );
321        }
322
323        // deschedule before retry
324        giet_pthread_yield();
325    }
326} // end mwmr_write()
327
328
329//////////////////////////////////////
330void mwmr_read( mwmr_channel_t*  mwmr, 
331                uint32_t*        buffer, 
332                uint32_t         items) 
333{
334
335#if GIET_DEBUG_USER_MWMR
336uint32_t    x;
337uint32_t    y;
338uint32_t    lpid;
339giet_proc_xyp( &x, &y, &lpid );
340#endif
341
342    uint32_t n;
343    uint32_t nwords; // requested transfer length (in words)
344    uint32_t depth;  // channel depth (in words)
345    uint32_t width;  // channel width (in words)
346    uint32_t sts;    // channel sts
347    uint32_t ptr;    // channel ptr
348
349    if (items == 0) return;
350
351    while (1) 
352    {
353        // get the lock
354        lock_acquire( &mwmr->lock );
355
356        // compute nwords
357        depth  = mwmr->depth;
358        width  = mwmr->width;
359        sts    = mwmr->sts;
360        ptr    = mwmr->ptr;
361        nwords = width * items;
362
363        if (sts >= nwords) // read nwords, release lock and return
364        {
365            for (n = 0; n < nwords; n++) 
366            {
367                buffer[n] = mwmr->data[ptr];
368                if ((ptr + 1) == depth)  ptr = 0;
369                else                     ptr = ptr + 1;
370            }
371            mwmr->sts = mwmr->sts - nwords;
372            mwmr->ptr = ptr;
373
374#if GIET_DEBUG_USER_MWMR
375giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] mwmr_read() for %d words"
376                "\n %d words read / fifo %x / sts = %d\n",
377                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
378#endif
379
380            lock_release( &mwmr->lock );
381            return;
382        }
383        else if (sts < width) // release lock and retry
384        {
385            lock_release( &mwmr->lock );
386        }
387        else // read as many items as possible, release lock and retry
388        {   
389            nwords = (sts / width) * width; // integer number of items
390            for (n = 0; n < nwords; n++) 
391            {
392                buffer[n] = mwmr->data[ptr];
393                if ((ptr + 1) == depth) ptr = 0;
394                else                    ptr = ptr + 1;
395            }
396            mwmr->sts = sts - nwords;
397            mwmr->ptr = ptr;
398            buffer = buffer + nwords;
399            items = items - (nwords/width);
400
401#if GIET_DEBUG_USER_MWMR
402giet_tty_printf("\n[DEBUG MWMR] P[%d,%d,%d] mwmr_read() for %d words"
403                "\n %d words read / fifo %x / sts = %d\n",
404                x, y, lpid, items*width , nwords, (uint32_t)mwmr, mwmr->sts );
405#endif
406
407            lock_release( &mwmr->lock );
408        }
409
410        // deschedule before retry
411        giet_pthread_yield();
412    }
413} // end mwmr_read()
414
415
416
417
418
419
420
421
422/////////////////////////////////////////////
423void mwmr_bufio_init( mwmr_bufio_t*    bufio,       
424                      uint8_t*         buffer, 
425                      uint32_t         size,       // number of bytes
426                      uint32_t         is_input,
427                      mwmr_channel_t*  mwmr )
428{
429    uint32_t bytes_per_item = (mwmr->width)<<2;
430
431    giet_pthread_assert( ((size % bytes_per_item) == 0) ,
432    "ERROR in mwmr_bufio_init() : BUFIO size must be multiple of MWMR item size\n"); 
433
434    bufio->mwmr     = mwmr;
435    bufio->is_input = is_input;
436    bufio->base     = buffer;
437    bufio->ptr      = 0;
438    bufio->max      = 0;
439    bufio->nitems   = size / bytes_per_item; 
440    bufio->nbytes   = size;
441}  // end mwmr_bufio_init()
442
443////////////////////////////////////////////
444void mwmr_bufio_dump( mwmr_bufio_t*  bufio )
445{
446    giet_tty_printf("\n[DEBUG MWMR] &bufio = %x / &mwmr = %x / &buffer = %x"
447                    "\n             is_input = %d / nbytes = %d / ptr = %d / max = %d\n",
448                    bufio , bufio->mwmr , bufio->base,
449                    bufio->is_input , bufio->nbytes , bufio->ptr , bufio->max );
450    uint32_t i = 0;
451    while ( i < bufio->nbytes )
452    {
453        giet_tty_printf(" %x", bufio->base[i] );
454        if ( (i & 0xF) == 0xF ) giet_tty_printf("\n");
455        i++;
456    }
457    giet_tty_printf("\n");
458}  // end mwmr_bufio_dump()
459   
460////////////////////////////////////////////////////
461uint8_t mwmr_bufio_read_byte( mwmr_bufio_t*  bufio )
462{
463    giet_pthread_assert( ( bufio->is_input ) ,
464    "ERROR in mwmr_bufio_read_byte() : bufio not input\n"); 
465
466    uint8_t ret;
467
468    if ( bufio->ptr == 0 )  // refill
469    {
470        uint32_t items;
471        do
472        {
473            items = nb_mwmr_read( bufio->mwmr , (uint32_t*)bufio->base , bufio->nitems );
474
475            // deschedule if channel empty
476            if (items == 0 ) giet_pthread_yield();
477        } 
478        while ( items == 0 );
479        bufio->max = items * ((bufio->mwmr->width)<<2);
480
481#if GIET_DEBUG_USER_MWMR
482giet_tty_printf("\n[DEBUG MWMR] mwmr_bufio_read_byte() read %d bytes from mwmr\n",
483                bufio->max );
484uint32_t i = 0;
485while ( i < bufio->max )
486{
487    giet_tty_printf(" %x", bufio->base[i] );
488    if ( (i & 0xF) == 0xF ) giet_tty_printf("\n");
489    i++;
490}
491giet_tty_printf("\n");
492#endif
493
494    }
495
496    ret = bufio->base[bufio->ptr];
497    bufio->ptr++;
498    if ( bufio->ptr == bufio->max ) bufio->ptr = 0;
499    return ret;
500
501}  // end mwmr_bufio_read_byte()
502
503///////////////////////////////////////////
504void mwmr_bufio_skip( mwmr_bufio_t*  bufio,
505                      uint32_t       length )
506{
507    giet_pthread_assert( ( bufio->is_input ) ,
508    "ERROR in mwmr_bufio_skip() : bufio not input\n"); 
509
510    while ( length )
511    {
512        if ( bufio->ptr == 0 )  // refill
513        {
514            uint32_t items;
515            do
516            {
517                items = nb_mwmr_read( bufio->mwmr , (uint32_t*)bufio->base , bufio->nitems );
518
519                // deschedule if channel empty
520                if (items == 0 ) giet_pthread_yield();
521            } 
522            while ( items == 0 );
523            bufio->max = items * ((bufio->mwmr->width)<<2);
524
525#if GIET_DEBUG_USER_MWMR
526giet_tty_printf("\n[DEBUG MWMR] mwmr_bufio_skip() read %d bytes from mwmr\n",
527                bufio->max );
528uint32_t i = 0;
529while ( i < bufio->max )
530{
531    giet_tty_printf(" %x", bufio->base[i] );
532    if ( (i & 0xF) == 0xF ) giet_tty_printf("\n");
533    i++;
534}
535giet_tty_printf("\n");
536#endif
537
538        }
539
540        bufio->ptr++;
541        if ( bufio->ptr == bufio->max ) bufio->ptr = 0;
542        length--;
543    }
544}  // end mwmr_bufio_skip()
545                     
546/////////////////////////////////////////////
547void mwmr_bufio_align( mwmr_bufio_t*  bufio )
548{
549    giet_pthread_assert( ( bufio->is_input ) ,
550    "ERROR in mwmr_bufio_align() : bufio not input\n");
551
552    uint32_t bytes_per_item = (bufio->mwmr->width)<<2;
553    uint32_t offset = bufio->ptr % bytes_per_item;
554
555    // align ptr on next item boundary if required
556    if ( offset )
557    {
558        bufio->ptr = bufio->ptr + bytes_per_item - offset;
559        if ( bufio-> ptr == bufio->max ) bufio->ptr = 0;
560    }
561}  // end mwmr_bufio_align()
562
563
564/////////////////////////////////////////////////
565void mwmr_bufio_write_byte( mwmr_bufio_t*  bufio,
566                            uint8_t        value )
567{
568    giet_pthread_assert( ( !bufio->is_input ) ,
569    "ERROR in mwmr_bufio_write_byte() : bufio not output\n"); 
570
571    bufio->base[bufio->ptr] = value;
572
573    bufio->ptr++;
574    if ( bufio->ptr == bufio->nbytes )  // flush bufio
575    {
576        // move data to mwmr channel
577        mwmr_write( bufio->mwmr , (uint32_t*)bufio->base , bufio->nitems );
578
579        // reinitialise bufio
580        bufio->ptr = 0;
581
582#if GIET_DEBUG_USER_MWMR
583giet_tty_printf("\n[DEBUG MWMR] mwmr_bufio_write_byte() write %d bytes to mwmr\n", 
584                bufio->nbytes );
585uint32_t i = 0;
586while ( i < bufio->nbytes )
587{
588    giet_tty_printf(" %x", bufio->base[i] );
589    if ( (i & 0xF) == 0xF ) giet_tty_printf("\n");
590    i++;
591}
592giet_tty_printf("\n");
593#endif
594    }
595}  // end mwmr_bufio_write_byte()
596
597/////////////////////////////////////////////
598void mwmr_bufio_flush( mwmr_bufio_t*  bufio )
599{
600    giet_pthread_assert( ( !bufio->is_input ) ,
601    "ERROR in mwmr_bufio_flush() : bufio not output\n"); 
602
603    uint32_t i;
604
605    uint32_t bytes_per_item = (bufio->mwmr->width)<<2;
606
607    // do nothing if bufio empty
608    if ( bufio->ptr == 0 ) return;
609   
610    // compute number of items and extra bytes to be moved to MWMR channel
611    uint32_t nitems = bufio->ptr / bytes_per_item;
612    uint32_t offset = bufio->ptr % bytes_per_item; 
613
614    // completes last item with 0 if required
615    if ( offset )
616    { 
617        for( i = bufio->ptr;
618             i < bufio->ptr + bytes_per_item - offset ; 
619             i++ ) bufio->base[i] = 0;
620
621        nitems++;
622    }
623
624#if GIET_DEBUG_USER_MWMR
625giet_tty_printf("\n[DEBUG MWMR] mwmr_bufio_flush() write %d bytes to mwmr\n", 
626                nitems * bytes_per_item );
627uint32_t j = 0;
628while ( j < (nitems * bytes_per_item) )
629{
630    giet_tty_printf(" %x", bufio->base[j] );
631    if ( (j & 0xF) == 0xF ) giet_tty_printf("\n");
632    j++;
633}
634giet_tty_printf("\n");
635#endif
636
637    // move nitems to mwmr channel
638    mwmr_write( bufio->mwmr , (uint32_t*)bufio->base , nitems );
639
640    // reinitialise bufio
641    bufio->ptr = 0;
642
643}  // end mwmr_bufio_flush()
644
645
646   
647// Local Variables:
648// tab-width: 4
649// c-basic-offset: 4
650// c-file-offsets:((innamespace . 0)(inline-open . 0))
651// indent-tabs-mode: nil
652// End:
653// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
654
Note: See TracBrowser for help on using the repository browser.