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

Last change on this file since 395 was 345, checked in by cfuguet, 10 years ago

giet_vm optimizations:

  • Several modifications in GIET_VM in order to support compilation with GCC optimizations (-O2) activated.
  • Adding missing volatile in some global variables.
  • Using ioread and iowrite utility functions in peripheral drivers which prevent GCC to remove writes or reads in hardware memory mapped registers.
  • Code refactoring of stdio printf functions. Now, shr_printf and tty_printf function reuse the same function body. The only difference is that shr_printf wraps printf function call with TTY get lock and release lock.
  • Property svn:executable set to *
File size: 13.1 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
36//////////////////////////////////////////////////////////////////////////////
37//  mwmr_lock_aquire()
38// This blocking function returns only when the lock has been taken.
39// If the lock is already taken a fixed delay is introduced before retry.
40//////////////////////////////////////////////////////////////////////////////
41void mwmr_lock_acquire(unsigned int * lock_address) {
42    register unsigned int * plock = lock_address;
43    register unsigned int delay = 100;
44    asm volatile (
45            "1:                               \n"
46            "ll   $2,    0(%0)                \n" /* $2 <= lock current value */
47            "bnez $2,    2f                   \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,    3f                   \n" /* exit if atomic */
51            "2:                               \n"
52            "move $4,    %1                   \n" /* $4 <= delay */
53            "4:                               \n"
54            "beqz $4,    4b                   \n" /* test end delay */
55            "addi $4,    $4,  -1              \n" /* $4 <= $4 - 1 */
56            "j           1b                   \n" /* retry ll */
57            "nop                              \n"
58            "3:                               \n"
59            :
60            :"r"(plock), "r"(delay)
61            :"$2", "$3", "$4");
62} 
63
64
65//////////////////////////////////////////////////////////////////////////////
66//       nb_mwmr_write()
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//////////////////////////////////////////////////////////////////////////////
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
83
84    if (nitems == 0) {
85        return 0;
86    }
87
88    // get the lock
89    mwmr_lock_acquire(&mwmr->lock);
90
91    // access fifo status
92    depth = mwmr->depth;
93    width = mwmr->width;
94    sts = mwmr->sts;
95    ptw = mwmr->ptw;
96    spaces = depth - sts;
97    nwords = width * nitems;
98
99    if (spaces >= nwords) { // transfer nitems, release lock and return
100        for (x = 0; x < nwords; x++) {
101            mwmr->data[ptw] = buffer[x];
102            if ((ptw + 1) == depth) {
103                ptw = 0;
104            }
105            else {
106                ptw = ptw + 1;
107            }
108        }
109        mwmr->sts = mwmr->sts + nwords;
110        mwmr->ptw = ptw;
111        mwmr->lock = 0;
112        return nitems;
113    }
114    else if (spaces < width) {
115        // release lock and return
116        mwmr->lock = 0;
117        return 0;
118    }
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++) {
123            mwmr->data[ptw] = buffer[x];
124            if ((ptw + 1) == depth) {
125                ptw = 0;
126            }
127            else {
128                ptw = ptw + 1;
129            }
130        }
131        mwmr->sts = sts + nwords;
132        mwmr->ptw = ptw;
133        mwmr->lock = 0;
134        return (nwords / width);
135    }
136} // end nb_mwmr_write()
137
138
139//////////////////////////////////////////////////////////////////////////////
140//    mwmr_write()
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//////////////////////////////////////////////////////////////////////////////
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
157
158    if (nitems == 0) {
159        return;
160    }
161
162    while (1) {
163        // get the lock
164        mwmr_lock_acquire(&mwmr->lock);
165
166        // compute spaces and nwords
167        depth = mwmr->depth;
168        width = mwmr->width;
169        sts  = mwmr->sts;
170        ptw  = mwmr->ptw;
171        spaces = depth - sts;
172        nwords = width * nitems;
173
174        if (spaces >= nwords) {
175            // write nwords, release lock and return
176            for (x = 0; x < nwords; x++) {
177                mwmr->data[ptw] = buffer[x];
178                if ((ptw + 1) == depth) {
179                    ptw = 0;
180                }
181                else {
182                    ptw = ptw + 1;
183                }
184            }
185            mwmr->ptw = ptw;
186            mwmr->sts = sts + nwords;
187            mwmr->lock = 0;
188            return;
189        }
190        else if (spaces < width) {
191            // release lock and retry after delay
192            mwmr->lock = 0;
193        }
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++) {
198                mwmr->data[ptw] = buffer[x];
199                if ((ptw + 1) == depth) {
200                    ptw = 0;
201                }
202                else {
203                    ptw = ptw + 1;
204                }
205            }
206            mwmr->sts = sts + nwords;
207            mwmr->ptw = ptw;
208            buffer = buffer + nwords;
209            nitems = nitems - (nwords/width);
210            mwmr->lock = 0;
211        }
212        giet_context_switch();
213    }
214} // end mwmr_write()
215
216
217//////////////////////////////////////////////////////////////////////////////
218//       nb_mwmr_read()
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//////////////////////////////////////////////////////////////////////////////
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
234
235    if (nitems == 0) {
236        return 0;
237    }
238
239    // get the lock
240    mwmr_lock_acquire(&mwmr->lock);
241
242    // access fifo status
243    depth = mwmr->depth;
244    width = mwmr->width;
245    sts = mwmr->sts;
246    ptr = mwmr->ptr;
247    nwords = width * nitems;
248
249    if (sts >= nwords) {
250        // transfer nitems, release lock and return
251        for (x = 0; x < nwords; x++) {
252            buffer[x] = mwmr->data[ptr];
253            if ((ptr + 1) == depth) {
254                ptr = 0;
255            }
256            else {
257                ptr = ptr + 1;
258            }
259        }
260        mwmr->sts = mwmr->sts - nwords;
261        mwmr->ptr = ptr;
262        mwmr->lock = 0;
263        return nitems;
264    }
265    else if (sts < width) {
266        // release lock and return
267        mwmr->lock = 0;
268        return 0;
269    }
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++) {
274            buffer[x] = mwmr->data[ptr];
275            if ((ptr + 1) == depth) {
276                ptr = 0;
277            }
278            else {
279                ptr = ptr + 1;
280            }
281        }
282        mwmr->sts = sts - nwords;
283        mwmr->ptr = ptr;
284        mwmr->lock = 0;
285        return (nwords / width);
286    }
287} // nb_mwmr_read()
288
289
290//////////////////////////////////////////////////////////////////////////////
291//    mwmr_read()
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//////////////////////////////////////////////////////////////////////////////
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
307
308    if (nitems == 0) {
309        return;
310    }
311
312    while (1) {
313        // get the lock
314        mwmr_lock_acquire(&mwmr->lock);
315
316        // compute nwords
317        depth = mwmr->depth;
318        width = mwmr->width;
319        sts = mwmr->sts;
320        ptr = mwmr->ptr;
321        nwords = width * nitems;
322
323        if (sts >= nwords) {
324            // read nwords, release lock and return
325            for (x = 0; x < nwords; x++) {
326                buffer[x] = mwmr->data[ptr];
327                if ((ptr + 1) == depth) {
328                    ptr = 0;
329                }
330                else {
331                    ptr = ptr + 1;
332                }
333            }
334            mwmr->sts = mwmr->sts - nwords;
335            mwmr->ptr = ptr;
336            mwmr->lock = 0;
337            return;
338        }
339        else if (sts < width) {
340            // release lock and retry after delay
341            mwmr->lock = 0;
342        }
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++) {
346                buffer[x] = mwmr->data[ptr];
347                if ((ptr + 1) == depth) {
348                    ptr = 0;
349                }
350                else {
351                    ptr = ptr + 1;
352                }
353            }
354            mwmr->sts = sts - nwords;
355            mwmr->ptr = ptr;
356            buffer = buffer + nwords;
357            nitems = nitems - (nwords/width);
358            mwmr->lock = 0;
359        }
360        giet_context_switch();
361    }
362} // end mwmr_read()
363
364
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.