aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/psp/memory.cpp
blob: e134a7d0f4a62ea3d3105c1bba06532aa0563b9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/* 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"

void Copier::copy(byte *dst, const byte *src, uint32 bytes, PSPPixelFormat *format /* = NULL */) {
	DEBUG_ENTER_FUNC();

	uint32 prefixDst = (((uint32)dst) & 0x3);
	prefixDst = prefixDst ? 4 - prefixDst : 0;	// prefix only if we have address % 4 != 0
	uint32 prefixSrc = (((uint32)src) & 0x3);
	prefixSrc = prefixSrc ? 4 - prefixSrc : 0;  // prefix only if we have address % 4 != 0
	uint32 *dst32, *src32;
	bool swapRB = format ? format->swapRB : false;	// take swap value from pixelformat if it's given
#ifdef __PSP_DEBUG_PRINT__
	uint32 debugBytes = bytes;
	const byte *debugDst = dst, *debugSrc = src;
#endif
	uint32 words, remainingBytes;

	//PSP_DEBUG_PRINT("dst[%p], src[%p], bytes[%d], swap[%s], prefixDst[%u], prefixSrc[%u]\n", dst, src, bytes, swapRB ? "true" : "false", prefixDst, prefixSrc);

	if (prefixDst || prefixSrc) { 			// we're not aligned to word boundaries
		if (prefixDst != prefixSrc) {		// worst case: we can never be aligned. this mode is highly inefficient. try to get engines not to use this mode too much
			PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src, dst);
			if ((prefixDst & 1) || (prefixSrc & 1))
				copy8(dst, src, bytes);	// no swap is possible on 8 bit
			else
				copy16((uint16 *)dst, (uint16 *)src, bytes, format);

			goto test;
		}

		// Do the prefix: the part to get us aligned
		if (prefixDst & 1) { 			// byte
			copy8(dst, src, prefixDst);	// no swap available
		} else {						// short
			copy16((uint16 *)dst, (uint16 *)src, prefixDst, format);
		}
		if (bytes > prefixDst)	// check that we can afford to subtract from bytes
			bytes -= prefixDst;
		else {
			return;
		}
		dst32 = (uint32 *)(dst + prefixDst);
		src32 = (uint32 *)(src + prefixSrc);
	} else { // We're aligned to word boundaries
		dst32 = (uint32 *)dst;
		src32 = (uint32 *)src;
	}

	words = bytes >> 2;
	remainingBytes = bytes & 0x3;

	if (swapRB) {	// need to swap
		for (; words > 0; words--) {
			*dst32 = format->swapRedBlue32(*src32);
			dst32++;
			src32++;
		}
	} else { // no swapping
		for (; words > 0; words--) {
			*dst32 = *src32;
			dst32++;
			src32++;
		}
	}

	// Do any remaining bytes
	if (remainingBytes) {
		if (remainingBytes & 1)	// we have bytes left
			copy8((byte *)dst32, (byte *)src32, remainingBytes);
		else // 16bits left
			copy16((uint16*)dst32, (uint16 *)src32, remainingBytes, format);
	}

test:
	// debug
#ifdef __PSP_DEBUG_PRINT__
	bool mismatch = false;

	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], swap[%s], prefixDst[%u], prefixSrc[%u]\n", debugDst, debugSrc, debugBytes, swapRB ? "true" : "false", prefixDst, prefixSrc);
				mismatch = true;
			}
			PSP_DEBUG_PRINT_SAMELN("%x!=%x ", debugSrc[i], debugDst[i]);
		}
	}
	if (mismatch)
		PSP_DEBUG_PRINT("\n");
#endif

	return;		// So we have something to jump to with the label
}

inline void Copier::copy8(byte *dst, const byte *src, uint32 bytes) {
	for (; bytes > 0; bytes--) {
		*dst = *src;
		dst++;
		src++;
	}
}

inline void Copier::copy16(uint16 *dst, const uint16 *src, uint32 bytes, PSPPixelFormat *format /* = NULL */) {
	uint32 shorts = bytes >> 1;
	uint32 remainingBytes = bytes & 1;
	bool swapRB = format ? format->swapRB : false;

	if (swapRB) {
		for (; shorts > 0 ; shorts--) {
			*dst = format->swapRedBlue16(*src);
			dst++;
			src++;
		}
	} else {
		for (; shorts > 0 ; shorts--) {
			*dst = *src;
			dst++;
			src++;
		}
	}
	if (remainingBytes)
		*(byte *)dst = *(byte *)src;
}


// 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);
}