示例#1
0
int PspSpeedTests::threadFunc(SceSize args, void *argp) {
	PSP_INFO_PRINT("thread %x created.\n", sceKernelGetThreadId());

	_sem.take();

	PSP_INFO_PRINT("grabbed semaphore. Quitting thread\n");

	return 0;
}
示例#2
0
void printBuffer(byte *ptr, uint32 len) {
	uint32 printLen = len <= 10 ? len : 10;

	for (int i = 0; i < printLen; i++) {
		PSP_INFO_PRINT("%x ", ptr[i]);
	}

	if (len > 10) {
		PSP_INFO_PRINT("... ");
		for (int i = len - 10; i < len; i++)
			PSP_INFO_PRINT("%x ", ptr[i]);
	}

	PSP_INFO_PRINT("\n");
}
示例#3
0
int main(void) {
	//change clock rate to 333mhz
	scePowerSetClockFrequency(333, 333, 166);

	PowerManager::instance();	// Setup power manager

	SetupCallbacks();

	static const char *argv[] = { "scummvm", NULL };
	static int argc = sizeof(argv) / sizeof(char *) - 1;

	g_system = new OSystem_PSP();
	assert(g_system);

#ifdef DYNAMIC_MODULES
	PluginManager::instance().addPluginProvider(new PSPPluginProvider());
#endif

/* unit/speed tests */
#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
	PSP_INFO_PRINT("running tests\n");
	psp_tests();
	sceKernelSleepThread();	// that's it. That's all we're doing
#endif

	int res = scummvm_main(argc, argv);

	g_system->quit();	// TODO: Consider removing / replacing this!

	PowerManager::destroy();	// get rid of PowerManager

	sceKernelSleepThread();

	return res;
}
示例#4
0
void PspSpeedTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes) {
	uint32 time1, time2;
	uint32 fastcopyTime, memcpyTime;
	const int iterations = 2000;
	int intc;

	intc = pspSdkDisableInterrupts();

	time1 = PspRtc::instance().getMicros();
	for (int i=0; i<iterations; i++) {
		PspMemory::fastCopy(dst, src, bytes);
	}
	time2 = PspRtc::instance().getMicros();

	pspSdkEnableInterrupts(intc);

	fastcopyTime = time2-time1;

	intc = pspSdkDisableInterrupts();

	time1 = PspRtc::instance().getMicros();
	for (int i=0; i<iterations; i++) {
		memcpy(dst, src, bytes);
	}
	time2 = PspRtc::instance().getMicros();

	pspSdkEnableInterrupts(intc);

	memcpyTime = time2-time1;

	PSP_INFO_PRINT("%d bytes. memcpy[%d], fastcopy[%d]\n", bytes, memcpyTime, fastcopyTime);
}
示例#5
0
// 222: 9-10us
void PspSpeedTests::changePrioritySpeed(int id, int priority) {
	uint32 time1 = PspRtc::instance().getMicros();
	sceKernelChangeThreadPriority(id, priority);
	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Changing thread priority to %d for id %d took %dus\n", priority, id, time2-time1);
}
示例#6
0
// 222: 4-5us
void PspSpeedTests::getPrioritySpeed() {
	uint32 time1 = PspRtc::instance().getMicros();
	int priority = sceKernelGetThreadCurrentPriority();
	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Getting thread priority %d took %dus\n", priority, time2-time1);
}
示例#7
0
void psp_tests() {
	PSP_INFO_PRINT("in tests\n");

#ifdef PSP_ENABLE_SPEED_TESTS
	// Speed tests
	PspSpeedTests speedTests;
	speedTests.tickSpeed();
	speedTests.getMicrosSpeed();
	speedTests.msReadSpeed();
	speedTests.seekSpeed();
	speedTests.msReadSpeed();
	speedTests.threadFunctionsSpeed();
	speedTests.semaphoreSpeed();
	speedTests.semaphoreManyThreadSpeed();
	speedTests.fastCopySpeed();
#endif

#ifdef PSP_ENABLE_UNIT_TESTS
	// Unit tests
	PspUnitTests unitTests;

	//unitTests.testFastCopy();
	unitTests.testFileSystem();
#endif
}
示例#8
0
void PspSpeedTests::readAndTime(uint32 bytes, char *buffer, FILE *file) {
	uint32 time1 = PspRtc::instance().getMicros();
	// test minimal read
	fread(buffer, bytes, 1, file);
	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1);
}
示例#9
0
void PspSpeedTests::seekAndTime(int bytes, int origin, FILE *file) {
	char buffer[1000];

	uint32 time1 = PspRtc::instance().getMicros();
	// test minimal read
	fseek(file, bytes, origin);
	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Seeking %d byte from %d took %dus\n", bytes, origin, time2-time1);

	time1 = PspRtc::instance().getMicros();
	// test minimal read
	fread(buffer, 1000, 1, file);
	time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Reading 1000 bytes took %dus\n", time2-time1);
}
示例#10
0
void PspSpeedTests::semaphoreSpeed() {
	PspSemaphore sem(1);

	uint32 time1 = PspRtc::instance().getMicros();

	sem.take();

	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("taking semaphore took %d us\n", time2-time1);	// 10us

	uint32 time3 = PspRtc::instance().getMicros();

	sem.give();

	uint32 time4 = PspRtc::instance().getMicros();
	PSP_INFO_PRINT("releasing semaphore took %d us\n", time4-time3);	//10us-55us
}
示例#11
0
// 222: 5-7us
int PspSpeedTests::getThreadIdSpeed() {
	uint32 time1 = PspRtc::instance().getMicros();
	int threadId = sceKernelGetThreadId();
	uint32 time2 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("Getting thread ID %d took %dus\n", threadId, time2-time1);

	return threadId;
}
示例#12
0
void PspSpeedTests::getMicrosSpeed() {
	uint32 time1, time2, time3, time4;
	time1 = PspRtc::instance().getMicros();
	time2 = PspRtc::instance().getMicros();
	time3 = PspRtc::instance().getMicros();
	time4 = PspRtc::instance().getMicros();

	PSP_INFO_PRINT("getMicros() times: %d, %d, %d\n", time4-time3, time3-time2, time2-time1);
}
示例#13
0
void PspSpeedTests::semaphoreManyThreadSpeed() {

	// create 4 threads
	for (int i=0; i<4; i++) {
		int thid = sceKernelCreateThread("my_thread", PspSpeedTests::threadFunc, 0x18, 0x10000, THREAD_ATTR_USER, NULL);
		sceKernelStartThread(thid, 0, 0);
	}

	PSP_INFO_PRINT("main thread. created threads\n");

	uint32 threads = _sem.numOfWaitingThreads();
	while (threads < 4) {
		threads = _sem.numOfWaitingThreads();
		PSP_INFO_PRINT("main thread: waiting threads[%d]\n", threads);
	}

	PSP_INFO_PRINT("main: semaphore value[%d]\n", _sem.getValue());
	PSP_INFO_PRINT("main thread: waiting threads[%d]\n", _sem.numOfWaitingThreads());

	_sem.give(4);
}
示例#14
0
void PspUnitTests::testFastCopy() {
	PSP_INFO_PRINT("running fastcopy unit test ***********\n");
	PSP_INFO_PRINT("this test requires the test flag to be on in fastCopy\n\n");

	uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
	uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);

	// fill buffer 1
	for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
		bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);

	// print buffer
	for (int i=0; i<50; i++)
		PSP_INFO_PRINT("%x ", bufferSrc32[i]);
	PSP_INFO_PRINT("\n");

	byte *bufferSrc = ((byte *)bufferSrc32);
	byte *bufferDst = ((byte *)bufferDst32);

	fastCopyDifferentSizes(bufferDst, bufferSrc, true);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+2, bufferSrc+2, true);
	fastCopyDifferentSizes(bufferDst+3, bufferSrc+3);
	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst, bufferSrc+2, true);
	fastCopyDifferentSizes(bufferDst+2, bufferSrc, true);
	fastCopyDifferentSizes(bufferDst, bufferSrc+3);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+2);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+3);
	fastCopyDifferentSizes(bufferDst+2, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+2, bufferSrc+3);
	fastCopyDifferentSizes(bufferDst+3, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+3, bufferSrc+2);

	free(bufferSrc32);
	free(bufferDst32);
}
示例#15
0
int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
	DEBUG_ENTER_FUNC();

	int samples = 0;
