dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / lib / spu / WindowedFifo.cpp
1 #include "WindowedFifo.h"
2
3 /**
4  *
5  */
6 WindowedFifo::WindowedFifo(unsigned size = 20) {
7         //std::cout << "Create WindowedFifo." << std::endl;
8
9         _size = size;
10         _buffer = (char *) _malloc_align(_size, ALIGNMENT_FACTOR);
11   if(!_buffer) {
12     fprintf(stderr,"[WFIFO] Memory allocation failure\n");
13     exit(-1);
14   }
15         _head = 0;
16         _tail = 0;
17         _headRoom = 0;
18         _tailRoom = 0;
19         _use = 0;
20
21         _isHeadReserved = false;
22         _isTailReserved = false;
23
24         // For DMA transfers
25         _blocked = 0;
26         _activeDMA = false;
27 }
28
29 /**
30  *
31  */
32 WindowedFifo::~WindowedFifo() {
33         //std::cout << "Delete WindowedFifo." << std::endl;
34         if (_buffer) {
35                 _free_align(_buffer);
36         }
37         _buffer = 0;
38         _head = 0;
39         _tail = 0;
40         _use = 0;
41         //std::cout << "Deleted WindowedFifo." << std::endl;
42 }
43
44 /**
45  *
46  */
47 unsigned WindowedFifo::reserve(char** destination, unsigned len) {
48
49         //std::cout << "Attempt to reserve " << len << " bytes." << std::endl;
50
51         //can only reserve once piece at a time
52         if (_isHeadReserved) {
53                 *destination = 0;
54                 return 0;
55         }
56
57         //reserve at most as much memory as still available in the buffer
58         unsigned write = (len <= _size - _use ? len : 0);
59
60         if (write > 0) {
61                 //if wrap-around in buffer: return only buffer for the
62                 //contiguous buffer space
63                 if (_head + write > _size) {
64                         write = _size - _head;
65                 }
66
67                 _headRoom = (_head + write) == _size ? 0 : _head + write;
68                 *destination = &(_buffer[_head]);
69                 _isHeadReserved = true;
70         }
71
72         //std::cout << "Reserved " << write << " bytes." << std::endl;
73         _writeReserve = write;
74         return write;
75 }
76
77 /**
78  *
79  */
80 void WindowedFifo::release() {
81         if (_isHeadReserved) {
82                 //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl;
83                 _head = _headRoom;
84                 _use += _writeReserve;
85                 _isHeadReserved = false;
86         }
87 }
88
89 /**
90  *
91  */
92 unsigned WindowedFifo::capture(char **destination, unsigned len) {
93
94         //std::cout << "Attempt to capture " << len << " bytes." << std::endl;
95
96         if (_isTailReserved) {
97                 //std::cout << "Only one attempt to capture allowed." << std::endl;
98                 *destination = 0;
99                 return 0;
100         }
101
102         //capture at most as much data as available in the buffer
103         unsigned read = (len <= _use ? len : 0);
104
105         if (read > 0) {
106                 //if wrap-around in buffer: return only buffer for the
107                 //conntiguous buffer space
108                 if (_tail + read > _size) {
109                         read = _size - _tail;
110                 }
111
112                 _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read;
113                 *destination = &(_buffer[_tail]);
114                 _isTailReserved = true;
115         }
116
117         _readReserve = read;
118         //std::cout << "Captured " << read << " bytes." << std::endl;
119
120         return read;
121 }
122
123 /**
124  *
125  */
126 void WindowedFifo::consume() {
127         if (_isTailReserved) {
128                 //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl;
129                 _tail = _tailRoom;
130                 _use -= _readReserve;
131                 _isTailReserved = false;
132         }
133 }
134
135 /**
136  *
137  */
138 unsigned WindowedFifo::size() const {
139         return _size;
140 }
141
142 /**
143  *
144  */
145 unsigned WindowedFifo::unused() const {
146         return _size - _use;
147 }
148
149 /**
150  *
151  */
152 unsigned WindowedFifo::used() const {
153         return _use;
154 }
155
156 /*
157  * Get the pointer to the start of the queue
158  */
159 char *WindowedFifo::getQueuePointer() {
160         return _buffer;
161 }
162
163 /*
164  * Has completed a dma read process, i.e. has read out of the queue
165  */
166 void WindowedFifo::dmaRead(unsigned len) {
167         if (len == 0) {
168                 _blocked = BLOCKED_MAX_NR;
169         } else {
170                 _tail = ((unsigned) (_tail + len) % _size);
171                 _use -= len;
172         }
173
174         _activeDMA = false;
175 }
176
177 /*
178  * Start a DMA request, returns the current space one have
179  */
180 unsigned WindowedFifo::dmaStart() {
181         _activeDMA = true;
182
183         if (_tail + _use > _size) {
184                 return _size - _tail;
185         } else {
186                 return _use;
187         }
188 }
189
190 /*
191  * Is allowed to start a dma request
192  */
193 bool WindowedFifo::dmaAllowed() {
194 #ifndef STORE_REQUESTS
195         if (_blocked > 0) {
196                 _blocked--;
197                 return false;
198         } else {
199                 return !_activeDMA;
200         }
201 #else
202         return !_activeDMA;
203 #endif
204 }
205
206 /**
207  * Is needed for DMA transfers
208  */
209 unsigned WindowedFifo::dmaWrite(const void *source, unsigned len) {
210
211         char* buffer = (char*) source;
212
213         if (_head + len < _size) {
214                 memcpy(_buffer + _head, buffer, len);
215         } else {
216                 // We should never be here!
217                 memcpy(_buffer + _head, buffer, _size - _head);
218                 memcpy(_buffer, buffer + _size - _head, len - _size + _head);
219         }
220         _use += len;
221         _head = (_head + len) >= _size ? _head + len - _size : _head + len;
222
223         return len;
224 }
225
226 /**
227  * Test the implementation
228  */
229 /*
230  int main() {
231  WindowedFifo *myFifo = new WindowedFifo(16);
232
233  int* buf1;
234  int* buf2;
235  int x = myFifo->reserve((char**)&buf1, 8);
236  *buf1 = 10;
237  *(buf1 + 1) = 20;
238  myFifo->release();
239  int y = myFifo->capture((char**)&buf2, 8);
240  std::cout << "read " << *buf2 << " " << *(buf2 + 1) << std::endl;
241  myFifo->consume();
242
243  for (int j = 0; j < 3; j++) {
244  for (int i = 0; i < 6; i++) {
245  std::cout << "write " << i << " to Fifo.    ";
246  int write = myFifo->reserve((char**)&buf1, sizeof(int));
247  if (write == sizeof(int)) {
248  *buf1 = i;
249  myFifo->release();
250  std::cout << "used: " << std::setw(2) << myFifo->used()
251  << ", unused: " << std::setw(2) << myFifo->unused()
252  << ", size: "  << std::setw(2) << myFifo->size()
253  << std::endl;
254  } else {
255  std::cout << std::endl;
256  }
257  }
258  for (int i = 0; i < 16; i++) {
259  char* buf3;
260  int read = myFifo->capture((char**)&buf3, sizeof(char));
261  if (read == sizeof(char)) {
262  std::cout << "read " << (unsigned)*buf3 << "  from Fifo   ";
263  std::cout << "used: " << std::setw(2) << myFifo->used()
264  << ", unused: " << std::setw(2) << myFifo->unused()
265  << ", size: "  << std::setw(2) << myFifo->size()
266  << std::endl;
267  myFifo->consume();
268  } else {
269  std::cout << "read nothing from Fifo." << std::endl;
270  }
271
272  }
273  }
274  delete myFifo;
275  return 0;
276  }
277  */