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

Last change on this file since 238 was 228, checked in by meunier, 12 years ago

Added support for memspaces and const.
Added an interrupt masking to the "giet_context_switch" syscall
Corrected two bugs in boot/boot_init.c (one minor and one regarding barriers initialization)
Reformatted the code in all files.

File size: 13.1 KB
RevLine 
[159]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,
[165]14// if the platform does not provide hardware cache coherence.
[159]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//
[228]21// An MWMR transaction transfer    an integer number of items, and an item is
[159]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
36//////////////////////////////////////////////////////////////////////////////
37//  mwmr_lock_aquire()
38// This blocking function returns only when the lock has been taken.
[165]39// If the lock is already taken a fixed delay is introduced before retry.
[159]40//////////////////////////////////////////////////////////////////////////////
[228]41void mwmr_lock_acquire(unsigned int * lock_address) {
42    register unsigned int * plock = lock_address;
43    register unsigned int delay = 100;
[159]44    asm volatile (
[228]45            "mwmr_lock_try:                    \n"
46            "ll   $2,    0(%0)                \n" /* $2 <= lock current value */
47            "bnez $2,    mwmr_lock_delay    \n" /* retry after delay if lock busy */
48            "li   $3,    1                    \n" /* $3 <= argument for sc */
49            "sc   $3,    0(%0)                \n" /* try to get lock */
50            "bnez $3,    mwmr_lock_ok        \n" /* exit if atomic */
51            "mwmr_lock_delay:                \n"
[165]52            "move $4,    %1                 \n" /* $4 <= delay */
53            "mwmr_lock_loop:                \n"
[228]54            "beqz $4,    mwmr_lock_loop        \n" /* test end delay */
55            "addi $4,    $4,  -1            \n" /* $4 <= $4 - 1 */
56            "j           mwmr_lock_try        \n" /* retry ll */
57            "nop                            \n"
58            "mwmr_lock_ok:                    \n"
[159]59            :
[165]60            :"r"(plock), "r"(delay)
[159]61            :"$2", "$3", "$4");
62} 
[228]63
64
[207]65//////////////////////////////////////////////////////////////////////////////
[228]66//       nb_mwmr_write()
[207]67// This is a non-blocking function.
68// The nitems parameter is the number of items to be transfered.
69// The requested transfer is therefore (nitems * width) words.
70// It takes the lock for exclusive access before testing the channel state.
71// If there is not enough data in mwmr channel to read nitems,
72// it reads as many items as possible, releases the lock, and returns
73// the number of read items (it can be 0).
74//////////////////////////////////////////////////////////////////////////////
[228]75unsigned int nb_mwmr_write(mwmr_channel_t * mwmr, unsigned int * buffer, unsigned int nitems) {
76    unsigned int x;
77    unsigned int spaces; // number of empty slots (in words)
78    unsigned int nwords; // requested transfer length (in words)
79    unsigned int depth;  // channel depth (in words)
80    unsigned int width;  // channel width (in words)
81    unsigned int sts;    // channel sts
82    unsigned int ptw;    // channel ptw
[159]83
[228]84    if (nitems == 0) {
85        return 0;
86    }
[207]87
88    // get the lock
[228]89    mwmr_lock_acquire(&mwmr->lock);
[207]90
91    // access fifo status
[228]92    depth = mwmr->depth;
93    width = mwmr->width;
94    sts = mwmr->sts;
95    ptw = mwmr->ptw;
[207]96    spaces = depth - sts;
97    nwords = width * nitems;
98
[228]99    if (spaces >= nwords) { // transfer nitems, release lock and return
100        for (x = 0; x < nwords; x++) {
[207]101            mwmr->data[ptw] = buffer[x];
[228]102            if ((ptw + 1) == depth) {
103                ptw = 0;
104            }
105            else {
106                ptw = ptw + 1;
107            }
[207]108        }
[228]109        mwmr->sts = mwmr->sts + nwords;
110        mwmr->ptw = ptw;
[207]111        mwmr->lock = 0;
112        return nitems;
113    }
[228]114    else if (spaces < width) {
115        // release lock and return
[207]116        mwmr->lock = 0;
117        return 0;
118    }
[228]119    else {
120        // transfer as many items as possible, release lock and return
121        nwords = (spaces / width) * width;    // integer number of items
122        for (x = 0; x < nwords; x++) {
[207]123            mwmr->data[ptw] = buffer[x];
[228]124            if ((ptw + 1) == depth) {
125                ptw = 0;
126            }
127            else {
128                ptw = ptw + 1;
129            }
[207]130        }
[228]131        mwmr->sts = sts + nwords;
132        mwmr->ptw = ptw;
[207]133        mwmr->lock = 0;
[228]134        return (nwords / width);
[207]135    }
136} // end nb_mwmr_write()
137
[228]138
[159]139//////////////////////////////////////////////////////////////////////////////
[228]140//    mwmr_write()
[159]141// This blocking function returns only when the transfer is completed.
142// The nitems parameter is the number of items to be transfered.
143// The requested transfer is therefore (nitems * width) words.
144// It takes the lock for exclusive access before testing the channel state.
145// If there is not enough space in mwmr channel to write nitems,
146// it writes as many items as possible, releases the lock, and retry
147// after a random delay.
148//////////////////////////////////////////////////////////////////////////////
[228]149void mwmr_write(mwmr_channel_t * mwmr, unsigned int * buffer, unsigned int nitems) {
150    unsigned int x;
151    unsigned int spaces; // number of empty slots (in words)
152    unsigned int nwords; // requested transfer length (in words)
153    unsigned int depth;  // channel depth (in words)
154    unsigned int width;  // channel width (in words)
155    unsigned int sts;    // channel sts
156    unsigned int ptw;    // channel ptw
[159]157
[228]158    if (nitems == 0) {
159        return;
160    }
[175]161
[228]162    while (1) {
[159]163        // get the lock
164        mwmr_lock_acquire(&mwmr->lock);
165
166        // compute spaces and nwords
[228]167        depth = mwmr->depth;
168        width = mwmr->width;
169        sts  = mwmr->sts;
170        ptw  = mwmr->ptw;
[159]171        spaces = depth - sts;
172        nwords = width * nitems;
173
[228]174        if (spaces >= nwords) {
175            // write nwords, release lock and return
176            for (x = 0; x < nwords; x++) {
[159]177                mwmr->data[ptw] = buffer[x];
[228]178                if ((ptw + 1) == depth) {
179                    ptw = 0;
180                }
181                else {
182                    ptw = ptw + 1;
183                }
[159]184            }
[228]185            mwmr->ptw = ptw;
186            mwmr->sts = sts + nwords;
[159]187            mwmr->lock = 0;
188            return;
189        }
[228]190        else if (spaces < width) {
191            // release lock and retry after delay
[159]192            mwmr->lock = 0;
193        }
[228]194        else {
195            // write as many items as possible, release lock and retry after delay
196            nwords = (spaces / width) * width;  // integer number of items
197            for (x = 0; x < nwords; x++) {
[159]198                mwmr->data[ptw] = buffer[x];
[228]199                if ((ptw + 1) == depth) {
200                    ptw = 0;
201                }
202                else {
203                    ptw = ptw + 1;
204                }
[159]205            }
[228]206            mwmr->sts = sts + nwords;
207            mwmr->ptw = ptw;
208            buffer = buffer + nwords;
209            nitems = nitems - (nwords/width);
[159]210            mwmr->lock = 0;
211        }
[228]212        giet_context_switch();
[159]213    }
[207]214} // end mwmr_write()
[159]215
[228]216
[159]217//////////////////////////////////////////////////////////////////////////////
[228]218//       nb_mwmr_read()
[207]219// This is a non-blocking function.
220// The nitems parameter is the number of items to be transfered.
221// The requested transfer is therefore (nitems * width) words.
222// It takes the lock for exclusive access before testing the channel state.
223// If there is not enough data in mwmr channel to read nitems,
224// it reads as many items as possible, releases the lock, and returns
225// the number of read items (it can be 0).
226//////////////////////////////////////////////////////////////////////////////
[228]227unsigned int nb_mwmr_read(mwmr_channel_t * mwmr, unsigned int * buffer, unsigned int nitems) {
228    unsigned int x;
229    unsigned int nwords; // requested transfer length (in words)
230    unsigned int depth;  // channel depth (in words)
231    unsigned int width;  // channel width (in words)
232    unsigned int sts;    // channel sts
233    unsigned int ptr;    // channel ptr
[207]234
[228]235    if (nitems == 0) {
236        return 0;
237    }
[207]238
239    // get the lock
[228]240    mwmr_lock_acquire(&mwmr->lock);
[207]241
242    // access fifo status
[228]243    depth = mwmr->depth;
244    width = mwmr->width;
245    sts = mwmr->sts;
246    ptr = mwmr->ptr;
[207]247    nwords = width * nitems;
248
[228]249    if (sts >= nwords) {
250        // transfer nitems, release lock and return
251        for (x = 0; x < nwords; x++) {
[207]252            buffer[x] = mwmr->data[ptr];
[228]253            if ((ptr + 1) == depth) {
254                ptr = 0;
255            }
256            else {
257                ptr = ptr + 1;
258            }
[207]259        }
[228]260        mwmr->sts = mwmr->sts - nwords;
261        mwmr->ptr = ptr;
[207]262        mwmr->lock = 0;
263        return nitems;
264    }
[228]265    else if (sts < width) {
266        // release lock and return
[207]267        mwmr->lock = 0;
268        return 0;
269    }
[228]270    else {
271        // transfer as many items as possible, release lock and return
272        nwords = (sts / width) * width; // integer number of items
273        for (x = 0 ; x < nwords ; x++) {
[207]274            buffer[x] = mwmr->data[ptr];
[228]275            if ((ptr + 1) == depth) {
276                ptr = 0;
277            }
278            else {
279                ptr = ptr + 1;
280            }
[207]281        }
[228]282        mwmr->sts = sts - nwords;
283        mwmr->ptr = ptr;
[207]284        mwmr->lock = 0;
[228]285        return (nwords / width);
[207]286    }
[228]287} // nb_mwmr_read()
[207]288
[228]289
[207]290//////////////////////////////////////////////////////////////////////////////
[228]291//    mwmr_read()
[159]292// This blocking function returns only when the transfer is completed.
293// The nitems parameter is the number of items to be transfered.
294// The requested transfer is therefore (nitems * width) words.
295// It takes the lock for exclusive access before testing the channel state.
296// If there is not enough data in mwmr channel to read nitems,
297// it reads as many items as possible, releases the lock, and retry
298// after a random delay.
299//////////////////////////////////////////////////////////////////////////////
[228]300void mwmr_read( mwmr_channel_t * mwmr, unsigned int * buffer, unsigned int nitems) {
301    unsigned int x;
302    unsigned int nwords; // requested transfer length (in words)
303    unsigned int depth;  // channel depth (in words)
304    unsigned int width;  // channel width (in words)
305    unsigned int sts;    // channel sts
306    unsigned int ptr;    // channel ptr
[159]307
[228]308    if (nitems == 0) {
309        return;
310    }
[175]311
[228]312    while (1) {
[159]313        // get the lock
[228]314        mwmr_lock_acquire(&mwmr->lock);
[159]315
316        // compute nwords
[228]317        depth = mwmr->depth;
318        width = mwmr->width;
319        sts = mwmr->sts;
320        ptr = mwmr->ptr;
[159]321        nwords = width * nitems;
322
[228]323        if (sts >= nwords) {
324            // read nwords, release lock and return
325            for (x = 0; x < nwords; x++) {
[159]326                buffer[x] = mwmr->data[ptr];
[228]327                if ((ptr + 1) == depth) {
328                    ptr = 0;
329                }
330                else {
331                    ptr = ptr + 1;
332                }
[159]333            }
[228]334            mwmr->sts = mwmr->sts - nwords;
335            mwmr->ptr = ptr;
[159]336            mwmr->lock = 0;
337            return;
338        }
[228]339        else if (sts < width) {
340            // release lock and retry after delay
[159]341            mwmr->lock = 0;
342        }
[228]343        else {   // read as many items as possible, release lock and retry after delay
344            nwords = (sts / width) * width; // integer number of items
345            for (x = 0; x < nwords; x++) {
[200]346                buffer[x] = mwmr->data[ptr];
[228]347                if ((ptr + 1) == depth) {
348                    ptr = 0;
349                }
350                else {
351                    ptr = ptr + 1;
352                }
[159]353            }
[228]354            mwmr->sts = sts - nwords;
355            mwmr->ptr = ptr;
356            buffer = buffer + nwords;
357            nitems = nitems - (nwords/width);
[159]358            mwmr->lock = 0;
359        }
[228]360        giet_context_switch();
[159]361    }
[207]362} // end mwmr_read()
[159]363
[207]364
[228]365// Local Variables:
366// tab-width: 4
367// c-basic-offset: 4
368// c-file-offsets:((innamespace . 0)(inline-open . 0))
369// indent-tabs-mode: nil
370// End:
371// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
372
Note: See TracBrowser for help on using the repository browser.