aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/psp/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/platform/psp/memory.cpp')
-rw-r--r--backends/platform/psp/memory.cpp903
1 files changed, 499 insertions, 404 deletions
diff --git a/backends/platform/psp/memory.cpp b/backends/platform/psp/memory.cpp
index d66650aee5..1e7705e9e8 100644
--- a/backends/platform/psp/memory.cpp
+++ b/backends/platform/psp/memory.cpp
@@ -1,404 +1,499 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
- *
- */
-
-#include "common/scummsys.h"
-#include "common/singleton.h"
-#include "common/list.h"
-#include "backends/platform/psp/PSPPixelFormat.h"
-#include "backends/platform/psp/memory.h"
-
-// Class Copier --------------------------------------------------------------------------
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-//#define TEST_MEMORY_COPY
-
-// swapRB is used to swap red and blue in the display
-void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) {
- DEBUG_ENTER_FUNC();
-
-#ifdef TEST_MEMORY_COPY
- uint32 debugBytes = bytes;
- const byte *debugDst = dst, *debugSrc = src;
-#endif
-
- PSP_DEBUG_PRINT("copy(): dst[%p], src[%p], bytes[%d]\n", dst, src, bytes);
-
- // align the destination pointer first
- uint32 prefixDst = (((uint32)dst) & 0x3);
-
- if (prefixDst) {
- prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0
- PSP_DEBUG_PRINT("prefixDst[%d]\n", prefixDst);
-
- bytes -= prefixDst; // remember we assume bytes >= 4
-
- if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
- copy8(dst, src, bytes);
-#ifdef TEST_MEMORY_COPY
- testCopy(debugDst, debugSrc, debugBytes);
-#endif
- return;
- }
-
- while (prefixDst--) {
- *dst++ = *src++;
- }
- }
-
- // check the source pointer alignment now
- uint32 alignSrc = (((uint32)src) & 0x3);
-
- if (alignSrc) { // we'll need to realign our reads
- copy32Misaligned((uint32 *)dst, src, bytes, alignSrc);
- } else {
- copy32Aligned((uint32 *)dst, (uint32 *)src, bytes);
- }
-
-#ifdef TEST_MEMORY_COPY
- testCopy(debugDst, debugSrc, debugBytes);
-#endif
-}
-
-void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) {
-
- bool mismatch = false;
- PSP_INFO_PRINT("testing memcpy...");
-
- for (uint32 i = 0; i < debugBytes; i++) {
- if (debugDst[i] != debugSrc[i]) {
- if (mismatch == false) {
- PSP_DEBUG_PRINT_SAMELN("**** mismatch in copy! ****\n");
- PSP_DEBUG_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
- mismatch = true;
- }
- PSP_DEBUG_PRINT_SAMELN("%x!=%x ", debugSrc[i], debugDst[i]);
- }
- }
- if (mismatch) {
- PSP_DEBUG_PRINT("\n");
- } else {
- PSP_INFO_PRINT("ok\n");
- }
-}
-
-//
-// used to swap red and blue
-void PspMemory::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
- DEBUG_ENTER_FUNC();
-
- // align the destination pointer first
- uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix
-
- if (prefixDst) {
- bytes -= prefixDst; // remember we assume bytes > 4
- *dst16++ = *src16++;
-
- if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY * 2) { // check if it's worthwhile to continue
- swap16(dst16, src16, bytes, format);
- return;
- }
- }
-
- // check the source pointer alignment now
- uint32 alignSrc = (((uint32)src16) & 0x3);
-
- if (alignSrc) { // we'll need to realign our reads
- PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16);
- swap32Misaligned((uint32 *)dst16, (uint16 *)src16, bytes, format);
- } else {
- swap32Aligned((uint32 *)dst16, (uint32 *)src16, bytes, format);
- }
-}
-
-void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) {
- PSP_DEBUG_PRINT("copy32Aligned(): dst32[%p], src32[%p], bytes[%d]\n", dst32, src32, bytes);
-
- int words8 = bytes >> 5;
-
- // try blocks of 8 words at a time
- if (words8) {
- while (words8--) {
- dst32[0] = src32[0];
- dst32[1] = src32[1];
- dst32[2] = src32[2];
- dst32[3] = src32[3];
- dst32[4] = src32[4];
- dst32[5] = src32[5];
- dst32[6] = src32[6];
- dst32[7] = src32[7];
- dst32 += 8;
- src32 += 8;
- }
- }
-
- int words4 = (bytes & 0x1F) >> 4;
-
- // try blocks of 4 words at a time
- if (words4) {
- dst32[0] = src32[0];
- dst32[1] = src32[1];
- dst32[2] = src32[2];
- dst32[3] = src32[3];
- dst32 += 4;
- src32 += 4;
- }
-
- int bytesLeft = (bytes & 0xF); // only look at bytes left after we did the above
- int wordsLeft = bytesLeft >> 2;
-
- // now just do single words
- while (wordsLeft) {
- *dst32++ = *src32++;
- wordsLeft--;
- }
-
- bytesLeft = bytes & 0x3; // get remaining bytes
-
- PSP_DEBUG_PRINT("bytesLeft[%d]\n", bytesLeft);
-
- byte *dst = (byte *)dst32;
- byte *src = (byte *)src32;
-
- while (bytesLeft--) {
- *dst++ = *src++;
- }
-}
-
-void PspMemory::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) {
- DEBUG_ENTER_FUNC();
- int words = bytes >> 2;
-
- // try blocks of 4 words at a time
- for (; words - 4 >= 0; words -= 4) {
- dst32[0] = format.swapRedBlue32(src32[0]);
- dst32[1] = format.swapRedBlue32(src32[1]);
- dst32[2] = format.swapRedBlue32(src32[2]);
- dst32[3] = format.swapRedBlue32(src32[3]);
- dst32 += 4;
- src32 += 4;
- }
-
- // now just do words
- for (; words > 0; words--) {
- *dst32++ = format.swapRedBlue32(*src32++);
- }
-
- uint32 remainingBytes = bytes & 0x3;
-
- if (remainingBytes) { // for swap, must be a 16 bit value
- *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32)); // only 1 short left
- }
-}
-
-
-// More challenging -- need to shift
-// Assume dst is aligned
-void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc) {
- PSP_DEBUG_PRINT("copy32Misaligned: dst32[%p], src[%p], bytes[%d], alignSrc[%d]\n", dst32, src, bytes, alignSrc);
-
- uint32 *src32 = (uint32 *)(((uint32)src) & 0xFFFFFFFC); // remove misalignment
- uint32 offset;
-
- switch (alignSrc) {
- case 1:
- offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 8, 24);
- break;
- case 2:
- offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 16, 16);
- break;
- case 3:
- offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 24, 8);
- break;
- }
-
- uint32 remainingBytes = bytes & 3;
-
- if (remainingBytes) {
- byte *dst = (byte *)dst32;
- src += offset;
- dst += offset;
- copy8(dst, src, remainingBytes);
- }
-}
-
-// returns offset in dst
-uint32 PspMemory::misaligned32Detail(uint32 *dst32, uint32 *src32, uint32 bytes, uint32 alignSrc, const uint32 shiftValue, const uint32 lastShiftValue) {
- uint32 *origDst32 = dst32;
- register uint32 dstWord, srcWord;
-
- PSP_DEBUG_PRINT("misaligned32Detail(): alignSrc[%d], dst32[%p], src32[%p], words[%d]\n", alignSrc, dst32, src32, words);
-
- // Try to do groups of 4 words
- uint32 words4 = bytes >> 4;
-
- srcWord = src32[0];
-
- while (words4--) {
- dstWord = srcWord >> shiftValue;
- srcWord = src32[1];
- dstWord |= srcWord << lastShiftValue;
- dst32[0] = dstWord;
- dstWord = srcWord >> shiftValue;
- srcWord = src32[2];
- dstWord |= srcWord << lastShiftValue;
- dst32[1] = dstWord;
- dstWord = srcWord >> shiftValue;
- srcWord = src32[3];
- dstWord |= srcWord << lastShiftValue;
- dst32[2] = dstWord;
- dstWord = srcWord >> shiftValue;
- srcWord = src32[4];
- dstWord |= srcWord << lastShiftValue;
- dst32[3] = dstWord;
- src32 += 4;
- dst32 += 4;
- }
-
- uint32 words = (bytes & 0xF) >> 2;
-
- // we read one word ahead of what we write
- // setup the first read
- if (words) {
- srcWord = *src32++;
-
- while (words--) {
- dstWord = srcWord >> shiftValue;
- srcWord = *src32++;
- dstWord |= srcWord << lastShiftValue;
- *dst32++ = dstWord;
- }
- }
-
- return (byte *)dst32 - (byte *)origDst32;
-}
-// More challenging -- need to shift
-// Assume dst is aligned
-void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
- DEBUG_ENTER_FUNC();
- if (bytes < MIN_AMOUNT_FOR_MISALIGNED_COPY) { // less than a certain number of bytes it's just not worth it
- swap16((uint16 *)dst32, src16, bytes, format);
- return;
- }
-
- int words = bytes >> 2;
- uint32 remainingBytes = bytes & 3;
-
- uint32 *src32 = (uint32 *)(((uint32)src16) & 0xFFFFFFFC); // remove misalignment
-
- // we read one word ahead of what we write
- // setup the first read
- uint32 lastWord = ((*src32++) >> 16) & 0xFFFF;
-
- for (; words; words--) {
- uint32 srcWord = *src32++;
- uint32 curWord = (srcWord >> 16) & 0xFFFF;
- lastWord |= (srcWord & 0xFFFF) << 16; // take the part of the src that belongs to this word
- *dst32++ = format.swapRedBlue32(lastWord);
- lastWord = curWord;
- }
-
- if (remainingBytes) { // add in the remaining stuff
- *(uint16 *)dst32 = format.swapRedBlue16((uint16)lastWord);
- }
-}
-
-inline void PspMemory::copy16(uint16 *dst16, const uint16 *src16, uint32 bytes) {
- PSP_DEBUG_PRINT("copy16(): dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes);
-
- uint32 shorts = bytes >> 1;
- uint32 remainingBytes = bytes & 1;
-
- for (; shorts > 0 ; shorts--) {
- *dst16++ = *src16++;
- }
- if (remainingBytes)
- *(byte *)dst16 = *(byte *)src16;
-}
-
-// Class VramAllocator -----------------------------------
-
-DECLARE_SINGLETON(VramAllocator)
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-
-void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) {
- DEBUG_ENTER_FUNC();
- assert(size > 0);
-
- byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS;
- Common::List<Allocation>::iterator i;
-
- // Find a block that fits, starting from the beginning
- for (i = _allocList.begin(); i != _allocList.end(); ++i) {
- byte *currAddress = (*i).address;
-
- if (currAddress - lastAddress >= size) // We found a match
- break;
-
- if ((*i).getEnd() > lastAddress)
- lastAddress = (byte *)(*i).getEnd();
- }
-
- if (lastAddress + size > (byte *)VRAM_END_ADDRESS) {
- PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n",
- size, _bytesAllocated);
- return NULL;
- }
-
- _allocList.insert(i, Allocation(lastAddress, size));
- _bytesAllocated += size;
-
- PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress);
- PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated);
-
- return lastAddress;
-}
-
-// Deallocate a block from VRAM
-void VramAllocator::deallocate(void *address) {
- DEBUG_ENTER_FUNC();
- address = (byte *)CACHED(address); // Make sure all addresses are the same
-
- Common::List<Allocation>::iterator i;
-
- // Find the Allocator to deallocate
- for (i = _allocList.begin(); i != _allocList.end(); ++i) {
- if ((*i).address == address) {
- _bytesAllocated -= (*i).size;
- _allocList.erase(i);
- PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size);
- return;
- }
- }
-
- PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address);
-}
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/singleton.h"
+#include "common/list.h"
+#include "backends/platform/psp/PSPPixelFormat.h"
+#include "backends/platform/psp/memory.h"
+
+// Class Copier --------------------------------------------------------------------------
+//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
+//#define __PSP_DEBUG_PRINT__
+
+#include "backends/platform/psp/trace.h"
+
+//#define TEST_MEMORY_COPY
+
+extern "C" {
+
+void *__wrap_memcpy(void *dst, void *src, size_t bytes) {
+ PspMemory::fastCopy((byte *)dst, (byte *)src, bytes);
+ return dst;
+}
+
+}
+
+void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) {
+ DEBUG_ENTER_FUNC();
+
+#ifdef TEST_MEMORY_COPY
+ uint32 debugBytes = bytes;
+ const byte *debugDst = dst, *debugSrc = src;
+#endif
+
+ PSP_DEBUG_PRINT("copy(): dst[%p], src[%p], bytes[%d]\n", dst, src, bytes);
+
+ // align the destination pointer first
+ uint32 prefixDst = (((uint32)dst) & 0x3);
+
+ if (prefixDst) {
+ prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0
+ PSP_DEBUG_PRINT("prefixDst[%d]\n", prefixDst);
+
+ bytes -= prefixDst; // remember we assume bytes >= 4
+
+ if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
+ copy8(dst, src, bytes + prefixDst);
+#ifdef TEST_MEMORY_COPY
+ testCopy(debugDst, debugSrc, debugBytes);
+#endif
+ return;
+ }
+
+ while (prefixDst--) {
+ *dst++ = *src++;
+ }
+ }
+
+ // check the source pointer alignment now
+ uint32 alignSrc = (((uint32)src) & 0x3);
+
+ if (alignSrc) { // we'll need to realign our reads
+ copy32Misaligned((uint32 *)dst, src, bytes, alignSrc);
+ } else {
+ copy32Aligned((uint32 *)dst, (uint32 *)src, bytes);
+ }
+
+#ifdef TEST_MEMORY_COPY
+ testCopy(debugDst, debugSrc, debugBytes);
+#endif
+}
+
+void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) {
+
+ bool mismatch = false;
+ PSP_INFO_PRINT("testing fastCopy...");
+
+ for (uint32 i = 0; i < debugBytes; i++) {
+ if (debugDst[i] != debugSrc[i]) {
+ if (!mismatch) {
+ PSP_INFO_PRINT("**** mismatch in copy! ****\n");
+ PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
+ mismatch = true;
+ }
+ PSP_INFO_PRINT("[%d]%x!=%x ", i, debugSrc[i], debugDst[i]);
+ }
+ }
+ if (mismatch) {
+ PSP_INFO_PRINT("\n");
+ } else {
+ PSP_INFO_PRINT("ok\n");
+ }
+}
+
+//
+// used to swap red and blue
+void PspMemory::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
+ DEBUG_ENTER_FUNC();
+
+#ifdef TEST_MEMORY_COPY
+ uint32 debugBytes = bytes;
+ const uint16 *debugDst = dst16, *debugSrc = src16;
+#endif
+
+ // align the destination pointer first
+ uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix
+
+ if (prefixDst) {
+ bytes -= prefixDst; // remember we assume bytes > 4
+ *dst16++ = format.swapRedBlue16(*src16++);
+
+ if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
+ swap16(dst16, src16, bytes, format);
+
+#ifdef TEST_MEMORY_COPY
+ testSwap(debugDst, debugSrc, debugBytes, format);
+#endif
+ return;
+ }
+ }
+
+ // check the source pointer alignment now
+ uint32 alignSrc = (((uint32)src16) & 0x3);
+
+ if (alignSrc) { // we'll need to realign our reads
+ PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16);
+ swap32Misaligned((uint32 *)dst16, src16, bytes, format);
+ } else {
+ swap32Aligned((uint32 *)dst16, (const uint32 *)src16, bytes, format);
+ }
+
+#ifdef TEST_MEMORY_COPY
+ testSwap(debugDst, debugSrc, debugBytes, format);
+#endif
+
+}
+
+void PspMemory::testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format) {
+
+ bool mismatch = false;
+ PSP_INFO_PRINT("testing fastSwap...");
+
+ uint32 shorts = debugBytes >> 1;
+
+ for (uint32 i = 0; i < shorts; i++) {
+ if (debugDst[i] != format.swapRedBlue16(debugSrc[i])) {
+ if (!mismatch) {
+ PSP_INFO_PRINT("**** mismatch in swap! ****\n");
+ PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
+ mismatch = true;
+ }
+ PSP_INFO_PRINT("[%d]%x!=%x ", i<<1, format.swapRedBlue16(debugSrc[i]), debugDst[i]);
+ }
+ }
+ if (mismatch) {
+ PSP_INFO_PRINT("\n");
+ } else {
+ PSP_INFO_PRINT("ok\n");
+ }
+}
+
+
+void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) {
+ PSP_DEBUG_PRINT("copy32Aligned(): dst32[%p], src32[%p], bytes[%d]\n", dst32, src32, bytes);
+
+ int words8 = bytes >> 5;
+
+ // try blocks of 8 words at a time
+ if (words8) {
+ while (words8--) {
+ uint32 a, b, c, d;
+ a = src32[0];
+ b = src32[1];
+ c = src32[2];
+ d = src32[3];
+ dst32[0] = a;
+ dst32[1] = b;
+ dst32[2] = c;
+ dst32[3] = d;
+ a = src32[4];
+ b = src32[5];
+ c = src32[6];
+ d = src32[7];
+ dst32[4] = a;
+ dst32[5] = b;
+ dst32[6] = c;
+ dst32[7] = d;
+ dst32 += 8;
+ src32 += 8;
+ }
+ }
+
+ int words4 = (bytes & 0x1F) >> 4;
+
+ // try blocks of 4 words at a time
+ if (words4) {
+ uint32 a, b, c, d;
+ a = src32[0];
+ b = src32[1];
+ c = src32[2];
+ d = src32[3];
+ dst32[0] = a;
+ dst32[1] = b;
+ dst32[2] = c;
+ dst32[3] = d;
+ dst32 += 4;
+ src32 += 4;
+ }
+
+ int bytesLeft = (bytes & 0xF); // only look at bytes left after we did the above
+ int wordsLeft = bytesLeft >> 2;
+
+ // now just do single words
+ while (wordsLeft) {
+ *dst32++ = *src32++;
+ wordsLeft--;
+ }
+
+ bytesLeft = bytes & 0x3; // get remaining bytes
+
+ PSP_DEBUG_PRINT("bytesLeft[%d]\n", bytesLeft);
+
+ byte *dst = (byte *)dst32;
+ byte *src = (byte *)src32;
+
+ while (bytesLeft--) {
+ *dst++ = *src++;
+ }
+}
+
+void PspMemory::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) {
+ DEBUG_ENTER_FUNC();
+ int words4 = bytes >> 4;
+
+ // try blocks of 4 words at a time
+ while (words4--) {
+ uint32 a, b, c, d;
+ a = format.swapRedBlue32(src32[0]);
+ b = format.swapRedBlue32(src32[1]);
+ c = format.swapRedBlue32(src32[2]);
+ d = format.swapRedBlue32(src32[3]);
+ dst32[0] = a;
+ dst32[1] = b;
+ dst32[2] = c;
+ dst32[3] = d;
+ dst32 += 4;
+ src32 += 4;
+ }
+
+ uint32 bytesLeft = bytes & 0xF;
+ uint32 words = bytesLeft >> 2;
+
+ // now just do words
+ while (words--) {
+ *dst32++ = format.swapRedBlue32(*src32++);
+ }
+
+ bytesLeft = bytes & 0x3;
+
+ if (bytesLeft) { // for swap, can only be 1 short left
+ *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32));
+ }
+}
+
+
+// More challenging -- need to shift
+// Assume dst is aligned
+void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc) {
+ PSP_DEBUG_PRINT("copy32Misaligned: dst32[%p], src[%p], bytes[%d], alignSrc[%d]\n", dst32, src, bytes, alignSrc);
+
+ uint32 *src32 = (uint32 *)(((uint32)src) & 0xFFFFFFFC); // remove misalignment
+ uint32 offset;
+
+ switch (alignSrc) {
+ case 1:
+ offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 8, 24);
+ break;
+ case 2:
+ offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 16, 16);
+ break;
+ default: /* 3 */
+ offset = misaligned32Detail(dst32, src32, bytes, alignSrc, 24, 8);
+ break;
+ }
+
+ uint32 remainingBytes = bytes & 3;
+
+ if (remainingBytes) {
+ byte *dst = (byte *)dst32;
+ src += offset;
+ dst += offset;
+ copy8(dst, src, remainingBytes);
+ }
+}
+
+// returns offset in dst
+uint32 PspMemory::misaligned32Detail(uint32 *dst32, uint32 *src32, uint32 bytes, uint32 alignSrc, const uint32 shiftValue, const uint32 lastShiftValue) {
+ uint32 *origDst32 = dst32;
+ register uint32 dstWord, srcWord;
+
+ PSP_DEBUG_PRINT("misaligned32Detail(): alignSrc[%d], dst32[%p], src32[%p], bytes[%d]\n", alignSrc, dst32, src32, bytes);
+
+ // Try to do groups of 4 words
+ uint32 words4 = bytes >> 4;
+
+ srcWord = src32[0];
+
+ while (words4--) {
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[1];
+ dstWord |= srcWord << lastShiftValue;
+ dst32[0] = dstWord;
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[2];
+ dstWord |= srcWord << lastShiftValue;
+ dst32[1] = dstWord;
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[3];
+ dstWord |= srcWord << lastShiftValue;
+ dst32[2] = dstWord;
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[4];
+ dstWord |= srcWord << lastShiftValue;
+ dst32[3] = dstWord;
+ src32 += 4;
+ dst32 += 4;
+ }
+
+ uint32 words = (bytes & 0xF) >> 2;
+
+ // we read one word ahead of what we write
+ // setup the first read
+ if (words) {
+ src32++; // we already loaded the value, so just increment
+
+ while (words--) {
+ dstWord = srcWord >> shiftValue;
+ srcWord = *src32++;
+ dstWord |= srcWord << lastShiftValue;
+ *dst32++ = dstWord;
+ }
+ }
+
+ return (byte *)dst32 - (byte *)origDst32;
+}
+
+// More challenging -- need to shift
+// We assume dst is aligned
+void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
+ DEBUG_ENTER_FUNC();
+
+ const uint32 shiftValue = 16;
+ uint32 *src32 = (uint32 *)(((uint32)src16) & 0xFFFFFFFC); // remove misalignment
+
+ // Try to do groups of 4 words
+ uint32 words4 = bytes >> 4;
+ uint32 srcWord = src32[0]; // preload
+
+ while (words4--) {
+ uint32 dstWord = srcWord >> shiftValue;
+ srcWord = src32[1];
+ dstWord |= srcWord << shiftValue;
+ dst32[0] = format.swapRedBlue32(dstWord);
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[2];
+ dstWord |= srcWord << shiftValue;
+ dst32[1] = format.swapRedBlue32(dstWord);
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[3];
+ dstWord |= srcWord << shiftValue;
+ dst32[2] = format.swapRedBlue32(dstWord);
+ dstWord = srcWord >> shiftValue;
+ srcWord = src32[4];
+ dstWord |= srcWord << shiftValue;
+ dst32[3] = format.swapRedBlue32(dstWord);
+ src32 += 4;
+ dst32 += 4;
+ }
+
+ uint32 words = (bytes & 0xF) >> 2;
+
+ // we read one word ahead of what we write
+ // setup the first read
+ if (words) {
+ //srcWord = *src32++; // don't need this. already loaded
+ src32++; // we already have the value loaded in
+
+ while (words--) {
+ uint32 dstWord = srcWord >> shiftValue;
+ srcWord = *src32++;
+ dstWord |= srcWord << shiftValue;
+ *dst32++ = format.swapRedBlue32(dstWord);
+ }
+ }
+
+ uint32 bytesLeft = bytes & 3;
+
+ if (bytesLeft) { // for swap, can only be 1 short left
+ *((uint16 *)dst32) = format.swapRedBlue16((uint16)(srcWord >> shiftValue));
+ }
+}
+
+inline void PspMemory::copy16(uint16 *dst16, const uint16 *src16, uint32 bytes) {
+ PSP_DEBUG_PRINT("copy16(): dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes);
+
+ uint32 shorts = bytes >> 1;
+ uint32 remainingBytes = bytes & 1;
+
+ for (; shorts > 0 ; shorts--) {
+ *dst16++ = *src16++;
+ }
+ if (remainingBytes)
+ *(byte *)dst16 = *(byte *)src16;
+}
+
+// Class VramAllocator -----------------------------------
+
+DECLARE_SINGLETON(VramAllocator)
+
+//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
+//#define __PSP_DEBUG_PRINT__
+
+#include "backends/platform/psp/trace.h"
+
+
+void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) {
+ DEBUG_ENTER_FUNC();
+ assert(size > 0);
+
+ byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS;
+ Common::List<Allocation>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _allocList.begin(); i != _allocList.end(); ++i) {
+ byte *currAddress = (*i).address;
+
+ if (currAddress - lastAddress >= size) // We found a match
+ break;
+
+ if ((*i).getEnd() > lastAddress)
+ lastAddress = (byte *)(*i).getEnd();
+ }
+
+ if (lastAddress + size > (byte *)VRAM_END_ADDRESS) {
+ PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n",
+ size, _bytesAllocated);
+ return NULL;
+ }
+
+ _allocList.insert(i, Allocation(lastAddress, size));
+ _bytesAllocated += size;
+
+ PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress);
+ PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated);
+
+ return lastAddress;
+}
+
+// Deallocate a block from VRAM
+void VramAllocator::deallocate(void *address) {
+ DEBUG_ENTER_FUNC();
+ address = (byte *)CACHED(address); // Make sure all addresses are the same
+
+ Common::List<Allocation>::iterator i;
+
+ // Find the Allocator to deallocate
+ for (i = _allocList.begin(); i != _allocList.end(); ++i) {
+ if ((*i).address == address) {
+ _bytesAllocated -= (*i).size;
+ _allocList.erase(i);
+ PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size);
+ return;
+ }
+ }
+
+ PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address);
+}