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

Last change on this file since 159 was 159, checked in by alain, 12 years ago

Introducing the spin_locks / modifying the MWMR channels and the barriers

File size: 8.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// 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 hardwate 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 random delay is introduced before retry.
40//////////////////////////////////////////////////////////////////////////////
41void mwmr_lock_acquire(unsigned int* plock)
42{
43    asm volatile (
44            "mwmr_lock_try:                                     \n"
45            "ll   $2,    0(%0)                          \n" /* $2 <= lock current value */
46            "bnez $2,    mwmr_lock_delay        \n" /* retry if lock already taken */
47            "li   $3,    1                                      \n" /* $3 <= argument for sc */
48            "sc   $3,    0(%0)                          \n" /* try to get lock */
49            "bnez $3,    mwmr_lock_ok           \n" /* exit if atomic */
50
51            "mwmr_lock_delay:                           \n"
52            "jal  rand                                  \n" /* rand() system call */
53            "nop                                                        \n"
54            "andi $4,   $2,     0xFF                    \n"     /* $4 <= random delay < 256 cycles */
55
56            "mwmr_lock_loop:                            \n"
57            "addi $4,    $4,  -1                        \n" /* $4 <= $4 - 1 */
58            "beqz $4,    mwmr_lock_loop         \n" /* test end delay */
59            "nop                                                        \n"
60            "j           mwmr_lock_try          \n" /* retry */
61            "nop                                                        \n"
62            "mwmr_lock_ok:                                      \n"
63            :
64            :"r"(plock)
65            :"$2", "$3", "$4");
66} 
67
68//////////////////////////////////////////////////////////////////////////////
69//      mwmr_write()
70// This blocking function returns only when the transfer is completed.
71// The nitems parameter is the number of items to be transfered.
72// The requested transfer is therefore (nitems * width) words.
73// It takes the lock for exclusive access before testing the channel state.
74// If there is not enough space in mwmr channel to write nitems,
75// it writes as many items as possible, releases the lock, and retry
76// after a random delay.
77//////////////////////////////////////////////////////////////////////////////
78void mwmr_write( mwmr_channel_t*        mwmr, 
79                 unsigned int*          buffer,
80                 unsigned int           nitems )
81{
82    unsigned int        x;
83    unsigned int        spaces;         // number of empty slots (in words)
84    unsigned int        nwords;         // requested transfer length (in words)
85    unsigned int    depth;              // channel depth (in words)
86    unsigned int    width;              // channel width (in words)
87    unsigned int    sts;        // channel sts
88    unsigned int    ptw;        // channel ptw
89
90    while(1)
91    {
92        // get the lock
93        mwmr_lock_acquire(&mwmr->lock);
94
95        // compute spaces and nwords
96        depth  = mwmr->depth;
97        width  = mwmr->width;
98        sts    = mwmr->sts;
99        ptw    = mwmr->ptw;
100        spaces = depth - sts;
101        nwords = width * nitems;
102
103        if( spaces >= nwords )  // write nwords, release lock and return
104        {
105            for ( x = 0 ; x < nwords ; x++ ) 
106            {
107                mwmr->data[ptw] = buffer[x];
108                if ( (ptw + 1) == depth ) ptw = 0;
109                else                      ptw = ptw + 1;
110            }
111            mwmr->ptw  = ptw;
112            mwmr->sts  = sts + nwords;
113            mwmr->lock = 0;
114            return;
115        }
116        else if ( spaces < width )      // release lock and retry after delay
117        {
118            mwmr->lock = 0;
119            for ( x = rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
120        }
121        else    // write as many items as possible, release lock and retry after delay
122        {
123            nwords = (spaces/width) * width;  // integer nmber of items
124            for ( x = 0 ; x < nwords ; x++ ) 
125            {
126                mwmr->data[ptw] = buffer[x];
127                if ( (ptw + 1) == depth ) ptw = 0;
128                else                      ptw = ptw + 1;
129            }
130            mwmr->sts  = sts + nwords;
131            mwmr->ptw  = ptw;
132            buffer     = buffer + nwords;
133            nitems     = nitems - (nwords/width);
134            mwmr->lock = 0;
135        }
136        // random delay before retry
137        for ( x = rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
138    }
139} 
140
141//////////////////////////////////////////////////////////////////////////////
142//      mwmr_read()
143// This blocking function returns only when the transfer is completed.
144// The nitems parameter is the number of items to be transfered.
145// The requested transfer is therefore (nitems * width) words.
146// It takes the lock for exclusive access before testing the channel state.
147// If there is not enough data in mwmr channel to read nitems,
148// it reads as many items as possible, releases the lock, and retry
149// after a random delay.
150//////////////////////////////////////////////////////////////////////////////
151void mwmr_read( mwmr_channel_t*         mwmr, 
152                unsigned int*           buffer,
153                unsigned int            nitems )
154{
155    unsigned int        x;
156    unsigned int        nwords;         // requested transfer length (in words)
157    unsigned int    depth;              // channel depth (in words)
158    unsigned int    width;              // channel width (in words)
159    unsigned int    sts;        // channel sts
160    unsigned int    ptr;        // channel ptw
161
162    while(1)
163    {
164        // get the lock
165        mwmr_lock_acquire( &mwmr->lock );
166
167        // compute nwords
168        depth  = mwmr->depth;
169        width  = mwmr->width;
170        sts    = mwmr->sts;
171        ptr    = mwmr->ptr;
172        nwords = width * nitems;
173
174        if( sts >= nwords )     // read nwords, release lock and return
175        {
176            for ( x = 0 ; x < nwords ; x++ ) 
177            {
178                buffer[x] = mwmr->data[ptr];
179                if ( (ptr + 1) == depth ) ptr = 0;
180                else                      ptr = ptr + 1;
181            }
182            mwmr->sts  = mwmr->sts - nwords;
183            mwmr->ptr  = ptr;
184            mwmr->lock = 0;
185            return;
186        }
187        else if ( sts < width ) // release lock and retry after delay
188        {
189            mwmr->lock = 0;
190            for ( x = rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
191        }
192        else    // read as many items as possible, release lock and retry after delay
193        {
194            nwords = (sts/width) * width;       // integer number of items
195            for ( x = 0 ; x < nwords ; x++ ) 
196            {
197                buffer[x] = mwmr->data[mwmr->ptr];
198                if ( (ptr + 1) == depth ) ptr = 0;
199                else                      ptr = ptr + 1;
200            }
201            mwmr->sts  = sts - nwords;
202            mwmr->ptr  = ptr;
203            buffer     = buffer + nwords;
204            nitems     = nitems - (nwords/width);
205            mwmr->lock = 0;
206        }
207        // random delay before retry
208        for ( x = rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
209    }
210} 
211
Note: See TracBrowser for help on using the repository browser.