source: soft/giet_vm/libs/mwmr.c @ 158

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

Introducing the giet_vm and some example applications

File size: 6.6 KB
RevLine 
[158]1//////////////////////////////////////////////////////////////////////////////////
2// File     : mwmr.c         
3// Date     : 01/04/2012
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7// The mwmr.c and mwmr.h files are part of the GIET nano-kernel.
8// This  middlewre implements a user level Multi-Writers / Multi-Readers
9// communication channel, that can be sued 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//
14// The mwmr_get_base() returns the virtual base address of the MWMR channel.
15// As this function requires a system call, it is defined in the stdio.c and
16// stdio.h files.
17//
18// ALL MWMR channels must be defined in the mapping_info data structure,
19// to be initialised by the GIET in the boot phase.
20// The max number of words that can be stored in a MWMR channel is defined by the
21// depth parameter, but all MWMR channels are implemented as fixed size buffers,
22// and the size is defined by the GIET_MWMR_SIZE_MAX configuration parameter.
23// An MWMR transaction is an integer number of unsigned int (32 bits mwords).
24// Both the mwmr_read() and mwmr_write() functions are blocking functions.
25// A private lock provides exclusive access to the MWMR channel, that can have
26// a variable number of producers and a variable number of consumers.
27///////////////////////////////////////////////////////////////////////////////////
28
29#include <mwmr.h>
30#include <stdio.h>
31
32///////////////////////////////////////////////////////////////////////////////////
33//      mwmr_lock_acquire()
34// We use a fixed delay befor retry, in order to avoid the system call
35// associated to the rand() function.
36// This is probably a weakness, that can be improved...
37///////////////////////////////////////////////////////////////////////////////////
38inline void mwmr_lock_acquire(unsigned int* lock)
39{
40    asm volatile (
41            "lock_try:              \n"
42            "ll   $2,    0(%0)      \n" /* $2 <= lock current value */
43            "bnez $2,    lock_delay \n" /* retry if lock already taken */
44            "li   $3,    1          \n" /* $3 <= argument for sc */
45            "sc   $3,    0(%0)      \n" /* try to get lock */
46            "bnez $3,    lock_ok    \n" /* exit if atomic */
47            "lock_delay:            \n"
48            "li   $4,    100        \n" /* $4 <= delay */
49            "lock_loop:             \n"
50            "addi $4,    $4,  -1    \n" /* $4 <= $4 - 1 */
51            "beqz $4,    lock_loop  \n" /* test end delay */
52            "nop                    \n"
53            "j           lock_try   \n" /* retry if not atomic */
54            "nop                    \n"
55            "lock_ok:               \n"
56            :
57            :"r"(lock)
58            :"$2", "$3", "$4");
59} 
60
61//////////////////////////////////////////////////////////////////////////////
62//      mwmr_write()
63// This blocking function returns only when the transfer is completed.
64// It takes the lock for exclusive access before testing the channel state.
65// If there is not enough space in mwmr channel to write nwords words,
66// it writes as many words as possible, release the lock, and retry after
67// a random delay.
68//////////////////////////////////////////////////////////////////////////////
69void mwmr_write( mwmr_channel_t*        mwmr, 
70                 unsigned int*          buffer,
71                 unsigned int           nwords )
72{
73    unsigned int        x;
74    unsigned int        spaces;
75
76    while(1)
77    {
78        // get the lock
79        mwmr_lock_acquire((unsigned int*)&mwmr->lock);
80
81        // compute number of empty slots
82        spaces = mwmr->depth - mwmr->sts;
83
84        if( spaces >= nwords )  // write nwords, release lock and return
85        {
86            for ( x = 0 ; x < nwords ; x++ ) 
87            {
88                mwmr->data[mwmr->ptw] = buffer[x];
89                mwmr->ptw  = (mwmr->ptw + 1) % mwmr->depth;
90            }
91            mwmr->sts  = mwmr->sts + nwords;
92            mwmr->lock = 0;
93            return;
94        }
95        else if ( spaces == 0 ) // release lock and retry after delay
96        {
97            mwmr->lock = 0;
98            for ( x = rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
99        }
100        else            // write spaces, release lock and retry after delay
101        {
102            for ( x = 0 ; x < spaces ; x++ ) 
103            {
104                mwmr->data[mwmr->ptw] = buffer[x];
105                mwmr->ptw  = (mwmr->ptw + 1) % mwmr->depth;
106            }
107            mwmr->sts  = mwmr->depth;
108            nwords     = nwords - spaces;
109            buffer     = buffer + spaces;
110            mwmr->lock = 0;
111        }
112
113        // random delay before retry
114        for ( x = rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
115    }
116} 
117
118//////////////////////////////////////////////////////////////////////////////
119//      mwmr_read()
120// This blocking function returns only when the transfer is completed.
121// It takes the lock for exclusive access before testing the channel state.
122// If there is not enough data in mwmr channel to read nwords words,
123// it reads as many words as possible, release the lock, and retry after
124// a random delay.
125//////////////////////////////////////////////////////////////////////////////
126void mwmr_read( mwmr_channel_t*         mwmr, 
127                unsigned int*           buffer,
128                unsigned int            nwords )
129{
130    unsigned int        x;
131    unsigned int        dispos;
132
133    while(1)
134    {
135        // get the lock
136        mwmr_lock_acquire((unsigned int*)&mwmr->lock);
137
138        // compute number of available words
139        dispos = mwmr->sts;
140
141        if( dispos >= nwords )  // read nwords, release lock and return
142        {
143            for ( x = 0 ; x < nwords ; x++ ) 
144            {
145                buffer[x] = mwmr->data[mwmr->ptr];
146                mwmr->ptr  = (mwmr->ptr + 1) % mwmr->depth;
147            }
148            mwmr->sts  = mwmr->sts - nwords;
149            mwmr->lock = 0;
150            return;
151        }
152        else if ( dispos == 0 ) // release lock and retry after delay
153        {
154            mwmr->lock = 0;
155            for ( x = rand()>>8 ; x > 0 ; x-- ) asm volatile ( "nop" );
156        }
157        else            // read dispos, release lock and retry after delay
158        {
159            for ( x = 0 ; x < dispos ; x++ ) 
160            {
161                buffer[x] = mwmr->data[mwmr->ptr];
162                mwmr->ptr  = (mwmr->ptr + 1) % mwmr->depth;
163            }
164            mwmr->sts  = 0;
165            nwords     = nwords - dispos;
166            buffer     = buffer + dispos;
167            mwmr->lock = 0;
168        }
169
170        // random delay before retry
171        for ( x = rand()>>6 ; x > 0 ; x-- ) asm volatile ( "nop" );
172    }
173} 
174
Note: See TracBrowser for help on using the repository browser.