dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / lib / ppu / WindowedFifo.cpp
diff --git a/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.cpp b/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.cpp
new file mode 100644 (file)
index 0000000..16e09ba
--- /dev/null
@@ -0,0 +1,223 @@
+#include "WindowedFifo.h"
+
+/**
+ *
+ */
+WindowedFifo::WindowedFifo(unsigned size = 20) {
+       //std::cout << "Create WindowedFifo." << std::endl;
+       _size = size;
+       _buffer = (char *) _malloc_align(_size, ALIGNMENT_FACTOR);
+        if(!_buffer) {
+           fprintf(stderr,"[WFIFO] Memory allocation failure\n");
+           exit(-1);
+       }
+
+       _head = 0;
+       _tail = 0;
+
+       _headRoom = 0;
+       _tailRoom = 0;
+       _use = 0;
+       _blocked = 0;
+
+       _isHeadReserved = false;
+       _isTailReserved = false;
+       _activeDMA = false;
+}
+
+/**
+ *
+ */
+WindowedFifo::~WindowedFifo() {
+       if (_buffer) {
+               _free_align(_buffer);
+       }
+       _buffer = 0;
+       _head = 0;
+       _tail = 0;
+       _use = 0;
+}
+
+/**
+ *
+ */
+unsigned WindowedFifo::reserve(void** dest, unsigned len) {
+       char** destination = (char**) dest;
+       //std::cout << "Attempt to reserve " << len << " bytes." << std::endl;
+
+       //can only reserve one piece at a time
+       if (_isHeadReserved) {
+               *destination = 0;
+               return 0;
+       }
+
+       //reserve at most as much memory as still available in the buffer
+       unsigned write = (len <= _size - _use ? len : _size - _use);
+
+       if (write > 0) {
+               //if wrap-around in buffer: return only buffer for the
+               //contiguous buffer space
+               if (_head + write > _size) {
+                       write = _size - _head;
+               }
+
+               _headRoom = (_head + write) == _size ? 0 : _head + write;
+               *destination = &(_buffer[_head]);
+               _isHeadReserved = true;
+       }
+
+       //std::cout << "Reserved " << write << " bytes." << std::endl;
+       _writeReserve = write;
+       return write;
+}
+
+/**
+ *
+ */
+void WindowedFifo::release() {
+       if (_isHeadReserved) {
+               //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl;
+               _head = _headRoom;
+               _use += _writeReserve;
+               _isHeadReserved = false;
+       }
+}
+
+/**
+ *
+ */
+unsigned WindowedFifo::capture(void **dest, unsigned len) {
+       char** destination = (char**) dest;
+       //std::cout << "Attempt to capture " << len << " bytes." << std::endl;
+
+       if (_isTailReserved) {
+               //std::cout << "Only one attempt to capture allowed." << std::endl;
+               *destination = 0;
+               return 0;
+       }
+
+       //capture at most as much data as available in the buffer
+       unsigned read = (len <= _use ? len : _use);
+
+       if (read > 0) {
+               //if wrap-around in buffer: return only buffer for the
+               //conntiguous buffer space
+               if (_tail + read > _size) {
+                       read = _size - _tail;
+               }
+
+               _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read;
+               *destination = &(_buffer[_tail]);
+               _isTailReserved = true;
+       }
+
+       //std::cout << "Captured " << read << " bytes." << std::endl;
+       _readReserve = read;
+       return read;
+}
+
+/**
+ *
+ */
+void WindowedFifo::consume() {
+       if (_isTailReserved) {
+               //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl;
+               _tail = _tailRoom;
+               _use -= _readReserve;
+               _isTailReserved = false;
+       }
+}
+
+/**
+ *
+ */
+unsigned WindowedFifo::size() const {
+       return _size;
+}
+
+/**
+ *
+ */
+unsigned WindowedFifo::unused() const {
+       return _size - _use;
+}
+
+/**
+ *
+ */
+unsigned WindowedFifo::used() const {
+       return _use;
+}
+
+/*
+ * Get the pointer to the start of the queue
+ */
+char *WindowedFifo::getQueuePointer() {
+       return _buffer;
+}
+
+/*
+ * Has completed a dma read process, i.e. has read out of the queue
+ */
+void WindowedFifo::dmaRead(unsigned len) {
+       _activeDMA = false;
+
+       if (len == 0) {
+               _blocked = BLOCKED_MAX_NR;
+       } else {
+               _tail = ((unsigned) (_tail + len) % _size);
+               _use -= len;
+       }
+}
+
+/*
+ * Start a DMA request, returns the current space one have
+ */
+unsigned WindowedFifo::dmaStart() {
+       _activeDMA = true;
+
+       // If we go over the end, we only take as much as is on one side!
+       //return used();
+
+       if (_tail + _use > _size) {
+               return _size - _tail;
+       } else {
+               return _use;
+       }
+}
+
+/*
+ * Is allowed to start a dma request
+ */
+bool WindowedFifo::dmaAllowed() {
+#ifndef STORE_REQUESTS
+       if (_blocked > 0) {
+               _blocked--;
+               return false;
+       } else {
+               return !_activeDMA;
+       }
+#else
+       return !_activeDMA;
+#endif
+}
+
+/**
+ * Is needed for DMA transfers
+ */
+unsigned WindowedFifo::dmaWrite(const void *source, unsigned len) {
+
+       char* buffer = (char*) source;
+
+       if (_head + len < _size) {
+               memcpy(_buffer + _head, buffer, len);
+       } else {
+               // We should never be here!
+               memcpy(_buffer + _head, buffer, _size - _head);
+               memcpy(_buffer, buffer + _size - _head, len - _size + _head);
+       }
+       _use += len;
+       _head = (_head + len) >= _size ? _head + len - _size : _head + len;
+
+       return len;
+}