int main(int argc, char *argv[]) {
	sceKernelSetCompiledSdkVersion(0x2060010);
	schedf("Until 2.60:\n");
	runReferTests();

	sceKernelSetCompiledSdkVersion(0x2060011);
	schedf("\n\nAfter 2.60:\n");
	runReferTests();

	return 0;
}
void testSdkVersion(u32 ver) {
	char temp[256];
	snprintf(temp, sizeof(temp), "SDK version %08x", ver);
	checkpointNext(temp);
	if (ver != 0) {
		sceKernelSetCompiledSdkVersion(ver);
	}

	PspGeCallbackData cbdata;

	cbdata.signal_func = (PspGeCallback) ge_signal;
	cbdata.signal_arg  = NULL;
	cbdata.finish_func = (PspGeCallback) ge_finish;
	cbdata.finish_arg  = NULL;
	int cbid1 = sceGeSetCallback(&cbdata);

	listid = sceGeListEnQueue(dlist1, dlist1, cbid1, NULL);
	sceGeListUpdateStallAddr(listid, dlist1 + 100);
	checkpoint("  Delay: %08x", sceKernelDelayThread(10000));
	checkpoint("  Continue: %08x", sceGeContinue());
	checkpoint("  Delay: %08x", sceKernelDelayThread(10000));
	sceGeBreak(1, NULL);
	checkpoint("  Done: %x", sceGeGetCmd(GE_CMD_AMBIENTCOLOR));

	sceGeUnsetCallback(cbid1);

	cbdata.signal_func = (PspGeCallback) ge_signal2;
	cbdata.signal_arg  = NULL;
	cbdata.finish_func = (PspGeCallback) ge_finish;
	cbdata.finish_arg  = NULL;
	int cbid2 = sceGeSetCallback(&cbdata);

	listid = sceGeListEnQueue(dlist1, dlist1, cbid2, NULL);
	sceGeListUpdateStallAddr(listid, dlist1 + 100);
	checkpoint("  Delay: %08x", sceKernelDelayThread(10000));
	checkpoint("  Continue: %08x", sceGeContinue());
	checkpoint("  Delay: %08x", sceKernelDelayThread(10000));
	sceGeBreak(1, NULL);
	checkpoint("  Done: %x", sceGeGetCmd(GE_CMD_AMBIENTCOLOR));
	
	sceGeUnsetCallback(cbid2);
}
int main(int argc, char *argv[])
{
	SceCtrlData pad;
	int oldButtons = 0;
#define SECOND	   1000000
#define REPEAT_START (1 * SECOND)
#define REPEAT_DELAY (SECOND / 5)
	struct timeval repeatStart;
	struct timeval repeatDelay;

	repeatStart.tv_sec = 0;
	repeatStart.tv_usec = 0;
	repeatDelay.tv_sec = 0;
	repeatDelay.tv_usec = 0;

	pspDebugScreenInit();
	pspDebugScreenPrintf("Press Cross to start the IO Test\n");

	while(!done)
	{
		sceCtrlReadBufferPositive(&pad, 1);
		int buttonDown = (oldButtons ^ pad.Buttons) & pad.Buttons;

		if (pad.Buttons == oldButtons)
		{
			struct timeval now;
			gettimeofday(&now, NULL);
			if (repeatStart.tv_sec == 0)
			{
				repeatStart.tv_sec = now.tv_sec;
				repeatStart.tv_usec = now.tv_usec;
				repeatDelay.tv_sec = 0;
				repeatDelay.tv_usec = 0;
			}
			else
			{
				long usec = (now.tv_sec - repeatStart.tv_sec) * SECOND;
				usec += (now.tv_usec - repeatStart.tv_usec);
				if (usec >= REPEAT_START)
				{
					if (repeatDelay.tv_sec != 0)
					{
						usec = (now.tv_sec - repeatDelay.tv_sec) * SECOND;
						usec += (now.tv_usec - repeatDelay.tv_usec);
						if (usec >= REPEAT_DELAY)
						{
							repeatDelay.tv_sec = 0;
						}
					}

					if (repeatDelay.tv_sec == 0)
					{
						buttonDown = pad.Buttons;
						repeatDelay.tv_sec = now.tv_sec;
						repeatDelay.tv_usec = now.tv_usec;
					}
				}
			}
		}
		else
		{
			repeatStart.tv_sec = 0;
		}

		if (buttonDown & PSP_CTRL_CROSS)
		{
			sceKernelSetCompiledSdkVersion(0x307FFFF);
			runTest();
			sceKernelSetCompiledSdkVersion(0x307FFFF + 1);
			runTest();
		}

		if (buttonDown & PSP_CTRL_TRIANGLE)
		{
			done = 1;
		}

		oldButtons = pad.Buttons;
	}

	sceGuTerm();

	sceKernelExitGame();
	return 0;
}
extern "C" int main(int argc, char *argv[]) {
	ExitCallbackArg arg;
	ExitCallbackArgParams params;

	arg.unknown1 = 0;
	arg.params = &params;
	params.size = 12;
	params.unk1 = 0x1337;
	params.unk2 = 0x1337;

	Callback cb1("count1", &cbFunc, NULL);
	Callback cb2("count2", &cbFunc, &arg.common);

	checkpointNext("Objects:");
	checkpoint("  Normal: %08x", sceKernelRegisterExitCallback(cb1));
	checkpoint("  NULL: %08x", sceKernelRegisterExitCallback(0));
	checkpoint("  Invalid: %08x", sceKernelRegisterExitCallback(0xDEADBEEF));
	cb1.Delete();
	checkpoint("  Deleted: %08x", sceKernelRegisterExitCallback(cb1));

	sceKernelSetCompiledSdkVersion(0x3090500);
	cb1.Create("count1", &cbFunc, NULL);

	checkpointNext("Objects (SDK 3.95+):");
	checkpoint("  Normal: %08x", sceKernelRegisterExitCallback(cb1));
	checkpoint("  NULL: %08x", sceKernelRegisterExitCallback(0));
	checkpoint("  Invalid: %08x", sceKernelRegisterExitCallback(0xDEADBEEF));
	cb1.Delete();
	checkpoint("  Deleted: %08x", sceKernelRegisterExitCallback(cb1));
	
	cb1.Create("count1", &cbFunc, NULL);
	checkpointNext("LoadExecForUser_362A956B:");
	testLoadExec362A956B("  With invalid CB", arg);
	checkpoint("  Register without arg: %08x", sceKernelRegisterExitCallback(cb1));
	testLoadExec362A956B("  Without arg", arg);
	checkpoint("  Register invalid: %08x", sceKernelRegisterExitCallback(0));
	testLoadExec362A956B("  With invalid again", arg);
	checkpoint("  Register valid: %08x", sceKernelRegisterExitCallback(cb2));

	int unknown1s[] = {-1, 0, 1, 2, 3, 4};
	for (size_t i = 0; i < ARRAY_SIZE(unknown1s); ++i) {
		char temp[32];
		snprintf(temp, sizeof(temp), "  arg.unknown1 = %d", unknown1s[i]);
		arg.unknown1 = unknown1s[i];
		params.unk1 = 0x1337;
		params.unk2 = 0x1337;
		testLoadExec362A956B(temp, arg);
	}
	arg.unknown1 = 0;

	int sizes[] = {-1, 0, 1, 2, 3, 4, 11, 12, 13, 16};
	for (size_t i = 0; i < ARRAY_SIZE(sizes); ++i) {
		char temp[32];
		snprintf(temp, sizeof(temp), "  arg.param->size = %d", sizes[i]);
		params.size = sizes[i];
		params.unk1 = 0x1337;
		params.unk2 = 0x1337;
		testLoadExec362A956B(temp, arg);
	}
	params.size = 12;

	cb1.Delete();
	cb2.Delete();
	return 0;
}