X-Git-Url: http://sraa.de/git/?a=blobdiff_plain;f=dol%2Fsrc%2Fdol%2Fvisitor%2Fcell%2Flib%2Fppu%2FFastCommunication.cpp;fp=dol%2Fsrc%2Fdol%2Fvisitor%2Fcell%2Flib%2Fppu%2FFastCommunication.cpp;h=70a3bbde777fe51967cbac39f289c6e760fe8457;hb=8c411cf24ed0eb889191aaeafd8fa1e69081df42;hp=0000000000000000000000000000000000000000;hpb=dea7a4fb1ed110d3ce6e6d9255103d724bd66c0e;p=jump.git diff --git a/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.cpp b/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.cpp new file mode 100644 index 0000000..70a3bbd --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.cpp @@ -0,0 +1,617 @@ +/* + * FastCommunication.cpp / Version PPE + * + * Created on: Mar 3, 2009 + * Author: lschor + * + * For remarks to this file, please refer to the SPE variant. + * + * Completion of the SPEs: + * Is coordinated by this process. Each SPE has to send a request to + * the PPE if it is allowed to finish. + * If all SPEs have requested to complete, the PPE sends to the SPEs a + * message that they can complete, thus return. + */ + +#include "FastCommunication.h" + +/* + * Constructor + */ +FastCommunication::FastCommunication(int nrOfQueues, + uint64_t *context_all, uint64_t * ea_ls_base, + int32_t * queueFromSPEIn, int32_t * queueOnSPEIn, + uint64_t *fifoTails) { + + _context_all = context_all; + queueFromSPE = queueFromSPEIn; + queueOnSPE = queueOnSPEIn; + _ea_ls_base = ea_ls_base; + _fifoTails = fifoTails; + _nrSpeComplete = 0; + + _nrOfQueues = nrOfQueues; + try { _fifos = new fifoCollection[nrOfQueues]; } + catch(std::bad_alloc &e) { + fprintf(stderr, "[FastCommunication] Memory allocation failure\n"); + exit(1); + } + + for (int i = 0; i < MAXNOREQ; i++) { + _request[i].valid = false; + } +} + +/* + * Deconstructor + */ +FastCommunication::~FastCommunication() { + delete _fifos; +} + +/* + * Register an additional FIFO in the Communication + */ +bool FastCommunication::addFifo(int fifoNr, Fifo* fifo, int type, + int queue) { + _fifos[fifoNr].fifo = fifo; + _fifos[fifoNr].queue = queue; + _fifos[fifoNr].type = type; + _fifos[fifoNr].iswfifo = false; + + // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them + if (_nrOfRequest < MAXNOREQ) { + _nrOfRequest += 2; + } + + return true; +} + +/* + * Register an additional WindowedFIFO in the Communication + */ +bool FastCommunication::addWFifo(int fifoNr, WindowedFifo* wfifo, + int type, int queue) { + _fifos[fifoNr].wfifo = wfifo; + _fifos[fifoNr].queue = queue; + _fifos[fifoNr].type = type; + _fifos[fifoNr].iswfifo = true; + + // Per FIFO queue, we need two requests, but we can store at max MAXNOREQ of them + if (_nrOfRequest < MAXNOREQ) { + _nrOfRequest += 2; + } + + return true; +} + +/* + * Communication: Main update procedure to update + */ +bool FastCommunication::update() { + // Check if you have received a new message + for (int processNr = 0; processNr < NUM_SPES; processNr++) { + if (!spe_out_mbox_status((spe_context*) _context_all[processNr])) + continue; + + uint32_t messageIn; + spe_out_mbox_read((spe_context*) _context_all[processNr], + &messageIn, 1); + + uint32_t code = GETFASTCODE(messageIn); + uint32_t queue = GETFASTQUEUE(messageIn); + uint32_t len = GETFASTLEN(messageIn); + + /***************************************************************************************************************/ + if (code == SPE_READ_DEMAND) // Have to send a write address (1) --> (2) + { + // Find out for which fifo the request is + fifoCollection *fifocol = NULL; + int i; + for (i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].queue == queue) { + fifocol = &_fifos[i]; + break; + } + } + + // The queue was not found + if (fifocol == NULL) { + printf("PPU COM> ERROR, this queue does not exists!\n"); + return false; + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_fifos[i].iswfifo) { + WindowedFifo* wfifo = NULL; + wfifo = _fifos[i].wfifo; + + uint32_t inTail = wfifo->_inTail; + + // This is the len we like to read + len = len > (wfifo->unused()) ? wfifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + uint64_t baseAddress = _fifoTails[queue] + inTail; + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + request->len = len; + request->wfifo = wfifo; + request->iswfifo = true; + request->status = read_started; + request->queue = queue; + request->offset = offset; + + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[processNr], + baseAddress, (void *) &(request->data[0]), + roundDMA(len + offset), request->tag_id, + 0, 0); + } while (ret != 0); + } else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) + { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->wfifo = wfifo; + request->iswfifo = true; + request->status = read_pending; + request->queue = queue; +#endif + } + + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + Fifo* fifo = NULL; + fifo = _fifos[i].fifo; + + uint32_t inTail = fifo->_inTail; + + // This is the len we like to read + len = len > (fifo->unused()) ? fifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + uint64_t baseAddress = _fifoTails[queue] + inTail; + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_started; + request->queue = queue; + request->offset = offset; + + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[processNr], + baseAddress, (void *) &(request->data[0]), + roundDMA(len + offset), request->tag_id, + 0, 0); + } while (ret != 0); + } + + // Len == 0 + else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_pending; + request->queue = queue; +#endif + } + } + } + + /***************************************************************************************************************/ + else if (code == SPE_READ_COMPLETE) // Can finish a write request (4) --> (5) + { + // Get the stored request + comRequest* request = getRequest(read_request_sent, queue); + + if (request == NULL) { + printf("PPU Communicate> Couldn't find the request\n"); + return 0; + } + + // Inform my FIFO that the request is completed + if (request->iswfifo) + request->wfifo->dmaRead(len); + else + request->fifo->dmaRead(len); + + // Request free + deleteRequest(request); + } + + /***************************************************************************************************************/ + else if (code == SPE_COMPLETE) // One SPE has finished + { + _nrSpeComplete++; + } + } + + /***************************************************************************************************************/ + // Check if some active write processes have finished (4) + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[req].valid) { + if (_request[req].status == read_started) { + if (!(testMessage(queueFromSPE[_request[req].queue]) > 0)) + continue; + + uint32_t tag_id = _request[req].tag_id; + uint32_t ret; + uint32_t + test = + spe_mfcio_tag_status_read( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + 0, SPE_TAG_IMMEDIATE, &ret); + + if (((ret & (1 << tag_id)) == 0)) { + // Have to write the data into the fifo + if (_request[req].iswfifo) { // WFIFO + + _request[req].wfifo->dmaWrite( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + // Increase the inTail value (used to know where the last request was started) + + _request[req].wfifo->_inTail + = (_request[req].wfifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + } else { // FIFO + _request[req].fifo->write( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + _request[req].fifo->_inTail + = (_request[req].fifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + + } + + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, _request[req].queue, + _request[req].len); + sendMessage(message, queueFromSPE[_request[req].queue]); + + deleteRequest(&_request[req]); + _currentRequest = (req + 1) % _nrOfRequest; + + break; + } + } else if (_request[req].status == read_pending) { // Has an open request for sending + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_request[req].iswfifo) { + + if (_request[req].wfifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->wfifo->unused()) ? request->wfifo->unused() + : request->len; + + uint32_t inTail = request->wfifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + + inTail; + + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset --> How much we had to align + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + + // Set up the request in the MFC + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + baseAddress, + (void *) &(request->data[0]), + roundDMA(len + offset), + request->tag_id, 0, 0); + } while (ret != 0); + } + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + + if (_request[req].fifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->fifo->unused()) ? request->fifo->unused() : request->len; + + uint32_t inTail = request->fifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + + inTail; + + while (baseAddress % 16 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + + // Start the DMA transfer + int ret; + do { + ret + = spe_mfcio_put( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + baseAddress, + (void *) &(request->data[0]), + roundDMA(len + offset), + request->tag_id, 0, 0); + } while (ret != 0); + } + } + } + } + req = (req + 1) % _nrOfRequest; + } + + /***************************************************************************************************************/ + // Have some out - queue some data to send + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) { + if (_fifos[i].iswfifo) { // WFIFO + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].wfifo->dmaAllowed() + && _fifos[i].wfifo->used() > 0) { + uint32_t queue = _fifos[i].queue; + + // Can we send a message to this processor or is it blocked? + if (testMessage(queueOnSPE[queue]) <= 0) { + continue; + } + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].wfifo->dmaStart(); + // Create a write-demand message + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->wfifo = _fifos[i].wfifo; + request->iswfifo = true; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } else { // FIFO + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].fifo->dmaAllowed() && _fifos[i].fifo->used() + > 0) { + uint32_t queue = _fifos[i].queue; + + if (testMessage(queueOnSPE[queue]) <= 0) + continue; + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].fifo->dmaStart(); + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->fifo = _fifos[i].fifo; + request->iswfifo = false; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } + } + } + return true; +} + +/* + * Create a new request to store in the cache + * + */ +comRequest* FastCommunication::newRequest() { + for (int i = 0; i < _nrOfRequest; i++) { + if (!_request[i].valid) { + _request[i].tag_id = i + 3; + _request[i].valid = true; + return &(_request[i]); + } + } + + return NULL; +} + +/* + * Delete the request + * + */ +void FastCommunication::deleteRequest(comRequest* request) { + request->valid = false; + request->tag_id = 0; +} + +/* + * Returns the request one like to get + */ +comRequest* FastCommunication::getRequest(uint8_t status, uint32_t queue) { + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[req].valid && _request[req].status == status + && _request[req].queue == queue) { + _currentRequest = (req + 1) % _nrOfRequest; + return &(_request[req]); + } + req = (req + 1) % _nrOfRequest; + } + + return NULL; +} + +/** + * True if no communication is necessary, false if there is active communication + */ +bool FastCommunication::empty() { ///////////////////////////////////////////////////////////////// + // check if one fifo would like to send something to another SPE + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) { + if (_fifos[i].iswfifo) { // WFIFO + if (_fifos[i].wfifo->used() > 0) + { + return false; + } + } else { + if (_fifos[i].fifo->used() > 0) + { + return false; + } + } + } + } + + // are open sendings? + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[i].valid) { + return false; + } + } + + if (_nrSpeComplete < NUM_SPES) { + return false; + } + + return true; +} + +/** + * Send a message to a SPE + */ +void FastCommunication::sendMessage(uint32_t message, int32_t process) { + spe_in_mbox_write((spe_context*) _context_all[process], + (uint32_t*) &message, 1, SPE_MBOX_ANY_NONBLOCKING); +} + +/** + * Test if we can send a message to an SPE without stalling + */ +int FastCommunication::testMessage(int32_t process) { + return spe_in_mbox_status((spe_context*) _context_all[process]); +} +