2 * FastCommunication.cpp / Version PPE
4 * Created on: Mar 3, 2009
7 * For remarks to this file, please refer to the SPE variant.
9 * Completion of the SPEs:
10 * Is coordinated by this process. Each SPE has to send a request to
11 * the PPE if it is allowed to finish.
12 * If all SPEs have requested to complete, the PPE sends to the SPEs a
13 * message that they can complete, thus return.
16 #include "FastCommunication.h"
21 FastCommunication::FastCommunication(int nrOfQueues,
22 uint64_t *context_all, uint64_t * ea_ls_base,
23 int32_t * queueFromSPEIn, int32_t * queueOnSPEIn,
24 uint64_t *fifoTails) {
26 _context_all = context_all;
27 queueFromSPE = queueFromSPEIn;
28 queueOnSPE = queueOnSPEIn;
29 _ea_ls_base = ea_ls_base;
30 _fifoTails = fifoTails;
33 _nrOfQueues = nrOfQueues;
34 try { _fifos = new fifoCollection[nrOfQueues]; }
35 catch(std::bad_alloc &e) {
36 fprintf(stderr, "[FastCommunication] Memory allocation failure\n");
40 for (int i = 0; i < MAXNOREQ; i++) {
41 _request[i].valid = false;
48 FastCommunication::~FastCommunication() {
53 * Register an additional FIFO in the Communication
55 bool FastCommunication::addFifo(int fifoNr, Fifo* fifo, int type,
57 _fifos[fifoNr].fifo = fifo;
58 _fifos[fifoNr].queue = queue;
59 _fifos[fifoNr].type = type;
60 _fifos[fifoNr].iswfifo = false;
62 // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them
63 if (_nrOfRequest < MAXNOREQ) {
71 * Register an additional WindowedFIFO in the Communication
73 bool FastCommunication::addWFifo(int fifoNr, WindowedFifo* wfifo,
74 int type, int queue) {
75 _fifos[fifoNr].wfifo = wfifo;
76 _fifos[fifoNr].queue = queue;
77 _fifos[fifoNr].type = type;
78 _fifos[fifoNr].iswfifo = true;
80 // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them
81 if (_nrOfRequest < MAXNOREQ) {
89 * Communication: Main update procedure to update
91 bool FastCommunication::update() {
92 // Check if you have received a new message
93 for (int processNr = 0; processNr < NUM_SPES; processNr++) {
94 if (!spe_out_mbox_status((spe_context*) _context_all[processNr]))
98 spe_out_mbox_read((spe_context*) _context_all[processNr],
101 uint32_t code = GETFASTCODE(messageIn);
102 uint32_t queue = GETFASTQUEUE(messageIn);
103 uint32_t len = GETFASTLEN(messageIn);
105 /***************************************************************************************************************/
106 if (code == SPE_READ_DEMAND) // Have to send a write address (1) --> (2)
108 // Find out for which fifo the request is
109 fifoCollection *fifocol = NULL;
111 for (i = 0; i < _nrOfQueues; i++) {
112 if (_fifos[i].queue == queue) {
113 fifocol = &_fifos[i];
118 // The queue was not found
119 if (fifocol == NULL) {
120 printf("PPU COM> ERROR, this queue does not exists!\n");
124 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 if (_fifos[i].iswfifo) {
127 WindowedFifo* wfifo = NULL;
128 wfifo = _fifos[i].wfifo;
130 uint32_t inTail = wfifo->_inTail;
132 // This is the len we like to read
133 len = len > (wfifo->unused()) ? wfifo->unused() : len;
135 // We can read something
137 // Write all information we used to the request-memory
138 comRequest* request = newRequest();
140 // Has no memory to store a new request
141 if (request == NULL) {
142 // not possible to start a request for this SPE --> Send len = 0
143 uint32_t message = CREATEFASTMESSAGE(
144 SPE_READ_COMPLETE, queue, 0);
145 sendMessage(message, queueFromSPE[queue]);
149 uint64_t baseAddress = _fifoTails[queue] + inTail;
150 while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
154 uint32_t offset = _fifoTails[queue] + inTail
157 // Store all data in the request buffer
158 request->data = (char *) _malloc_align(roundDMA(len
159 + offset), ALIGNMENT_FACTOR);
161 request->wfifo = wfifo;
162 request->iswfifo = true;
163 request->status = read_started;
164 request->queue = queue;
165 request->offset = offset;
170 (spe_context*) _context_all[processNr],
171 baseAddress, (void *) &(request->data[0]),
172 roundDMA(len + offset), request->tag_id,
176 #ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase
177 uint32_t message = CREATEFASTMESSAGE(
178 SPE_READ_COMPLETE, queue, 0);
179 sendMessage(message, queueFromSPE[queue]);
180 #else // I store the request and may try in a later time to start the transfer
181 comRequest* request = newRequest();
183 // Has no memory to store a new request
186 // not possible to start a request for this SPE --> Send len = 0
187 uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0);
188 sendMessage(message, queueFromSPE[queue]);
193 request->wfifo = wfifo;
194 request->iswfifo = true;
195 request->status = read_pending;
196 request->queue = queue;
202 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 fifo = _fifos[i].fifo;
208 uint32_t inTail = fifo->_inTail;
210 // This is the len we like to read
211 len = len > (fifo->unused()) ? fifo->unused() : len;
213 // We can read something
215 // Write all information we used to the request-memory
216 comRequest* request = newRequest();
218 // Has no memory to store a new request
219 if (request == NULL) {
220 // not possible to start a request for this SPE --> Send len = 0
221 uint32_t message = CREATEFASTMESSAGE(
222 SPE_READ_COMPLETE, queue, 0);
223 sendMessage(message, queueFromSPE[queue]);
227 uint64_t baseAddress = _fifoTails[queue] + inTail;
228 while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
232 uint32_t offset = _fifoTails[queue] + inTail
235 // Store all data in the request buffer
236 request->data = (char *) _malloc_align(roundDMA(len
237 + offset), ALIGNMENT_FACTOR);
239 request->fifo = fifo;
240 request->iswfifo = false;
241 request->status = read_started;
242 request->queue = queue;
243 request->offset = offset;
248 (spe_context*) _context_all[processNr],
249 baseAddress, (void *) &(request->data[0]),
250 roundDMA(len + offset), request->tag_id,
257 #ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase
258 uint32_t message = CREATEFASTMESSAGE(
259 SPE_READ_COMPLETE, queue, 0);
260 sendMessage(message, queueFromSPE[queue]);
261 #else // I store the request and may try in a later time to start the transfer
262 comRequest* request = newRequest();
264 // Has no memory to store a new request
265 if (request == NULL) {
266 // not possible to start a request for this SPE --> Send len = 0
267 uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0);
268 sendMessage(message, queueFromSPE[queue]);
273 request->fifo = fifo;
274 request->iswfifo = false;
275 request->status = read_pending;
276 request->queue = queue;
282 /***************************************************************************************************************/
283 else if (code == SPE_READ_COMPLETE) // Can finish a write request (4) --> (5)
285 // Get the stored request
286 comRequest* request = getRequest(read_request_sent, queue);
288 if (request == NULL) {
289 printf("PPU Communicate> Couldn't find the request\n");
293 // Inform my FIFO that the request is completed
294 if (request->iswfifo)
295 request->wfifo->dmaRead(len);
297 request->fifo->dmaRead(len);
300 deleteRequest(request);
303 /***************************************************************************************************************/
304 else if (code == SPE_COMPLETE) // One SPE has finished
310 /***************************************************************************************************************/
311 // Check if some active write processes have finished (4)
312 uint8_t req = _currentRequest;
314 for (int i = 0; i < _nrOfRequest; i++) {
315 if (_request[req].valid) {
316 if (_request[req].status == read_started) {
317 if (!(testMessage(queueFromSPE[_request[req].queue]) > 0))
320 uint32_t tag_id = _request[req].tag_id;
324 spe_mfcio_tag_status_read(
325 (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
326 0, SPE_TAG_IMMEDIATE, &ret);
328 if (((ret & (1 << tag_id)) == 0)) {
329 // Have to write the data into the fifo
330 if (_request[req].iswfifo) { // WFIFO
332 _request[req].wfifo->dmaWrite(
333 (char *) _request[req].data
334 + _request[req].offset,
336 _free_align(_request[req].data);
338 // Increase the inTail value (used to know where the last request was started)
340 _request[req].wfifo->_inTail
341 = (_request[req].wfifo->_inTail
342 + _request[req].len) % (FIFO_SIZE[_request[req].queue]);
344 _request[req].fifo->write(
345 (char *) _request[req].data
346 + _request[req].offset,
348 _free_align(_request[req].data);
350 _request[req].fifo->_inTail
351 = (_request[req].fifo->_inTail
352 + _request[req].len) % (FIFO_SIZE[_request[req].queue]);
356 uint32_t message = CREATEFASTMESSAGE(
357 SPE_READ_COMPLETE, _request[req].queue,
359 sendMessage(message, queueFromSPE[_request[req].queue]);
361 deleteRequest(&_request[req]);
362 _currentRequest = (req + 1) % _nrOfRequest;
366 } else if (_request[req].status == read_pending) { // Has an open request for sending
368 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 if (_request[req].iswfifo) {
372 if (_request[req].wfifo->unused() > 0) {
373 comRequest *request = &_request[req];
375 // This is the len we like to read
376 uint32_t len = request->len > (request->wfifo->unused()) ? request->wfifo->unused()
379 uint32_t inTail = request->wfifo->_inTail;
380 uint64_t baseAddress = _fifoTails[request->queue]
383 while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0)
386 // Offset --> How much we had to align
387 uint32_t offset = _fifoTails[request->queue]
388 + inTail - baseAddress;
390 request->data = (char *) _malloc_align(roundDMA(
391 len + offset), ALIGNMENT_FACTOR);
393 request->status = read_started;
394 request->offset = offset;
396 // Set up the request in the MFC
400 (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
402 (void *) &(request->data[0]),
403 roundDMA(len + offset),
404 request->tag_id, 0, 0);
409 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 if (_request[req].fifo->unused() > 0) {
414 comRequest *request = &_request[req];
416 // This is the len we like to read
417 uint32_t len = request->len > (request->fifo->unused()) ? request->fifo->unused() : request->len;
419 uint32_t inTail = request->fifo->_inTail;
420 uint64_t baseAddress = _fifoTails[request->queue]
423 while (baseAddress % 16 != 0)
427 uint32_t offset = _fifoTails[request->queue]
428 + inTail - baseAddress;
430 // Store all data in the request buffer
431 request->data = (char *) _malloc_align(roundDMA(
432 len + offset), ALIGNMENT_FACTOR);
434 request->status = read_started;
435 request->offset = offset;
437 // Start the DMA transfer
442 (spe_context*) _context_all[queueFromSPE[_request[req].queue]],
444 (void *) &(request->data[0]),
445 roundDMA(len + offset),
446 request->tag_id, 0, 0);
452 req = (req + 1) % _nrOfRequest;
455 /***************************************************************************************************************/
456 // Have some out - queue some data to send
457 for (int i = 0; i < _nrOfQueues; i++) {
458 if (_fifos[i].type == this->out) {
459 if (_fifos[i].iswfifo) { // WFIFO
460 // Start only a write process if there is really enough place in the outbound mailbox
461 if (_fifos[i].wfifo->dmaAllowed()
462 && _fifos[i].wfifo->used() > 0) {
463 uint32_t queue = _fifos[i].queue;
465 // Can we send a message to this processor or is it blocked?
466 if (testMessage(queueOnSPE[queue]) <= 0) {
470 // Write all information we used to the request-memory
471 comRequest* request = newRequest();
473 // Has no memory to store a new request
474 if (request == NULL) {
476 uint32_t len = _fifos[i].wfifo->dmaStart();
477 // Create a write-demand message
478 uint32_t message = CREATEFASTMESSAGE(
479 SPE_READ_DEMAND, queue, len);
482 request->queue = queue;
483 request->status = read_request_sent;
484 request->wfifo = _fifos[i].wfifo;
485 request->iswfifo = true;
487 sendMessage(message, queueOnSPE[queue]);
492 // Start only a write process if there is really enough place in the outbound mailbox
493 if (_fifos[i].fifo->dmaAllowed() && _fifos[i].fifo->used()
495 uint32_t queue = _fifos[i].queue;
497 if (testMessage(queueOnSPE[queue]) <= 0)
500 // Write all information we used to the request-memory
501 comRequest* request = newRequest();
503 // Has no memory to store a new request
504 if (request == NULL) {
506 uint32_t len = _fifos[i].fifo->dmaStart();
507 uint32_t message = CREATEFASTMESSAGE(
508 SPE_READ_DEMAND, queue, len);
510 request->queue = queue;
511 request->status = read_request_sent;
512 request->fifo = _fifos[i].fifo;
513 request->iswfifo = false;
515 sendMessage(message, queueOnSPE[queue]);
526 * Create a new request to store in the cache
529 comRequest* FastCommunication::newRequest() {
530 for (int i = 0; i < _nrOfRequest; i++) {
531 if (!_request[i].valid) {
532 _request[i].tag_id = i + 3;
533 _request[i].valid = true;
534 return &(_request[i]);
545 void FastCommunication::deleteRequest(comRequest* request) {
546 request->valid = false;
551 * Returns the request one like to get
553 comRequest* FastCommunication::getRequest(uint8_t status, uint32_t queue) {
554 uint8_t req = _currentRequest;
556 for (int i = 0; i < _nrOfRequest; i++) {
557 if (_request[req].valid && _request[req].status == status
558 && _request[req].queue == queue) {
559 _currentRequest = (req + 1) % _nrOfRequest;
560 return &(_request[req]);
562 req = (req + 1) % _nrOfRequest;
569 * True if no communication is necessary, false if there is active communication
571 bool FastCommunication::empty() { /////////////////////////////////////////////////////////////////
572 // check if one fifo would like to send something to another SPE
573 for (int i = 0; i < _nrOfQueues; i++) {
574 if (_fifos[i].type == this->out) {
575 if (_fifos[i].iswfifo) { // WFIFO
576 if (_fifos[i].wfifo->used() > 0)
581 if (_fifos[i].fifo->used() > 0)
589 // are open sendings?
590 for (int i = 0; i < _nrOfRequest; i++) {
591 if (_request[i].valid) {
596 if (_nrSpeComplete < NUM_SPES) {
604 * Send a message to a SPE
606 void FastCommunication::sendMessage(uint32_t message, int32_t process) {
607 spe_in_mbox_write((spe_context*) _context_all[process],
608 (uint32_t*) &message, 1, SPE_MBOX_ANY_NONBLOCKING);
612 * Test if we can send a message to an SPE without stalling
614 int FastCommunication::testMessage(int32_t process) {
615 return spe_in_mbox_status((spe_context*) _context_all[process]);