#ifdef PRINT_BUFFERS
	int16 *debugBuffer = buffer;
#endif

	// Keep going as long as we have input available
	while (samples < numSamples && _state != MP3_STATE_EOS) {
		const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header));

		while (samples < len) {
			*buffer++ = _pcmSamples[_posInFrame << 1];
			samples++;
			if (MAD_NCHANNELS(&_header) == 2) {
				*buffer++ = _pcmSamples[(_posInFrame << 1) + 1];
				samples++;
			}
			_posInFrame++;	// always skip an extra sample since ME always outputs stereo
		}

		if (_posInFrame >= _pcmLength) {
			// We used up all PCM data in the current frame -- read & decode more
			decodeMP3Data();
		}
	}

#ifdef PRINT_BUFFERS
		PSP_INFO_PRINT("buffer:\n");
		for (int i = 0; i<numSamples; i++)
			PSP_INFO_PRINT("%d ", debugBuffer[i]);
		PSP_INFO_PRINT("\n\n");
#endif

	return samples;
}
示例#16
0
void PspSpeedTests::fastCopySpeed() {
	PSP_INFO_PRINT("running fastCopy speed test\n");

	uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
	uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);

	// fill buffer 1
	for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
		bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);

	// print buffer
	for (int i=0; i<50; i++)
		PSP_INFO_PRINT("%x ", bufferSrc32[i]);
	PSP_INFO_PRINT("\n");

	byte *bufferSrc = ((byte *)bufferSrc32);
	byte *bufferDst = ((byte *)bufferDst32);

	PSP_INFO_PRINT("\n\ndst and src cached: -----------------\n");
	fastCopyDifferentSizes(bufferDst, bufferSrc);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc);

	PSP_INFO_PRINT("\n\ndst cached, src uncached: -----------------\n");
	bufferSrc = UNCACHED(bufferSrc);
	fastCopyDifferentSizes(bufferDst, bufferSrc);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc);

	PSP_INFO_PRINT("\n\ndst uncached, src uncached: --------------\n");
	bufferDst = UNCACHED(bufferDst);
	fastCopyDifferentSizes(bufferDst, bufferSrc);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc);

	PSP_INFO_PRINT("\n\ndst uncached, src cached: -------------------\n");
	bufferSrc = CACHED(bufferSrc);
	fastCopyDifferentSizes(bufferDst, bufferSrc);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst, bufferSrc+1);
	fastCopyDifferentSizes(bufferDst+1, bufferSrc);


	free(bufferSrc32);
	free(bufferDst32);
}
示例#17
0
void PspSpeedTests::fastCopyDifferentSizes(byte *dst, byte *src) {
	PSP_INFO_PRINT("\nsrc[%p], dst[%p]\n", src, dst);
	fastCopySpecificSize(dst, src, 1);
	fastCopySpecificSize(dst, src, 2);
	fastCopySpecificSize(dst, src, 3);
	fastCopySpecificSize(dst, src, 4);
	fastCopySpecificSize(dst, src, 5);
	fastCopySpecificSize(dst, src, 8);
	fastCopySpecificSize(dst, src, 10);
	fastCopySpecificSize(dst, src, 16);
	fastCopySpecificSize(dst, src, 32);
	fastCopySpecificSize(dst, src, 50);
	fastCopySpecificSize(dst, src, 100);
	fastCopySpecificSize(dst, src, 500);
	fastCopySpecificSize(dst, src, 1024);
	fastCopySpecificSize(dst, src, 2048);
}
示例#18
0
void PspSpeedTests::threadFunctionsSpeed() {
	// very unscientific -- just ballpark
	int id;
	id = getThreadIdSpeed();
	getThreadIdSpeed();
	getPrioritySpeed();
	getPrioritySpeed();
	changePrioritySpeed(id, 30);
	changePrioritySpeed(id, 35);
	changePrioritySpeed(id, 25);

	// test context switch time
	for (int i=0; i<10; i++) {
		uint time1 = PspRtc::instance().getMicros();
		PspThread::delayMicros(0);
		uint time2 = PspRtc::instance().getMicros();
		PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1);	// 10-15us
	}
}
示例#19
0
inline void MasterGuRenderer::guPostRender() {
	DEBUG_ENTER_FUNC();

	sceGuFinish();
#ifdef USE_DISPLAY_CALLBACK
	if (_callbackId < 0)
		PSP_ERROR("bad callbackId[%d]\n", _callbackId);
	else
		sceKernelNotifyCallback(_callbackId, 0);	// notify the callback. Nothing extra to pass
#else
	sceGuSync(0, 0);

#ifdef ENABLE_RENDER_MEASURE
	uint32 now = g_system->getMillis();
	PSP_INFO_PRINT("Render took %d milliseconds\n", now - _lastRenderTime);
#endif /* ENABLE_RENDER_MEASURE */

	sceDisplayWaitVblankStart();
	sceGuSwapBuffers();
	_renderFinished = true;
#endif /* !USE_DISPLAY_CALLBACK */
}
示例#20
0
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");
	}
}
示例#21
0
void PspMemorySwap::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");
	}
}
示例#22
0
void PspSpeedTests::tickSpeed() {
	uint32 ticksPerSecond = sceRtcGetTickResolution();
	PSP_INFO_PRINT("ticksPerSecond[%d]\n", ticksPerSecond);

	uint32 currentTicks1[2];
	uint32 currentTicks2[2];

	sceRtcGetCurrentTick((u64 *)currentTicks1);
	sceRtcGetCurrentTick((u64 *)currentTicks2);
	PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks1[0], currentTicks1[1], currentTicks1[0], currentTicks1[1]);
	PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks2[0], currentTicks2[1], currentTicks2[0], currentTicks2[1]);

	pspTime time;
	sceRtcSetTick(&time, (u64 *)currentTicks2);
	PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds);

	pspTime time1;
	pspTime time2;
	sceRtcGetCurrentClockLocalTime(&time1);
	sceRtcGetCurrentClockLocalTime(&time2);
	PSP_INFO_PRINT("time1, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time1.year, time1.month, time1.day, time1.hour, time1.minutes, time1.seconds, time1.microseconds);
	PSP_INFO_PRINT("time2, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time2.year, time2.month, time2.day, time2.hour, time2.minutes, time2.seconds, time2.microseconds);
}
示例#23
0
void Mp3PspStream::decodeMP3Data() {
	DEBUG_ENTER_FUNC();

	do {
		if (_state == MP3_STATE_INIT) {
			initStream();
			initStreamME();
		}

		if (_state == MP3_STATE_EOS)
			return;

		findValidHeader();	// seach for next valid header

		while (_state == MP3_STATE_READY) {	// not a real 'while'. Just for easy flow
			_stream.error = MAD_ERROR_NONE;

			uint32 frame_size = _stream.next_frame - _stream.this_frame;

			updatePcmLength(); // Retrieve the number of PCM samples.
							   // We seem to change this, so it needs to be dynamic

			PSP_DEBUG_PRINT("MP3 frame size[%d]. pcmLength[%d]\n", frame_size, _pcmLength);

			memcpy(_codecInBuffer, _stream.this_frame, frame_size);	// we need it aligned

			// set up parameters for ME
			_codecParams[6] = (unsigned long)_codecInBuffer;
			_codecParams[8] = (unsigned long)_pcmSamples;
			_codecParams[7] = frame_size;
			_codecParams[9] = _pcmLength * 2;	// x2 for stereo, though this one's not so important

			// debug
#ifdef PRINT_BUFFERS
			PSP_DEBUG_PRINT("mp3 frame:\n");
			for (int i=0; i < (int)frame_size; i++) {
				PSP_DEBUG_PRINT_SAMELN("%x ", _codecInBuffer[i]);
			}
			PSP_DEBUG_PRINT("\n");
#endif
			// Decode the next frame
			// This function blocks. We'll want to put it in a thread
			int ret = sceAudiocodecDecode(_codecParams, 0x1002);
			if (ret < 0) {
				PSP_INFO_PRINT("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret);
			}

#ifdef PRINT_BUFFERS
			PSP_DEBUG_PRINT("PCM frame:\n");
			for (int i=0; i < (int)_codecParams[9]; i+=2) {	// changed from i+=2
				PSP_DEBUG_PRINT_SAMELN("%d ", (int16)_pcmSamples[i]);
			}
			PSP_DEBUG_PRINT("\n");
#endif
			_posInFrame = 0;
			break;
		}
	} while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);

	if (_stream.error != MAD_ERROR_NONE)	// catch EOS
		_state = MP3_STATE_EOS;
}
示例#24
0
// This function leaks. For now I don't care
bool PspUnitTests::testFileSystem() {
	// create memory
	const uint32 BufSize = 32 * 1024;
	char* buffer = new char[BufSize];
	int i;
	Common::WriteStream *wrStream;
	Common::SeekableReadStream *rdStream;

	PSP_INFO_PRINT("testing fileSystem...\n");

	// fill buffer
	for (i=0; i<(int)BufSize; i += 4) {
		buffer[i] = 'A';
		buffer[i + 1] = 'B';
		buffer[i + 2] = 'C';
		buffer[i + 3] = 'D';
	}

	// create a file
	const char *path = "./file.test";
	Common::FSNode file(path);

	PSP_INFO_PRINT("creating write stream...\n");

	wrStream = file.createWriteStream();
	if (!wrStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	// write contents
	char* index = buffer;
	int32 totalLength = BufSize;
	int32 curLength = 50;

	PSP_INFO_PRINT("writing...\n");

	while(totalLength - curLength > 0) {
		if ((int)wrStream->write(index, curLength) != curLength) {
			PSP_ERROR("couldn't write %d bytes\n", curLength);
			return false;
		}
		totalLength -= curLength;
		index += curLength;
		//curLength *= 2;
		//PSP_INFO_PRINT("write\n");
	}

	// write the rest
	if ((int)wrStream->write(index, totalLength) != totalLength) {
		PSP_ERROR("couldn't write %d bytes\n", curLength);
		return false;
	}

	delete wrStream;

	PSP_INFO_PRINT("reading...\n");

	rdStream = file.createReadStream();
	if (!rdStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	// seek to beginning
	if (!rdStream->seek(0, SEEK_SET)) {
		PSP_ERROR("couldn't seek to the beginning after writing the file\n");
		return false;
	}

	// read the contents
	char *readBuffer = new char[BufSize + 4];
	memset(readBuffer, 0, (BufSize + 4));
	index = readBuffer;
	while (rdStream->read(index, 100) == 100) {
		index += 100;
	}

	if (!rdStream->eos()) {
		PSP_ERROR("didn't find EOS at end of stream\n");
		return false;
	}

	// compare
	for (i=0; i<(int)BufSize; i++)
		if (buffer[i] != readBuffer[i]) {
			PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]);
			return false;
		}

	// Check for exceeding limit
	for (i=0; i<4; i++) {
		if (readBuffer[BufSize + i]) {
			PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]);
		}
	}

	delete rdStream;

	PSP_INFO_PRINT("writing...\n");

	wrStream = file.createWriteStream();
	if (!wrStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	const char *phrase = "Jello is really fabulous";
	uint32 phraseLen = strlen(phrase);

	int ret;
	if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) {
		PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen);
		return false;
	}

	PSP_INFO_PRINT("reading...\n");

	delete wrStream;
	rdStream = file.createReadStream();
	if (!rdStream) {
		PSP_ERROR("%s couldn't be created.\n", path);
		return false;
	}

	char *readPhrase = new char[phraseLen + 2];
	memset(readPhrase, 0, phraseLen + 2);

	if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) {
		PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen);
		return false;
	}

	for (i=0; i<(int)phraseLen; i++) {
		if (readPhrase[i] != phrase[i]) {
			PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]);
			return false;
		}
	}

	// check for exceeding
	if (readPhrase[i] != 0) {
		PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i);
		return false;
	}

	PSP_INFO_PRINT("trying to read end...\n");

	// seek to end
	if (!rdStream->seek(0, SEEK_END)) {
		PSP_ERROR("couldn't seek to end for append\n");
		return false;
	};

	// try to read
	if (rdStream->read(readPhrase, 2) || !rdStream->eos()) {
		PSP_ERROR("was able to read at end of file\n");
		return false;
	}

	PSP_INFO_PRINT("ok\n");
	return true;
}