diff src/xsf/vio2sf.c @ 2961:70b0973e7b70

Merge xsf plugin.
author William Pitcock <nenolod@atheme.org>
date Thu, 16 Oct 2008 14:45:41 -0500
parents
children 6013ab159139
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/xsf/vio2sf.c	Thu Oct 16 14:45:41 2008 -0500
@@ -0,0 +1,833 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "desmume/MMU.h"
+#include "desmume/armcpu.h"
+#include "desmume/NDSSystem.h"
+#include "desmume/SPU.h"
+#include "desmume/cp15.h"
+
+#include <zlib.h>
+#include "tagget.h"
+#include "vio2sf.h"
+
+volatile BOOL execute = FALSE;
+
+static struct
+{
+	unsigned char *rom;
+	unsigned char *state;
+	unsigned romsize;
+	unsigned statesize;
+	unsigned stateptr;
+} loaderwork = {0, 0, 0, 0, 0};
+
+static void load_term(void)
+{
+	if (loaderwork.rom)
+	{
+		free(loaderwork.rom);
+		loaderwork.rom = 0;
+	}
+	loaderwork.romsize = 0;
+	if (loaderwork.state)
+	{
+		free(loaderwork.state);
+		loaderwork.state = 0;
+	}
+	loaderwork.statesize = 0;
+}
+
+static int load_map(int issave, unsigned char *udata, unsigned usize)
+{	
+	unsigned char *iptr;
+	unsigned isize;
+	unsigned char *xptr;
+	unsigned xsize = getdwordle(udata + 4);
+	unsigned xofs = getdwordle(udata + 0);
+	if (issave)
+	{
+		iptr = loaderwork.state;
+		isize = loaderwork.statesize;
+		loaderwork.state = 0;
+		loaderwork.statesize = 0;
+	}
+	else
+	{
+		iptr = loaderwork.rom;
+		isize = loaderwork.romsize;
+		loaderwork.rom = 0;
+		loaderwork.romsize = 0;
+	}
+	if (!iptr)
+	{
+		iptr = malloc(xofs + xsize + 10);
+		if (!iptr)
+			return XSF_FALSE;
+		memset(iptr, 0, xofs + xsize + 10);
+		isize = xofs + xsize;
+	}
+	else if (isize < xofs + xsize)
+	{
+		unsigned rsize = xofs + xsize;
+		if (!issave)
+		{
+			rsize -= 1;
+			rsize |= rsize >> 1;
+			rsize |= rsize >> 2;
+			rsize |= rsize >> 4;
+			rsize |= rsize >> 8;
+			rsize |= rsize >> 16;
+			rsize += 1;
+		}
+		xptr = realloc(iptr, xofs + rsize + 10);
+		if (!xptr)
+		{
+			free(iptr);
+			return XSF_FALSE;
+		}
+		iptr = xptr;
+		isize = rsize;
+	}
+	memcpy(iptr + xofs, udata + 8, xsize);
+	if (issave)
+	{
+		loaderwork.state = iptr;
+		loaderwork.statesize = isize;
+	}
+	else
+	{
+		loaderwork.rom = iptr;
+		loaderwork.romsize = isize;
+	}
+	return XSF_TRUE;
+}
+
+static int load_mapz(int issave, unsigned char *zdata, unsigned zsize, unsigned zcrc)
+{
+	int ret;
+	int zerr;
+	uLongf usize = 8;
+	uLongf rsize = usize;
+	unsigned char *udata;
+	unsigned char *rdata;
+
+	udata = malloc(usize);
+	if (!udata)
+		return XSF_FALSE;
+
+	while (Z_OK != (zerr = uncompress(udata, &usize, zdata, zsize)))
+	{
+		if (Z_MEM_ERROR != zerr && Z_BUF_ERROR != zerr)
+		{
+			free(udata);
+			return XSF_FALSE;
+		}
+		if (usize >= 8)
+		{
+			usize = getdwordle(udata + 4) + 8;
+			if (usize < rsize)
+			{
+				rsize += rsize;
+				usize = rsize;
+			}
+			else
+				rsize = usize;
+		}
+		else
+		{
+			rsize += rsize;
+			usize = rsize;
+		}
+		free(udata);
+		udata = malloc(usize);
+		if (!udata)
+			return XSF_FALSE;
+	}
+
+	rdata = realloc(udata, usize);
+	if (!rdata)
+	{
+		free(udata);
+		return XSF_FALSE;
+	}
+
+	if (0)
+	{
+		unsigned ccrc = crc32(crc32(0L, Z_NULL, 0), rdata, usize);
+		if (ccrc != zcrc)
+			return XSF_FALSE;
+	}
+
+	ret = load_map(issave, rdata, usize);
+	free(rdata);
+	return ret;
+}
+
+static int load_psf_one(unsigned char *pfile, unsigned bytes)
+{
+	unsigned char *ptr = pfile;
+	unsigned code_size;
+	unsigned resv_size;
+	unsigned code_crc;
+	if (bytes < 16 || getdwordle(ptr) != 0x24465350)
+		return XSF_FALSE;
+
+	resv_size = getdwordle(ptr + 4);
+	code_size = getdwordle(ptr + 8);
+	code_crc = getdwordle(ptr + 12);
+
+	if (resv_size)
+	{
+		unsigned resv_pos = 0;
+		ptr = pfile + 16;
+		if (16+ resv_size > bytes)
+			return XSF_FALSE;
+		while (resv_pos + 12 < resv_size)
+		{
+			unsigned save_size = getdwordle(ptr + resv_pos + 4);
+			unsigned save_crc = getdwordle(ptr + resv_pos + 8);
+			if (getdwordle(ptr + resv_pos + 0) == 0x45564153)
+			{
+				if (resv_pos + 12 + save_size > resv_size)
+					return XSF_FALSE;
+				if (!load_mapz(1, ptr + resv_pos + 12, save_size, save_crc))
+					return XSF_FALSE;
+			}
+			resv_pos += 12 + save_size;
+		}
+	}
+
+	if (code_size)
+	{
+		ptr = pfile + 16 + resv_size;
+		if (16 + resv_size + code_size > bytes)
+			return XSF_FALSE;
+		if (!load_mapz(0, ptr, code_size, code_crc))
+			return XSF_FALSE;
+	}
+
+	return XSF_TRUE;
+}
+
+typedef struct
+{
+	const char *tag;
+	int taglen;
+	int level;
+	int found;
+} loadlibwork_t;
+
+static int load_libs(int level, void *pfile, unsigned bytes);
+
+static int load_psfcb(void *pWork, const char *pNameTop, const char *pNameEnd, const char *pValueTop, const char *pValueEnd)
+{
+	loadlibwork_t *pwork = (loadlibwork_t *)pWork;
+	int ret = xsf_tagenum_callback_returnvaluecontinue;
+	if (pNameEnd - pNameTop == pwork->taglen && !strncasecmp(pNameTop, pwork->tag , pwork->taglen))
+	{
+		unsigned l = pValueEnd - pValueTop;
+		char *lib = malloc(l + 1);
+		if (!lib)
+		{
+			ret = xsf_tagenum_callback_returnvaluebreak;
+		}
+		else
+		{
+			void *libbuf;
+			unsigned libsize;
+			memcpy(lib, pValueTop, l);
+			lib[l] = '\0';
+			if (!xsf_get_lib(lib, &libbuf, &libsize))
+			{
+				ret = xsf_tagenum_callback_returnvaluebreak;
+			}
+			else
+			{
+				if (!load_libs(pwork->level + 1, libbuf, libsize) || !load_psf_one(libbuf, libsize))				
+					ret = xsf_tagenum_callback_returnvaluebreak;
+				else
+					pwork->found++;
+				free(libbuf);
+			}
+			free(lib);
+		}
+	}
+	return ret;
+}
+
+static int load_libs(int level, void *pfile, unsigned bytes)
+{
+	char tbuf[16];
+	loadlibwork_t work;
+	int n = 1;
+
+	if (level > 10)
+		return XSF_TRUE;
+
+	work.level = level;
+	work.tag = "_lib";
+
+	do
+	{
+		work.taglen = strlen(work.tag);
+		work.found = 0;
+
+		if (xsf_tagenum(load_psfcb, &work, pfile, bytes) < 0)
+			return XSF_FALSE;
+
+#ifdef HAVE_SPRINTF_S
+		sprintf_s(tbuf, sizeof(tbuf), "_lib%10d", ++n);
+#else
+		sprintf(tbuf, "_lib%10d", ++n);
+#endif
+		work.tag = tbuf;
+	}
+	while (work.found);
+
+	return XSF_TRUE;
+}
+
+static int load_psf(void *pfile, unsigned bytes)
+{
+	load_term();
+
+	if (!load_libs(1, pfile, bytes) || !load_psf_one(pfile, bytes))
+		return XSF_FALSE;
+
+	return XSF_TRUE;
+}
+
+static void load_getstateinit(unsigned ptr)
+{
+	loaderwork.stateptr = ptr;
+}
+
+static u16 getwordle(const unsigned char *pData)
+{
+	return pData[0] | (((u16)pData[1]) << 8);
+}
+
+static void load_getsta(Status_Reg *ptr, unsigned l)
+{
+	unsigned s = l << 2;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		{
+			u32 st = getdwordle(loaderwork.state + loaderwork.stateptr + (i << 2));
+			ptr[i].bits.N = (st >> 31) & 1;
+			ptr[i].bits.Z = (st >> 30) & 1;
+			ptr[i].bits.C = (st >> 29) & 1;
+			ptr[i].bits.V = (st >> 28) & 1;
+			ptr[i].bits.Q = (st >> 27) & 1;
+			ptr[i].bits.RAZ = (st >> 8) & ((1 << 19) - 1);
+			ptr[i].bits.I = (st >> 7) & 1;
+			ptr[i].bits.F = (st >> 6) & 1;
+			ptr[i].bits.T = (st >> 5) & 1;
+			ptr[i].bits.mode = (st >> 0) & 0x1f;
+		}
+	loaderwork.stateptr += s;
+}
+
+static void load_getbool(BOOL *ptr, unsigned l)
+{
+	unsigned s = l << 2;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		ptr[i] = (BOOL)getdwordle(loaderwork.state + loaderwork.stateptr + (i << 2));
+	loaderwork.stateptr += s;
+}
+
+#if defined(SIGNED_IS_NOT_2S_COMPLEMENT)
+/* 2's complement */
+#define u32tos32(v) ((s32)((((s64)(v)) ^ 0x8000) - 0x8000))
+#else
+/* 2's complement */
+#define u32tos32(v) ((s32)v)
+#endif
+
+static void load_gets32(s32 *ptr, unsigned l)
+{
+	unsigned s = l << 2;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		ptr[i] = u32tos32(getdwordle(loaderwork.state + loaderwork.stateptr + (i << 2)));
+	loaderwork.stateptr += s;
+}
+
+static void load_getu32(u32 *ptr, unsigned l)
+{
+	unsigned s = l << 2;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		ptr[i] = getdwordle(loaderwork.state + loaderwork.stateptr + (i << 2));
+	loaderwork.stateptr += s;
+}
+
+static void load_getu16(u16 *ptr, unsigned l)
+{
+	unsigned s = l << 1;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		ptr[i] = getwordle(loaderwork.state + loaderwork.stateptr + (i << 1));
+	loaderwork.stateptr += s;
+}
+
+static void load_getu8(u8 *ptr, unsigned l)
+{
+	unsigned s = l;
+	unsigned i;
+	if ((loaderwork.stateptr > loaderwork.statesize) || ((loaderwork.stateptr + s) > loaderwork.statesize))
+		return;
+	for (i = 0; i < l; i++)
+		ptr[i] = loaderwork.state[loaderwork.stateptr + i];
+	loaderwork.stateptr += s;
+}
+
+void gdb_stub_fix(armcpu_t *armcpu)
+{
+	/* armcpu->R[15] = armcpu->instruct_adr; */
+	armcpu->next_instruction = armcpu->instruct_adr;
+	if(armcpu->CPSR.bits.T == 0)
+	{
+		armcpu->instruction = MMU_read32_acl(armcpu->proc_ID, armcpu->next_instruction,CP15_ACCESS_EXECUTE);
+		armcpu->instruct_adr = armcpu->next_instruction;
+		armcpu->next_instruction += 4;
+		armcpu->R[15] = armcpu->next_instruction + 4;
+	}
+	else
+	{
+		armcpu->instruction = MMU_read16_acl(armcpu->proc_ID, armcpu->next_instruction,CP15_ACCESS_EXECUTE);
+		armcpu->instruct_adr = armcpu->next_instruction;
+		armcpu->next_instruction += 2;
+		armcpu->R[15] = armcpu->next_instruction + 2;
+	}
+}
+
+static void load_setstate(void)
+{
+	if (!loaderwork.statesize)
+		return;
+
+    /* Skip over "Desmume Save File" crap */
+	load_getstateinit(0x17);
+
+	/* Read ARM7 cpu registers */
+	load_getu32(&NDS_ARM7.proc_ID, 1);
+	load_getu32(&NDS_ARM7.instruction, 1);
+	load_getu32(&NDS_ARM7.instruct_adr, 1);
+	load_getu32(&NDS_ARM7.next_instruction, 1);
+	load_getu32(NDS_ARM7.R, 16);
+	load_getsta(&NDS_ARM7.CPSR, 1);
+	load_getsta(&NDS_ARM7.SPSR, 1);
+	load_getu32(&NDS_ARM7.R13_usr, 1);
+	load_getu32(&NDS_ARM7.R14_usr, 1);
+	load_getu32(&NDS_ARM7.R13_svc, 1);
+	load_getu32(&NDS_ARM7.R14_svc, 1);
+	load_getu32(&NDS_ARM7.R13_abt, 1);
+	load_getu32(&NDS_ARM7.R14_abt, 1);
+	load_getu32(&NDS_ARM7.R13_und, 1);
+	load_getu32(&NDS_ARM7.R14_und, 1);
+	load_getu32(&NDS_ARM7.R13_irq, 1);
+	load_getu32(&NDS_ARM7.R14_irq, 1);
+	load_getu32(&NDS_ARM7.R8_fiq, 1);
+	load_getu32(&NDS_ARM7.R9_fiq, 1);
+	load_getu32(&NDS_ARM7.R10_fiq, 1);
+	load_getu32(&NDS_ARM7.R11_fiq, 1);
+	load_getu32(&NDS_ARM7.R12_fiq, 1);
+	load_getu32(&NDS_ARM7.R13_fiq, 1);
+	load_getu32(&NDS_ARM7.R14_fiq, 1);
+	load_getsta(&NDS_ARM7.SPSR_svc, 1);
+	load_getsta(&NDS_ARM7.SPSR_abt, 1);
+	load_getsta(&NDS_ARM7.SPSR_und, 1);
+	load_getsta(&NDS_ARM7.SPSR_irq, 1);
+	load_getsta(&NDS_ARM7.SPSR_fiq, 1);
+	load_getu32(&NDS_ARM7.intVector, 1);
+	load_getu8(&NDS_ARM7.LDTBit, 1);
+	load_getbool(&NDS_ARM7.waitIRQ, 1);
+	load_getbool(&NDS_ARM7.wIRQ, 1);
+	load_getbool(&NDS_ARM7.wirq, 1);
+
+	/* Read ARM9 cpu registers */
+	load_getu32(&NDS_ARM9.proc_ID, 1);
+	load_getu32(&NDS_ARM9.instruction, 1);
+	load_getu32(&NDS_ARM9.instruct_adr, 1);
+	load_getu32(&NDS_ARM9.next_instruction, 1);
+	load_getu32(NDS_ARM9.R, 16);
+	load_getsta(&NDS_ARM9.CPSR, 1);
+	load_getsta(&NDS_ARM9.SPSR, 1);
+	load_getu32(&NDS_ARM9.R13_usr, 1);
+	load_getu32(&NDS_ARM9.R14_usr, 1);
+	load_getu32(&NDS_ARM9.R13_svc, 1);
+	load_getu32(&NDS_ARM9.R14_svc, 1);
+	load_getu32(&NDS_ARM9.R13_abt, 1);
+	load_getu32(&NDS_ARM9.R14_abt, 1);
+	load_getu32(&NDS_ARM9.R13_und, 1);
+	load_getu32(&NDS_ARM9.R14_und, 1);
+	load_getu32(&NDS_ARM9.R13_irq, 1);
+	load_getu32(&NDS_ARM9.R14_irq, 1);
+	load_getu32(&NDS_ARM9.R8_fiq, 1);
+	load_getu32(&NDS_ARM9.R9_fiq, 1);
+	load_getu32(&NDS_ARM9.R10_fiq, 1);
+	load_getu32(&NDS_ARM9.R11_fiq, 1);
+	load_getu32(&NDS_ARM9.R12_fiq, 1);
+	load_getu32(&NDS_ARM9.R13_fiq, 1);
+	load_getu32(&NDS_ARM9.R14_fiq, 1);
+	load_getsta(&NDS_ARM9.SPSR_svc, 1);
+	load_getsta(&NDS_ARM9.SPSR_abt, 1);
+	load_getsta(&NDS_ARM9.SPSR_und, 1);
+	load_getsta(&NDS_ARM9.SPSR_irq, 1);
+	load_getsta(&NDS_ARM9.SPSR_fiq, 1);
+	load_getu32(&NDS_ARM9.intVector, 1);
+	load_getu8(&NDS_ARM9.LDTBit, 1);
+	load_getbool(&NDS_ARM9.waitIRQ, 1);
+	load_getbool(&NDS_ARM9.wIRQ, 1);
+	load_getbool(&NDS_ARM9.wirq, 1);
+
+	/* Read in other internal variables that are important */
+	load_gets32(&nds.ARM9Cycle, 1);
+	load_gets32(&nds.ARM7Cycle, 1);
+	load_gets32(&nds.cycles, 1);
+	load_gets32(nds.timerCycle[0], 4);
+	load_gets32(nds.timerCycle[1], 4);
+	load_getbool(nds.timerOver[0], 4);
+	load_getbool(nds.timerOver[1], 4);
+	load_gets32(&nds.nextHBlank, 1);
+	load_getu32(&nds.VCount, 1);
+	load_getu32(&nds.old, 1);
+	load_gets32(&nds.diff, 1);
+	load_getbool(&nds.lignerendu, 1);
+	load_getu16(&nds.touchX, 1);
+	load_getu16(&nds.touchY, 1);
+
+	/* Read in memory/registers specific to the ARM9 */
+	load_getu8 (ARM9Mem.ARM9_ITCM, 0x8000);
+	load_getu8 (ARM9Mem.ARM9_DTCM, 0x4000);
+	load_getu8 (ARM9Mem.ARM9_WRAM, 0x1000000);
+	load_getu8 (ARM9Mem.MAIN_MEM, 0x400000);
+	load_getu8 (ARM9Mem.ARM9_REG, 0x10000);
+	load_getu8 (ARM9Mem.ARM9_VMEM, 0x800);
+	load_getu8 (ARM9Mem.ARM9_OAM, 0x800);    
+	load_getu8 (ARM9Mem.ARM9_ABG, 0x80000);
+	load_getu8 (ARM9Mem.ARM9_BBG, 0x20000);
+	load_getu8 (ARM9Mem.ARM9_AOBJ, 0x40000);
+	load_getu8 (ARM9Mem.ARM9_BOBJ, 0x20000);
+	load_getu8 (ARM9Mem.ARM9_LCD, 0xA4000);
+
+	/* Read in memory/registers specific to the ARM7 */
+	load_getu8 (MMU.ARM7_ERAM, 0x10000);
+	load_getu8 (MMU.ARM7_REG, 0x10000);
+	load_getu8 (MMU.ARM7_WIRAM, 0x10000);
+
+	/* Read in shared memory */
+	load_getu8 (MMU.SWIRAM, 0x8000);
+
+#ifdef GDB_STUB
+#else
+	gdb_stub_fix(&NDS_ARM9);
+	gdb_stub_fix(&NDS_ARM7);
+#endif
+}
+
+static struct
+{
+	unsigned char *pcmbufalloc;
+	unsigned char *pcmbuftop;
+	unsigned filled;
+	unsigned used;
+	u32 bufferbytes;
+	u32 cycles;
+	int xfs_load;
+	int sync_type;
+	int arm7_clockdown_level;
+	int arm9_clockdown_level;
+} sndifwork = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static void SNDIFDeInit(void)
+{
+	if (sndifwork.pcmbufalloc)
+	{
+		free(sndifwork.pcmbufalloc);
+		sndifwork.pcmbufalloc = 0;
+		sndifwork.pcmbuftop = 0;
+		sndifwork.bufferbytes = 0;
+	}
+}
+static int SNDIFInit(int buffersize)
+{
+	u32 bufferbytes = buffersize * sizeof(s16);
+	SNDIFDeInit();
+	sndifwork.pcmbufalloc = malloc(bufferbytes + 3);
+	if (!sndifwork.pcmbufalloc)
+		return -1;
+	sndifwork.pcmbuftop = sndifwork.pcmbufalloc + ((4 - (((int)sndifwork.pcmbufalloc) & 3)) & 3);
+	sndifwork.bufferbytes = bufferbytes;
+	sndifwork.filled = 0;
+	sndifwork.used = 0;
+	sndifwork.cycles = 0;
+	return 0;
+}
+static void SNDIFMuteAudio(void)
+{
+}
+static void SNDIFUnMuteAudio(void)
+{
+}
+static void SNDIFSetVolume(int volume)
+{
+}
+static int SNDIFGetAudioSpace(void)
+{
+	return sndifwork.bufferbytes >> 2; // bytes to samples
+}
+static void SNDIFUpdateAudio(s16 * buffer, u32 num_samples)
+{
+	u32 num_bytes = num_samples << 2;
+	if (num_bytes > sndifwork.bufferbytes) num_bytes = sndifwork.bufferbytes;
+	memcpy(sndifwork.pcmbuftop, buffer, num_bytes);
+	sndifwork.filled = num_bytes;
+	sndifwork.used = 0;
+}
+#define VIO2SFSNDIFID 2
+static SoundInterface_struct VIO2SFSNDIF =
+{
+	VIO2SFSNDIFID,
+	"vio2sf Sound Interface",
+	SNDIFInit,
+	SNDIFDeInit,
+	SNDIFUpdateAudio,
+	SNDIFGetAudioSpace,
+	SNDIFMuteAudio,
+	SNDIFUnMuteAudio,
+	SNDIFSetVolume
+};
+
+SoundInterface_struct *SNDCoreList[] = {
+	&VIO2SFSNDIF,
+	&SNDDummy,
+	NULL
+};
+
+static struct armcpu_ctrl_iface *arm9_ctrl_iface = 0;
+static struct armcpu_ctrl_iface *arm7_ctrl_iface = 0;
+
+int xsf_start(void *pfile, unsigned bytes)
+{
+	int frames = xsf_tagget_int("_frames", pfile, bytes, -1);
+	int clockdown = xsf_tagget_int("_clockdown", pfile, bytes, 0);
+	sndifwork.sync_type = xsf_tagget_int("_vio2sf_sync_type", pfile, bytes, 0);
+	sndifwork.arm9_clockdown_level = xsf_tagget_int("_vio2sf_arm9_clockdown_level", pfile, bytes, clockdown);
+	sndifwork.arm7_clockdown_level = xsf_tagget_int("_vio2sf_arm7_clockdown_level", pfile, bytes, clockdown);
+	
+	sndifwork.xfs_load = 0;
+	if (!load_psf(pfile, bytes))
+		return XSF_FALSE;
+
+#ifdef GDB_STUB
+	if (NDS_Init(&arm9_base_memory_iface, &arm9_ctrl_iface, &arm7_base_memory_iface, &arm7_ctrl_iface))
+#else
+	if (NDS_Init())
+#endif
+		return XSF_FALSE;
+
+	SPU_ChangeSoundCore(VIO2SFSNDIFID, 737);
+
+	execute = FALSE;
+
+	MMU_unsetRom();
+	if (loaderwork.rom)
+	{
+		NDS_SetROM(loaderwork.rom, loaderwork.romsize - 1);
+	}
+
+	NDS_Reset();
+
+	execute = TRUE;
+
+	if (loaderwork.state)
+	{
+		armcp15_t *c9 = (armcp15_t *)NDS_ARM9.coproc[15];
+		int proc;
+		if (frames == -1)
+		{
+
+			/* set initial ARM9 coprocessor state */
+
+			armcp15_moveARM2CP(c9, 0x00000000, 0x01, 0x00, 0, 0);
+			armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x05, 0, 0);
+			armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x06, 0, 0);
+			armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x0a, 0, 4);
+			armcp15_moveARM2CP(c9, 0x04000033, 0x06, 0x00, 0, 4);
+			armcp15_moveARM2CP(c9, 0x0200002d, 0x06, 0x01, 0, 0);
+			armcp15_moveARM2CP(c9, 0x027e0021, 0x06, 0x02, 0, 0);
+			armcp15_moveARM2CP(c9, 0x08000035, 0x06, 0x03, 0, 0);
+			armcp15_moveARM2CP(c9, 0x027e001b, 0x06, 0x04, 0, 0);
+			armcp15_moveARM2CP(c9, 0x0100002f, 0x06, 0x05, 0, 0);
+			armcp15_moveARM2CP(c9, 0xffff001d, 0x06, 0x06, 0, 0);
+			armcp15_moveARM2CP(c9, 0x027ff017, 0x06, 0x07, 0, 0);
+			armcp15_moveARM2CP(c9, 0x00000020, 0x09, 0x01, 0, 1);
+
+			armcp15_moveARM2CP(c9, 0x027e000a, 0x09, 0x01, 0, 0);
+
+			armcp15_moveARM2CP(c9, 0x00000042, 0x02, 0x00, 0, 1);
+			armcp15_moveARM2CP(c9, 0x00000042, 0x02, 0x00, 0, 0);
+			armcp15_moveARM2CP(c9, 0x00000002, 0x03, 0x00, 0, 0);
+			armcp15_moveARM2CP(c9, 0x05100011, 0x05, 0x00, 0, 3);
+			armcp15_moveARM2CP(c9, 0x15111011, 0x05, 0x00, 0, 2);
+			armcp15_moveARM2CP(c9, 0x07dd1e10, 0x01, 0x00, 0, 0);
+			armcp15_moveARM2CP(c9, 0x0005707d, 0x01, 0x00, 0, 0);
+
+			armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x0a, 0, 4);
+			armcp15_moveARM2CP(c9, 0x02004000, 0x07, 0x05, 0, 1);
+			armcp15_moveARM2CP(c9, 0x02004000, 0x07, 0x0e, 0, 1);
+
+			/* set initial timer state */
+
+			MMU_write16(0, REG_TM0CNTL, 0x0000);
+			MMU_write16(0, REG_TM0CNTH, 0x00C1);
+			MMU_write16(1, REG_TM0CNTL, 0x0000);
+			MMU_write16(1, REG_TM0CNTH, 0x00C1);
+			MMU_write16(1, REG_TM1CNTL, 0xf7e7);
+			MMU_write16(1, REG_TM1CNTH, 0x00C1);
+
+			/* set initial interrupt state */
+
+			MMU.reg_IME[0] = 0x00000001;
+			MMU.reg_IE[0]  = 0x00042001;
+			MMU.reg_IME[1] = 0x00000001;
+			MMU.reg_IE[1]  = 0x0104009d;
+		}
+		else if (frames > 0)
+		{
+			/* execute boot code */
+			int i;
+			for (i=0; i<frames; i++)
+				NDS_exec_frame(0, 0);
+			i = 0;
+		}
+
+		/* load state */
+
+		load_setstate();
+		free(loaderwork.state);
+		loaderwork.state = 0;
+
+		if (frames == -1)
+		{
+			armcp15_moveARM2CP(c9, (NDS_ARM9.R13_irq & 0x0fff0000) | 0x0a, 0x09, 0x01, 0, 0);
+		}
+
+		/* restore timer state */
+
+		for (proc = 0; proc < 2; proc++)
+		{
+			MMU_write16(proc, REG_TM0CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM0CNTH & 0xFFF));
+			MMU_write16(proc, REG_TM1CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM1CNTH & 0xFFF));
+			MMU_write16(proc, REG_TM2CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM2CNTH & 0xFFF));
+			MMU_write16(proc, REG_TM3CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM3CNTH & 0xFFF));
+		}
+	}
+	else if (frames > 0)
+	{
+		/* skip 1 sec */
+		int i;
+		for (i=0; i<frames; i++)
+			NDS_exec_frame(0, 0);
+	}
+	execute = TRUE;
+	sndifwork.xfs_load = 1;
+	return XSF_TRUE;
+}
+
+int xsf_gen(void *pbuffer, unsigned samples)
+{
+	unsigned char *ptr = pbuffer;
+	unsigned bytes = samples <<= 2;
+	if (!sndifwork.xfs_load) return 0;
+	while (bytes)
+	{
+		unsigned remainbytes = sndifwork.filled - sndifwork.used;
+		if (remainbytes > 0)
+		{
+			if (remainbytes > bytes)
+			{
+				memcpy(ptr, sndifwork.pcmbuftop + sndifwork.used, bytes);
+				sndifwork.used += bytes;
+				ptr += bytes;
+				remainbytes -= bytes; /**/
+				bytes = 0;  /**/
+				break;
+			}
+			else
+			{
+				memcpy(ptr, sndifwork.pcmbuftop + sndifwork.used, remainbytes);
+				sndifwork.used += remainbytes;
+				ptr += remainbytes;
+				bytes -= remainbytes;
+				remainbytes = 0;
+			}
+		}
+		if (remainbytes == 0)
+		{
+
+#define HBASE_CYCLES 33509300.322234
+#define VBASE_CYCLES (((double)HBASE_CYCLES) / 100)
+#define HSAMPLES ((u32)((44100.0 * 6 * (99 + 256)) / HBASE_CYCLES))
+#define VSAMPLES ((u32)((44100.0 * 6 * (99 + 256) * 263) / HBASE_CYCLES))
+
+			int numsamples;
+			if (sndifwork.sync_type == 1)
+			{
+				/* vsync */
+				sndifwork.cycles += (441 * 6 * (99 + 256) * 263);
+				if (sndifwork.cycles >= (u32)(VBASE_CYCLES * (VSAMPLES + 1)))
+				{
+					numsamples = (VSAMPLES + 1);
+					sndifwork.cycles -= (u32)(VBASE_CYCLES * (VSAMPLES + 1));
+				}
+				else
+				{
+					numsamples = (VSAMPLES + 0);
+					sndifwork.cycles -= (u32)(VBASE_CYCLES * (VSAMPLES + 0));
+				}
+				NDS_exec_frame(sndifwork.arm9_clockdown_level, sndifwork.arm7_clockdown_level);
+			}
+			else
+			{
+				/* hsync */
+				sndifwork.cycles += (44100 * 6 * (99 + 256));
+				if (sndifwork.cycles >= (u32)(HBASE_CYCLES * (HSAMPLES + 1)))
+				{
+					numsamples = (HSAMPLES + 1);
+					sndifwork.cycles -= (u32)(HBASE_CYCLES * (HSAMPLES + 1));
+				}
+				else
+				{
+					numsamples = (HSAMPLES + 0);
+					sndifwork.cycles -= (u32)(HBASE_CYCLES * (HSAMPLES + 0));
+				}
+				NDS_exec_hframe(sndifwork.arm9_clockdown_level, sndifwork.arm7_clockdown_level);
+			}
+			SPU_EmulateSamples(numsamples);
+		}
+	}
+	return ptr - (unsigned char *)pbuffer;
+}
+
+void xsf_term(void)
+{
+	MMU_unsetRom();
+	NDS_DeInit();
+	load_term();
+}