source: soft/giet_vm/libs/mwmr_channel.c @ 185

Last change on this file since 185 was 178, checked in by karaoui, 12 years ago

updating libs.

File size: 8.6 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : mwmr_channel_.c         
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The mwmr_channel.c and mwmr_channel.h files are part of the GIET nano-kernel.
8// This  middleware implements a user level Multi-Writers / Multi-Readers
9// communication channel, that can be used by parallel multi-tasks applications
10// respecting the TCG (Tasks and Communications Graph) formalism.
11//
12// The mwmr_read() and mwmr_write() functions do not require a system call.
13// The channel itself must have been allocated in a non cacheable segment,
14// if the platform does not provide hardware cache coherence.
15//
16// ALL MWMR channels must be defined in the mapping_info data structure,
17// to be initialised by the GIET in the boot phase.
18// The vobj_get_vbase() system call (defined in stdio.c and stdio.h files)
19// can be used to get the virtual base address of the channel from it's name.
20//
21// An MWMR transaction transfer an integer number of items, and an item is
22// an integer number of unsigned int (32 bits words).
23// The max number of words that can be stored in a MWMR channel is defined by the
24// "depth" parameter, and the "width" parameter define the minimal number of
25// word contained in an atomic item. Therefore, the "depth" parameter must be
26// a multiple of the "width" parameter.
27//
28// Both the mwmr_read() and mwmr_write() functions are blocking functions.
29// A private lock provides exclusive access to the MWMR channel, that can have
30// a variable number of producers and a variable number of consumers.
31///////////////////////////////////////////////////////////////////////////////////
32
33#include <mwmr_channel.h>
34#include <stdio.h>
35#include <common.h>
36
37//////////////////////////////////////////////////////////////////////////////
38//  mwmr_lock_aquire()
39// This blocking function returns only when the lock has been taken.
40// If the lock is already taken a fixed delay is introduced before retry.
41//////////////////////////////////////////////////////////////////////////////
42void mwmr_lock_acquire(unsigned int* lock_address)
43{
44    register unsigned int*      plock = lock_address;
45    register unsigned int       delay = 100;
46    asm volatile (
47            "mwmr_lock_try:                                     \n"
48            "ll   $2,    0(%0)                          \n" /* $2 <= lock current value */
49            "bnez $2,    mwmr_lock_delay        \n" /* retry after delay if lock busy */
50            "li   $3,    1                                      \n" /* $3 <= argument for sc */
51            "sc   $3,    0(%0)                          \n" /* try to get lock */
52            "bnez $3,    mwmr_lock_ok           \n" /* exit if atomic */
53            "mwmr_lock_delay:                           \n"
54            "move $4,    %1                 \n" /* $4 <= delay */
55            "mwmr_lock_loop:                \n"
56            "beqz $4,    mwmr_lock_loop         \n" /* test end delay */
57            "addi $4,    $4,  -1                        \n" /* $4 <= $4 - 1 */
58            "j           mwmr_lock_try          \n" /* retry ll */
59            "nop                                                        \n"
60            "mwmr_lock_ok:                                      \n"
61            :
62            :"r"(plock), "r"(delay)
63            :"$2", "$3", "$4");
64} 
65
66//////////////////////////////////////////////////////////////////////////////
67//      mwmr_write()
68// This blocking function returns only when the transfer is completed.
69// The nitems parameter is the number of items to be transfered.
70// The requested transfer is therefore (nitems * width) words.
71// It takes the lock for exclusive access before testing the channel state.
72// If there is not enough space in mwmr channel to write nitems,
73// it writes as many items as possible, releases the lock, and retry
74// after a random delay.
75//////////////////////////////////////////////////////////////////////////////
76void mwmr_write( mwmr_channel_t*            mwmr, 
77                 const unsigned int*    buffer,
78                 unsigned int               nitems )
79{
80    unsigned int        x;
81    unsigned int        spaces;         // number of empty slots (in words)
82    unsigned int        nwords;         // requested transfer length (in words)
83    unsigned int    depth;              // channel depth (in words)
84    unsigned int    width;              // channel width (in words)
85    unsigned int    sts;        // channel sts
86    unsigned int    ptw;        // channel ptw
87
88    if(nitems == 0)
89        return;
90
91    assert(buffer && "mwmr write: Empty buffer");
92
93    while(1)
94    {
95        // get the lock
96        mwmr_lock_acquire(&mwmr->lock);
97
98        // compute spaces and nwords
99        depth  = mwmr->depth;
100        width  = mwmr->width;
101        sts    = mwmr->sts;
102        ptw    = mwmr->ptw;
103        spaces = depth - sts;
104        nwords = width * nitems;
105
106        if( spaces >= nwords )  // write nwords, release lock and return
107        {
108            for ( x = 0 ; x < nwords ; x++ ) 
109            {
110                mwmr->data[ptw] = buffer[x];
111                if ( (ptw + 1) == depth ) ptw = 0;
112                else                      ptw = ptw + 1;
113            }
114            mwmr->ptw  = ptw;
115            mwmr->sts  = sts + nwords;
116            mwmr->lock = 0;
117            return;
118        }
119        else if ( spaces < width )      // release lock and retry after delay
120        {
121            mwmr->lock = 0;
122            for ( x = giet_rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
123        }
124        else    // write as many items as possible, release lock and retry after delay
125        {
126            nwords = (spaces/width) * width;  // integer number of items
127            for ( x = 0 ; x < nwords ; x++ ) 
128            {
129                mwmr->data[ptw] = buffer[x];
130                if ( (ptw + 1) == depth ) ptw = 0;
131                else                      ptw = ptw + 1;
132            }
133            mwmr->sts  = sts + nwords;
134            mwmr->ptw  = ptw;
135            buffer     = buffer + nwords;
136            nitems     = nitems - (nwords/width);
137            mwmr->lock = 0;
138        }
139        // random delay before retry
140        for ( x = giet_rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
141    }
142} 
143
144//////////////////////////////////////////////////////////////////////////////
145//      mwmr_read()
146// This blocking function returns only when the transfer is completed.
147// The nitems parameter is the number of items to be transfered.
148// The requested transfer is therefore (nitems * width) words.
149// It takes the lock for exclusive access before testing the channel state.
150// If there is not enough data in mwmr channel to read nitems,
151// it reads as many items as possible, releases the lock, and retry
152// after a random delay.
153//////////////////////////////////////////////////////////////////////////////
154void mwmr_read( mwmr_channel_t*         mwmr, 
155                unsigned int*           buffer,
156                unsigned int            nitems )
157{
158    unsigned int        x;
159    unsigned int        nwords;         // requested transfer length (in words)
160    unsigned int    depth;              // channel depth (in words)
161    unsigned int    width;              // channel width (in words)
162    unsigned int    sts;        // channel sts
163    unsigned int    ptr;        // channel ptw
164
165    if(nitems == 0)
166        return;
167
168    assert(buffer && "mwmr read: Empty buffer");
169
170    while(1)
171    {
172        // get the lock
173        mwmr_lock_acquire( &mwmr->lock );
174
175        // compute nwords
176        depth  = mwmr->depth;
177        width  = mwmr->width;
178        sts    = mwmr->sts;
179        ptr    = mwmr->ptr;
180        nwords = width * nitems;
181
182        if( sts >= nwords )     // read nwords, release lock and return
183        {
184            for ( x = 0 ; x < nwords ; x++ ) 
185            {
186                buffer[x] = mwmr->data[ptr];
187                if ( (ptr + 1) == depth ) ptr = 0;
188                else                      ptr = ptr + 1;
189            }
190            mwmr->sts  = mwmr->sts - nwords;
191            mwmr->ptr  = ptr;
192            mwmr->lock = 0;
193            return;
194        }
195        else if ( sts < width ) // release lock and retry after delay
196        {
197            mwmr->lock = 0;
198            for ( x = giet_rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
199        }
200        else    // read as many items as possible, release lock and retry after delay
201        {
202            nwords = (sts/width) * width;       // integer number of items
203            for ( x = 0 ; x < nwords ; x++ ) 
204            {
205                buffer[x] = mwmr->data[mwmr->ptr];
206                if ( (ptr + 1) == depth ) ptr = 0;
207                else                      ptr = ptr + 1;
208            }
209            mwmr->sts  = sts - nwords;
210            mwmr->ptr  = ptr;
211            buffer     = buffer + nwords;
212            nitems     = nitems - (nwords/width);
213            mwmr->lock = 0;
214        }
215        // random delay before retry
216        for ( x = giet_rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
217    }
218} 
219
Note: See TracBrowser for help on using the repository browser.