#include <fcntl.h>\r
#include <errno.h>\r
\r
-#include "940shared.h"\r
+#include "code940/940shared.h"\r
#include "gp2x.h"\r
#include "emu.h"\r
#include "menu.h"\r
printf("wait iterations: %i\n", i);\r
#else\r
for (i = 0; shared_ctl->busy && i < 0x10000; i++)\r
- spend_cycles(4*1024);\r
+ spend_cycles(8*1024); // tested to be best for mp3 dec\r
if (i < 0x10000) return;\r
\r
/* 940 crashed */\r
- printf("940 crashed (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc);\r
+ printf("940 crashed (cnt: %i, ve: ", shared_ctl->loopc);\r
for (i = 0; i < 8; i++)\r
printf("%i ", shared_ctl->vstarts[i]);\r
printf(")\n");\r
/* now cause 940 to init it's ym2612 stuff */\r
shared_ctl->baseclock = baseclock;\r
shared_ctl->rate = rate;\r
- shared_ctl->jobs[0] = JOB940_YM2612INIT;\r
+ shared_ctl->jobs[0] = JOB940_INITALL;\r
shared_ctl->jobs[1] = 0;\r
shared_ctl->busy = 1;\r
\r
\r
# you may or may not need to change this\r
#devkit_path = x:/stuff/dev/devkitgp2x/\r
-devkit_path = /usr/local/devkitPro/devkitGP2X/\r
-lgcc_path = $(devkit_path)lib/gcc/arm-linux/4.0.3/\r
CROSS = arm-linux-\r
#CROSS = $(devkit_path)bin/arm-linux-\r
\r
#use_musashi = 1\r
#up = 1\r
\r
-DEFINC = -I../.. -I. -D__GP2X__ -D_UNZIP_SUPPORT # -DBENCHMARK\r
+DEFINC = -I../.. -I. -DARM -D__GP2X__ -D_UNZIP_SUPPORT # -DBENCHMARK\r
COPT_COMMON = -static -s -O3 -ftracer -fstrength-reduce -Wall -funroll-loops -fomit-frame-pointer -fstrict-aliasing -ffast-math\r
ifeq "$(profile)" "1"\r
COPT_COMMON += -fprofile-generate\r
OBJS += ../../cpu/DrZ80/drz80.o\r
endif\r
\r
-all: PicoDrive.gpe code940.bin\r
+all: PicoDrive.gpe\r
\r
PicoDrive.gpe : $(OBJS)\r
@echo $@\r
@cmd //C copy $@ \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
endif\r
\r
-up: # up940\r
+up:\r
@cp -v PicoDrive.gpe /mnt/gp2x/mnt/sd/games/PicoDrive/\r
\r
# @cmd //C copy PicoDrive.gpe \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
\r
-up940:\r
- @cp -v code940.bin /mnt/gp2x/mnt/sd/games/PicoDrive/\r
-\r
-# @cmd //C copy code940.bin \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
\r
testrefr.gpe : test.o gp2x.o asmutils.o\r
@echo $@\r
@make -C ../../cpu/Cyclone/proj -f Makefile.linux\r
\r
\r
-# stuff for 940 core\r
-\r
-# init, emu_control, emu\r
-OBJS940 += 940init.o 940.o 940ym2612.o\r
-# the asm code seems to be faster when run on 920, but not on 940 for some reason\r
-# OBJS940 += ../../Pico/sound/ym2612_asm.o\r
-\r
-# uClibc library code\r
-OBJS940 += uClibc/memset.o uClibc/s_floor.o uClibc/e_pow.o uClibc/e_sqrt.o uClibc/s_fabs.o\r
-OBJS940 += uClibc/s_scalbn.o uClibc/s_copysign.o uClibc/k_sin.o uClibc/k_cos.o uClibc/s_sin.o\r
-OBJS940 += uClibc/e_rem_pio2.o uClibc/k_rem_pio2.o uClibc/e_log.o uClibc/wrappers.o\r
-\r
-code940.bin : code940.gpe\r
- @echo $@\r
- @$(OBJCOPY) -O binary $< $@\r
-\r
-code940.gpe : $(OBJS940)\r
- @echo $@\r
- @$(LD) -static -e code940 -Ttext 0x0 $^ -L$(lgcc_path) -lgcc -o $@\r
-\r
-940ym2612.o : ../../Pico/sound/ym2612.c\r
- @echo $@\r
- @$(GCC) $(COPT_COMMON) -mtune=arm940t $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@\r
-\r
-\r
# cleanup\r
-clean: clean_pd clean_940\r
-tidy: tidy_pd tidy_940\r
-\r
-clean_pd: tidy_pd\r
+clean: tidy\r
@$(RM) PicoDrive.gpe\r
-tidy_pd:\r
+tidy:\r
@$(RM) $(OBJS)\r
# @make -C ../../cpu/Cyclone/proj -f Makefile.linux clean\r
\r
-clean_940: tidy_940\r
- @$(RM) code940.bin\r
-tidy_940:\r
- @$(RM) code940.gpe $(OBJS940)\r
\r
clean_prof:\r
find ../.. -name '*.gcno' -delete\r
@echo $<\r
@$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@\r
\r
-uClibc/e_pow.o : uClibc/e_pow.c\r
- @echo $<\r
- @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@\r
-\r
-uClibc/e_sqrt.o : uClibc/e_sqrt.c\r
- @echo $<\r
- @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@\r
#include "940shared.h"\r
\r
-static _940_data_t *shared_data = (_940_data_t *) 0x100000;\r
-static _940_ctl_t *shared_ctl = (_940_ctl_t *) 0x200000;\r
+static _940_data_t *shared_data = (_940_data_t *) 0x00100000;\r
+static _940_ctl_t *shared_ctl = (_940_ctl_t *) 0x00200000;\r
+static unsigned char *mp3_data = (unsigned char *) 0x01000000;\r
YM2612 *ym2612_940;\r
int *mix_buffer;\r
\r
\r
// debug\r
shared_ctl->vstarts[startvector]++;\r
- asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0");\r
+ // asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0");\r
\r
\r
- for (;; shared_ctl->loopc++)\r
+ for (;;)\r
{\r
- int job_num;\r
+ int job_num = 0;\r
/*\r
while (!shared_ctl->busy)\r
{\r
//shared_ctl->waitc++;\r
- spend_cycles(256);\r
+ spend_cycles(8*1024);\r
}\r
*/\r
if (!shared_ctl->busy)\r
{\r
switch (shared_ctl->jobs[job_num])\r
{\r
- case JOB940_YM2612INIT:\r
+ case JOB940_INITALL:\r
+ /* ym2612 */\r
shared_ctl->writebuff0[0] = shared_ctl->writebuff1[0] = 0xffff;\r
YM2612Init_(shared_ctl->baseclock, shared_ctl->rate);\r
+ /* Helix mp3 decoder */\r
+ shared_data->mp3dec = MP3InitDecoder();\r
break;\r
\r
case JOB940_YM2612RESETCHIP:\r
YM2612UpdateOne_(0, shared_ctl->length, shared_ctl->stereo);\r
break;\r
}\r
+\r
+ case JOB940_MP3DECODE: {\r
+ int mp3_offs = shared_ctl->mp3_offs;\r
+ unsigned char *readPtr = mp3_data + mp3_offs;\r
+ int bytesLeft = shared_ctl->mp3_len - mp3_offs;\r
+ int offset; // frame offset from readPtr\r
+ int err;\r
+\r
+ if (bytesLeft <= 0) break; // EOF, nothing to do\r
+\r
+ offset = MP3FindSyncWord(readPtr, bytesLeft);\r
+ if (offset < 0) {\r
+ shared_ctl->mp3_offs = shared_ctl->mp3_len;\r
+ break; // EOF\r
+ }\r
+ readPtr += offset;\r
+ bytesLeft -= offset;\r
+\r
+ err = MP3Decode(shared_data->mp3dec, &readPtr, &bytesLeft,\r
+ shared_data->mp3_buffer[shared_ctl->mp3_buffsel], 0);\r
+ if (err) {\r
+ if (err == ERR_MP3_INDATA_UNDERFLOW) {\r
+ shared_ctl->mp3_offs = shared_ctl->mp3_len; // EOF\r
+ break;\r
+ } else if (err <= -6 && err >= -12) {\r
+ // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*\r
+ // just try to skip the offending frame..\r
+ readPtr++;\r
+ }\r
+ shared_ctl->mp3_errors++;\r
+ shared_ctl->mp3_lasterr = err;\r
+ }\r
+ shared_ctl->mp3_offs = readPtr - mp3_data;\r
+ break;\r
+ }\r
}\r
}\r
\r
- shared_ctl->busy = 0;\r
-// cache_clean_flush();\r
cache_clean();\r
// asm volatile ("mov r0, #0" ::: "r0");\r
// asm volatile ("mcr p15, 0, r0, c7, c10, 4" ::: "r0"); /* drain write buffer, should be done on nonbuffered write */\r
+// cache_clean_flush();\r
+\r
+ shared_ctl->loopc++;\r
+ shared_ctl->busy = 0;\r
}\r
}\r
\r
mcr p15, 0, r0, c6, c3, 0\r
mcr p15, 0, r0, c6, c3, 1\r
\r
- @ set region 1 to be cacheable (so the first 2M will be cacheable)\r
- mov r0, #2\r
+ @ set up region 4: 16M 0x01000000-0x02000000 (mp3 area)\r
+ mov r0, #(0x17<<1)|1\r
+ orr r0, r0, #0x01000000\r
+ mcr p15, 0, r0, c6, c4, 0\r
+ mcr p15, 0, r0, c6, c4, 1\r
+\r
+ @ set regions 1 and 4 to be cacheable (so the first 2M and mp3 area will be cacheable)\r
+ mov r0, #(1<<1)|(1<<4)\r
mcr p15, 0, r0, c2, c0, 0\r
mcr p15, 0, r0, c2, c0, 1\r
\r
@ set region 1 to be bufferable too (only data)\r
+ mov r0, #(1<<1)\r
mcr p15, 0, r0, c3, c0, 0\r
\r
@ set protection, allow accsess only to regions 1 and 2\r
- mov r0, #(3<<6)|(3<<4)|(3<<2)|(0) @ data: [full, full, full, no access] for regions [3 2 1 0]\r
+ mov r0, #(3<<8)|(3<<6)|(3<<4)|(3<<2)|(0) @ data: [full, full, full, full, no access] for regions [4 3 2 1 0]\r
mcr p15, 0, r0, c5, c0, 0\r
- mov r0, #(0<<6)|(0<<4)|(3<<2)|(0) @ instructions: [no access, no, full, no]\r
+ mov r0, #(0<<8)|(0<<6)|(0<<4)|(3<<2)|(0) @ instructions: [no access, no, no, full, no]\r
mcr p15, 0, r0, c5, c0, 1\r
\r
mrc p15, 0, r0, c1, c0, 0 @ fetch current control reg\r
orr r0, r0, #1 @ 0x00000001: enable protection unit\r
orr r0, r0, #4 @ 0x00000004: enable D cache\r
orr r0, r0, #0x1000 @ 0x00001000: enable I cache\r
- orr r0, r0, #0xC0000000 @ 0xC0000000: async+fastbus\r
+ bic r0, r0, #0xC0000000\r
+ orr r0, r0, #0x40000000 @ 0x40000000: synchronous, faster?\r
+@ orr r0, r0, #0xC0000000 @ 0xC0000000: async\r
mcr p15, 0, r0, c1, c0, 0 @ set control reg\r
\r
@ flush (invalidate) the cache (just in case)\r
\r
.pool\r
\r
-@ vim:filetype=ignored:\r
+@ vim:filetype=armasm:\r
-#include "../../Pico/sound/ym2612.h"\r
+#include "../../../Pico/sound/ym2612.h"\r
+#include "../helix/pub/mp3dec.h"\r
\r
enum _940_job_t {\r
- JOB940_YM2612INIT = 1,\r
+ JOB940_INITALL = 1,\r
JOB940_YM2612RESETCHIP,\r
JOB940_YM2612UPDATEONE,\r
JOB940_PICOSTATELOAD,\r
+ JOB940_MP3DECODE,\r
JOB940_NUMJOBS\r
};\r
\r
\r
typedef struct\r
{\r
- YM2612 ym2612; /* current state of the emulated YM2612 */\r
- int mix_buffer[44100/50*2]; /* this is where the YM2612 samples will be mixed to */\r
- short mp3_buffer[2][1152*2]; /* buffer for mp3 decoder's output */\r
+ YM2612 ym2612; /* current state of the emulated YM2612 */\r
+ HMP3Decoder mp3dec; /* mp3 decoder's handle */\r
+ int mix_buffer[44100/50*2]; /* this is where the YM2612 samples will be mixed to */\r
+ short mp3_buffer[2][1152*2]; /* buffers for mp3 decoder's output */\r
} _940_data_t;\r
\r
\r
int writebuffsel; /* which write buffer to use (from 940 side) */\r
UINT16 writebuff0[2048]; /* list of writes to ym2612, 1024 for savestates, 1024 extra */\r
UINT16 writebuff1[2048];\r
+ int mp3_len; /* data len of loaded mp3 */\r
+ int mp3_offs; /* current playback offset (just after last decoded frame) */\r
+ int mp3_buffsel; /* which output buffer to decode to */\r
int vstarts[8]; /* debug: number of starts from each of 8 vectors */\r
int loopc; /* debug: main loop counter */\r
- int waitc; /* debug: wait loop counter */\r
+ int mp3_errors; /* debug: mp3 decoder's error counter */\r
+ int mp3_lasterr; /* debug: mp3 decoder's last error */\r
} _940_ctl_t;\r
--- /dev/null
+\r
+# you may or may not need to change this\r
+#devkit_path = x:/stuff/dev/devkitgp2x/\r
+devkit_path = /usr/local/devkitPro/devkitGP2X/\r
+lgcc_path = $(devkit_path)lib/gcc/arm-linux/4.0.3/\r
+CROSS = arm-linux-\r
+#CROSS = $(devkit_path)bin/arm-linux-\r
+\r
+# settings\r
+#up = 1\r
+\r
+DEFINC = -I../.. -I. -D__GP2X__ -DARM # -DBENCHMARK\r
+COPT_COMMON = -static -s -O3 -ftracer -fstrength-reduce -Wall -funroll-loops -fomit-frame-pointer -fstrict-aliasing -ffast-math\r
+COPT = $(COPT_COMMON) -mtune=arm920t\r
+GCC = $(CROSS)gcc\r
+STRIP = $(CROSS)strip\r
+AS = $(CROSS)as\r
+LD = $(CROSS)ld\r
+OBJCOPY = $(CROSS)objcopy\r
+\r
+all: code940.bin\r
+\r
+up940:\r
+ @cp -v code940.bin /mnt/gp2x/mnt/sd/games/PicoDrive/\r
+\r
+# @cmd //C copy code940.bin \\\\10.0.1.2\\gp2x\\mnt\\sd\\games\\PicoDrive\\\r
+\r
+.c.o:\r
+ @echo $<\r
+ $(GCC) $(COPT) $(DEFINC) -c $< -o $@\r
+.s.o:\r
+ @echo $<\r
+ $(GCC) $(COPT) $(DEFINC) -c $< -o $@\r
+\r
+\r
+# stuff for 940 core\r
+\r
+# init, emu_control, emu\r
+OBJS940 += 940init.o 940.o 940ym2612.o memcpy.o\r
+# the asm code seems to be faster when run on 920, but not on 940 for some reason\r
+# OBJS940 += ../../Pico/sound/ym2612_asm.o\r
+\r
+# uClibc library code\r
+OBJS940 += uClibc/memset.o uClibc/s_floor.o uClibc/e_pow.o uClibc/e_sqrt.o uClibc/s_fabs.o\r
+OBJS940 += uClibc/s_scalbn.o uClibc/s_copysign.o uClibc/k_sin.o uClibc/k_cos.o uClibc/s_sin.o\r
+OBJS940 += uClibc/e_rem_pio2.o uClibc/k_rem_pio2.o uClibc/e_log.o uClibc/wrappers.o\r
+\r
+code940.bin : code940.gpe\r
+ @echo $@\r
+ @$(OBJCOPY) -O binary $< $@\r
+\r
+code940.gpe : $(OBJS940) ../helix/helix_mp3.a\r
+ @echo $@\r
+ @$(LD) -static -e code940 -Ttext 0x0 $^ -L$(lgcc_path) -lgcc -o $@\r
+\r
+940ym2612.o : ../../../Pico/sound/ym2612.c\r
+ @echo $@\r
+ @$(GCC) $(COPT_COMMON) -mtune=arm940t $(DEFINC) -DEXTERNAL_YM2612 -c $< -o $@\r
+\r
+../helix/helix_mp3.a:\r
+ @make -C ../helix/\r
+\r
+\r
+# cleanup\r
+clean: tidy\r
+ @$(RM) code940.bin\r
+tidy:\r
+ @$(RM) code940.gpe $(OBJS940)\r
+\r
+\r
+OBJSMP3T = mp3test.o ../gp2x.o ../asmutils.o ../usbjoy.o\r
+\r
+mp3test.gpe : $(OBJSMP3T) ../helix/helix_mp3.a\r
+ $(GCC) -static -o $@ $^\r
+ $(STRIP) $@\r
+ @cp -v $@ /mnt/gp2x/mnt/sd\r
+\r
+cleanmp3test:\r
+ $(RM) $(OBJSMP3T) mp3test.gpe\r
+\r
+# uClibc/e_pow.o : uClibc/e_pow.c\r
+# @echo $<\r
+# @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@\r
+\r
+# uClibc/e_sqrt.o : uClibc/e_sqrt.c\r
+# @echo $<\r
+# @$(GCC) $(COPT) $(DEFINC) -fno-profile-generate -c $< -o $@\r
--- /dev/null
+/* $NetBSD: memcpy.S,v 1.3 1997/11/22 03:27:12 mark Exp $ */
+
+/*-
+* Copyright (c) 1997 The NetBSD Foundation, Inc.
+* All rights reserved.
+*
+* This code is derived from software contributed to The NetBSD Foundation
+* by Neil A. Carson and Mark Brinicombe
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. All advertising materials mentioning features or use of this software
+* must display the following acknowledgement:
+* This product includes software developed by the NetBSD
+* Foundation, Inc. and its contributors.
+* 4. Neither the name of The NetBSD Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+* ``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This was modified by Jay Monkman <jmonkman@smoothsmoothie.com> to
+* save and restore r12. This is necessary for RTEMS.
+*/
+/* #include <machine/asm.h>*/
+
+#define ENTRY(_LABEL) \
+ .global _LABEL; _LABEL:
+
+.globl memcpy
+memcpy:
+
+@ ENTRY(gp2x_memcpy)
+stmfd sp!, {r0, r12, lr}
+@ bl _gp2x_memcpy
+bl _memcpy
+ldmfd sp!, {r0, r12, pc}
+
+
+
+.globl memmove
+memmove:
+
+@ ENTRY(gp2x_memmove)
+stmfd sp!, {r0, r12, lr}
+@ bl _gp2x_memcpy
+bl _memcpy
+ldmfd sp!, {r0, r12, pc}
+
+
+
+/*
+* This is one fun bit of code ...
+* Some easy listening music is suggested while trying to understand this
+* code e.g. Iron Maiden
+*
+* For anyone attempting to understand it :
+*
+* The core code is implemented here with simple stubs for memcpy()
+* memmove() and bcopy().
+*
+* All local labels are prefixed with Lmemcpy_
+* Following the prefix a label starting f is used in the forward copy code
+* while a label using b is used in the backwards copy code
+* The source and destination addresses determine whether a forward or
+* backward copy is performed.
+* Separate bits of code are used to deal with the following situations
+* for both the forward and backwards copy.
+* unaligned source address
+* unaligned destination address
+* Separate copy routines are used to produce an optimised result for each
+* of these cases.
+* The copy code will use LDM/STM instructions to copy up to 32 bytes at
+* a time where possible.
+*
+* Note: r12 (aka ip) can be trashed during the function along with
+* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
+* Additional registers are preserved prior to use i.e. r4, r5 & lr
+*
+* Apologies for the state of the comments;-)
+*/
+
+
+
+_memcpy:
+
+@ ENTRY(_gp2x_memcpy)
+/* Determine copy direction */
+cmp r1, r0
+bcc Lmemcpy_backwards
+
+moveq r0, #0 /* Quick abort for len=0 */
+moveq pc, lr
+
+stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
+subs r2, r2, #4
+blt Lmemcpy_fl4 /* less than 4 bytes */
+ands r12, r0, #3
+bne Lmemcpy_fdestul /* oh unaligned destination addr */
+ands r12, r1, #3
+bne Lmemcpy_fsrcul /* oh unaligned source addr */
+
+Lmemcpy_ft8:
+/* We have aligned source and destination */
+subs r2, r2, #8
+blt Lmemcpy_fl12 /* less than 12 bytes (4 from above) */
+subs r2, r2, #0x14
+blt Lmemcpy_fl32 /* less than 32 bytes (12 from above) */
+stmdb sp!, {r4, r7, r8, r9, r10} /* borrow r4 */
+
+/* blat 64 bytes at a time */
+/* XXX for really big copies perhaps we should use more registers */
+Lmemcpy_floop32:
+ldmia r1!, {r3, r4, r7, r8, r9, r10, r12, lr}
+stmia r0!, {r3, r4, r7, r8, r9, r10, r12, lr}
+ldmia r1!, {r3, r4, r7, r8, r9, r10, r12, lr}
+stmia r0!, {r3, r4, r7, r8, r9, r10, r12, lr}
+subs r2, r2, #0x40
+bge Lmemcpy_floop32
+
+cmn r2, #0x10
+ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+stmgeia r0!, {r3, r4, r12, lr}
+subge r2, r2, #0x10
+ldmia sp!, {r4, r7, r8, r9, r10} /* return r4 */
+
+Lmemcpy_fl32:
+adds r2, r2, #0x14
+
+/* blat 12 bytes at a time */
+Lmemcpy_floop12:
+ldmgeia r1!, {r3, r12, lr}
+stmgeia r0!, {r3, r12, lr}
+subges r2, r2, #0x0c
+bge Lmemcpy_floop12
+
+Lmemcpy_fl12:
+adds r2, r2, #8
+blt Lmemcpy_fl4
+
+subs r2, r2, #4
+ldrlt r3, [r1], #4
+strlt r3, [r0], #4
+ldmgeia r1!, {r3, r12}
+stmgeia r0!, {r3, r12}
+subge r2, r2, #4
+
+Lmemcpy_fl4:
+/* less than 4 bytes to go */
+adds r2, r2, #4
+ldmeqia sp!, {r0, pc} /* done */
+
+/* copy the crud byte at a time */
+cmp r2, #2
+ldrb r3, [r1], #1
+strb r3, [r0], #1
+ldrgeb r3, [r1], #1
+strgeb r3, [r0], #1
+ldrgtb r3, [r1], #1
+strgtb r3, [r0], #1
+ldmia sp!, {r0, pc}
+
+/* erg - unaligned destination */
+Lmemcpy_fdestul:
+rsb r12, r12, #4
+cmp r12, #2
+
+/* align destination with byte copies */
+ldrb r3, [r1], #1
+strb r3, [r0], #1
+ldrgeb r3, [r1], #1
+strgeb r3, [r0], #1
+ldrgtb r3, [r1], #1
+strgtb r3, [r0], #1
+subs r2, r2, r12
+blt Lmemcpy_fl4 /* less the 4 bytes */
+
+ands r12, r1, #3
+beq Lmemcpy_ft8 /* we have an aligned source */
+
+/* erg - unaligned source */
+/* This is where it gets nasty ... */
+Lmemcpy_fsrcul:
+bic r1, r1, #3
+ldr lr, [r1], #4
+cmp r12, #2
+bgt Lmemcpy_fsrcul3
+beq Lmemcpy_fsrcul2
+cmp r2, #0x0c
+blt Lmemcpy_fsrcul1loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5}
+
+Lmemcpy_fsrcul1loop16:
+mov r3, lr, lsr #8
+ldmia r1!, {r4, r5, r12, lr}
+orr r3, r3, r4, lsl #24
+mov r4, r4, lsr #8
+orr r4, r4, r5, lsl #24
+mov r5, r5, lsr #8
+orr r5, r5, r12, lsl #24
+mov r12, r12, lsr #8
+orr r12, r12, lr, lsl #24
+stmia r0!, {r3-r5, r12}
+subs r2, r2, #0x10
+bge Lmemcpy_fsrcul1loop16
+ldmia sp!, {r4, r5}
+adds r2, r2, #0x0c
+blt Lmemcpy_fsrcul1l4
+
+Lmemcpy_fsrcul1loop4:
+mov r12, lr, lsr #8
+ldr lr, [r1], #4
+orr r12, r12, lr, lsl #24
+str r12, [r0], #4
+subs r2, r2, #4
+bge Lmemcpy_fsrcul1loop4
+
+Lmemcpy_fsrcul1l4:
+sub r1, r1, #3
+b Lmemcpy_fl4
+
+Lmemcpy_fsrcul2:
+cmp r2, #0x0c
+blt Lmemcpy_fsrcul2loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5}
+
+Lmemcpy_fsrcul2loop16:
+mov r3, lr, lsr #16
+ldmia r1!, {r4, r5, r12, lr}
+orr r3, r3, r4, lsl #16
+mov r4, r4, lsr #16
+orr r4, r4, r5, lsl #16
+mov r5, r5, lsr #16
+orr r5, r5, r12, lsl #16
+mov r12, r12, lsr #16
+orr r12, r12, lr, lsl #16
+stmia r0!, {r3-r5, r12}
+subs r2, r2, #0x10
+bge Lmemcpy_fsrcul2loop16
+ldmia sp!, {r4, r5}
+adds r2, r2, #0x0c
+blt Lmemcpy_fsrcul2l4
+
+Lmemcpy_fsrcul2loop4:
+mov r12, lr, lsr #16
+ldr lr, [r1], #4
+orr r12, r12, lr, lsl #16
+str r12, [r0], #4
+subs r2, r2, #4
+bge Lmemcpy_fsrcul2loop4
+
+Lmemcpy_fsrcul2l4:
+sub r1, r1, #2
+b Lmemcpy_fl4
+
+Lmemcpy_fsrcul3:
+cmp r2, #0x0c
+blt Lmemcpy_fsrcul3loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5}
+
+Lmemcpy_fsrcul3loop16:
+mov r3, lr, lsr #24
+ldmia r1!, {r4, r5, r12, lr}
+orr r3, r3, r4, lsl #8
+mov r4, r4, lsr #24
+orr r4, r4, r5, lsl #8
+mov r5, r5, lsr #24
+orr r5, r5, r12, lsl #8
+mov r12, r12, lsr #24
+orr r12, r12, lr, lsl #8
+stmia r0!, {r3-r5, r12}
+subs r2, r2, #0x10
+bge Lmemcpy_fsrcul3loop16
+ldmia sp!, {r4, r5}
+adds r2, r2, #0x0c
+blt Lmemcpy_fsrcul3l4
+
+Lmemcpy_fsrcul3loop4:
+mov r12, lr, lsr #24
+ldr lr, [r1], #4
+orr r12, r12, lr, lsl #8
+str r12, [r0], #4
+subs r2, r2, #4
+bge Lmemcpy_fsrcul3loop4
+
+Lmemcpy_fsrcul3l4:
+sub r1, r1, #1
+b Lmemcpy_fl4
+
+Lmemcpy_backwards:
+add r1, r1, r2
+add r0, r0, r2
+subs r2, r2, #4
+blt Lmemcpy_bl4 /* less than 4 bytes */
+ands r12, r0, #3
+bne Lmemcpy_bdestul /* oh unaligned destination addr */
+ands r12, r1, #3
+bne Lmemcpy_bsrcul /* oh unaligned source addr */
+
+Lmemcpy_bt8:
+/* We have aligned source and destination */
+subs r2, r2, #8
+blt Lmemcpy_bl12 /* less than 12 bytes (4 from above) */
+stmdb sp!, {r4, r7, r8, r9, r10, lr}
+subs r2, r2, #0x14 /* less than 32 bytes (12 from above) */
+blt Lmemcpy_bl32
+
+/* blat 64 bytes at a time */
+/* XXX for really big copies perhaps we should use more registers */
+Lmemcpy_bloop32:
+ldmdb r1!, {r3, r4, r7, r8, r9, r10, r12, lr}
+stmdb r0!, {r3, r4, r7, r8, r9, r10, r12, lr}
+ldmdb r1!, {r3, r4, r7, r8, r9, r10, r12, lr}
+stmdb r0!, {r3, r4, r7, r8, r9, r10, r12, lr}
+subs r2, r2, #0x40
+bge Lmemcpy_bloop32
+
+Lmemcpy_bl32:
+cmn r2, #0x10
+ldmgedb r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
+stmgedb r0!, {r3, r4, r12, lr}
+subge r2, r2, #0x10
+adds r2, r2, #0x14
+ldmgedb r1!, {r3, r12, lr} /* blat a remaining 12 bytes */
+stmgedb r0!, {r3, r12, lr}
+subge r2, r2, #0x0c
+ldmia sp!, {r4, r7, r8, r9, r10, lr}
+
+Lmemcpy_bl12:
+adds r2, r2, #8
+blt Lmemcpy_bl4
+subs r2, r2, #4
+ldrlt r3, [r1, #-4]!
+strlt r3, [r0, #-4]!
+ldmgedb r1!, {r3, r12}
+stmgedb r0!, {r3, r12}
+subge r2, r2, #4
+
+Lmemcpy_bl4:
+/* less than 4 bytes to go */
+adds r2, r2, #4
+moveq pc, lr /* done */
+
+/* copy the crud byte at a time */
+cmp r2, #2
+ldrb r3, [r1, #-1]!
+strb r3, [r0, #-1]!
+ldrgeb r3, [r1, #-1]!
+strgeb r3, [r0, #-1]!
+ldrgtb r3, [r1, #-1]!
+strgtb r3, [r0, #-1]!
+mov pc, lr
+
+/* erg - unaligned destination */
+Lmemcpy_bdestul:
+cmp r12, #2
+
+/* align destination with byte copies */
+ldrb r3, [r1, #-1]!
+strb r3, [r0, #-1]!
+ldrgeb r3, [r1, #-1]!
+strgeb r3, [r0, #-1]!
+ldrgtb r3, [r1, #-1]!
+strgtb r3, [r0, #-1]!
+subs r2, r2, r12
+blt Lmemcpy_bl4 /* less than 4 bytes to go */
+ands r12, r1, #3
+beq Lmemcpy_bt8 /* we have an aligned source */
+
+/* erg - unaligned source */
+/* This is where it gets nasty ... */
+Lmemcpy_bsrcul:
+bic r1, r1, #3
+ldr r3, [r1, #0]
+cmp r12, #2
+blt Lmemcpy_bsrcul1
+beq Lmemcpy_bsrcul2
+cmp r2, #0x0c
+blt Lmemcpy_bsrcul3loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5, lr}
+
+Lmemcpy_bsrcul3loop16:
+mov lr, r3, lsl #8
+ldmdb r1!, {r3-r5, r12}
+orr lr, lr, r12, lsr #24
+mov r12, r12, lsl #8
+orr r12, r12, r5, lsr #24
+mov r5, r5, lsl #8
+orr r5, r5, r4, lsr #24
+mov r4, r4, lsl #8
+orr r4, r4, r3, lsr #24
+stmdb r0!, {r4, r5, r12, lr}
+subs r2, r2, #0x10
+bge Lmemcpy_bsrcul3loop16
+ldmia sp!, {r4, r5, lr}
+adds r2, r2, #0x0c
+blt Lmemcpy_bsrcul3l4
+
+Lmemcpy_bsrcul3loop4:
+mov r12, r3, lsl #8
+ldr r3, [r1, #-4]!
+orr r12, r12, r3, lsr #24
+str r12, [r0, #-4]!
+subs r2, r2, #4
+bge Lmemcpy_bsrcul3loop4
+
+Lmemcpy_bsrcul3l4:
+add r1, r1, #3
+b Lmemcpy_bl4
+
+Lmemcpy_bsrcul2:
+cmp r2, #0x0c
+blt Lmemcpy_bsrcul2loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5, lr}
+
+Lmemcpy_bsrcul2loop16:
+mov lr, r3, lsl #16
+ldmdb r1!, {r3-r5, r12}
+orr lr, lr, r12, lsr #16
+mov r12, r12, lsl #16
+orr r12, r12, r5, lsr #16
+mov r5, r5, lsl #16
+orr r5, r5, r4, lsr #16
+mov r4, r4, lsl #16
+orr r4, r4, r3, lsr #16
+stmdb r0!, {r4, r5, r12, lr}
+subs r2, r2, #0x10
+bge Lmemcpy_bsrcul2loop16
+ldmia sp!, {r4, r5, lr}
+adds r2, r2, #0x0c
+blt Lmemcpy_bsrcul2l4
+
+Lmemcpy_bsrcul2loop4:
+mov r12, r3, lsl #16
+ldr r3, [r1, #-4]!
+orr r12, r12, r3, lsr #16
+str r12, [r0, #-4]!
+subs r2, r2, #4
+bge Lmemcpy_bsrcul2loop4
+
+Lmemcpy_bsrcul2l4:
+add r1, r1, #2
+b Lmemcpy_bl4
+
+Lmemcpy_bsrcul1:
+cmp r2, #0x0c
+blt Lmemcpy_bsrcul1loop4
+sub r2, r2, #0x0c
+stmdb sp!, {r4, r5, lr}
+
+Lmemcpy_bsrcul1loop32:
+mov lr, r3, lsl #24
+ldmdb r1!, {r3-r5, r12}
+orr lr, lr, r12, lsr #8
+mov r12, r12, lsl #24
+orr r12, r12, r5, lsr #8
+mov r5, r5, lsl #24
+orr r5, r5, r4, lsr #8
+mov r4, r4, lsl #24
+orr r4, r4, r3, lsr #8
+stmdb r0!, {r4, r5, r12, lr}
+subs r2, r2, #0x10
+bge Lmemcpy_bsrcul1loop32
+ldmia sp!, {r4, r5, lr}
+adds r2, r2, #0x0c
+blt Lmemcpy_bsrcul1l4
+
+Lmemcpy_bsrcul1loop4:
+mov r12, r3, lsl #24
+ldr r3, [r1, #-4]!
+orr r12, r12, r3, lsr #8
+str r12, [r0, #-4]!
+subs r2, r2, #4
+bge Lmemcpy_bsrcul1loop4
+
+Lmemcpy_bsrcul1l4:
+add r1, r1, #1
+b Lmemcpy_bl4
--- /dev/null
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <sys/mman.h>\r
+#include <sys/ioctl.h>\r
+#include <sys/time.h>\r
+#include <fcntl.h>\r
+#include <errno.h>\r
+\r
+#include "940shared.h"\r
+#include "../gp2x.h"\r
+//#include "emu.h"\r
+//#include "menu.h"\r
+#include "../asmutils.h"\r
+#include "../helix/pub/mp3dec.h"\r
+\r
+/* we will need some gp2x internals here */\r
+extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */\r
+extern volatile unsigned long *gp2x_memregl;\r
+\r
+static unsigned char *shared_mem = 0;\r
+static _940_data_t *shared_data = 0;\r
+static _940_ctl_t *shared_ctl = 0;\r
+static unsigned char *mp3_mem = 0;\r
+\r
+#define MP3_SIZE_MAX (0x1000000 - 4*640*480)\r
+\r
+int crashed_940 = 0;\r
+\r
+\r
+/***********************************************************/\r
+\r
+#define MAXOUT (+32767)\r
+#define MINOUT (-32768)\r
+\r
+/* limitter */\r
+#define Limit(val, max,min) { \\r
+ if ( val > max ) val = max; \\r
+ else if ( val < min ) val = min; \\r
+}\r
+\r
+\r
+void wait_busy_940(void)\r
+{\r
+ int i;\r
+#if 0\r
+ printf("940 busy, entering wait loop.. (cnt: %i, wc: %i, ve: ", shared_ctl->loopc, shared_ctl->waitc);\r
+ for (i = 0; i < 8; i++)\r
+ printf("%i ", shared_ctl->vstarts[i]);\r
+ printf(")\n");\r
+\r
+ for (i = 0; shared_ctl->busy; i++)\r
+ {\r
+ spend_cycles(1024); /* needs tuning */\r
+ }\r
+ printf("wait iterations: %i\n", i);\r
+#else\r
+ for (i = 0; shared_ctl->busy && i < 0x10000; i++)\r
+ spend_cycles(8*1024);\r
+ if (i < 0x10000) return;\r
+\r
+ /* 940 crashed */\r
+ printf("940 crashed (cnt: %i, ve: ", shared_ctl->loopc);\r
+ for (i = 0; i < 8; i++)\r
+ printf("%i ", shared_ctl->vstarts[i]);\r
+ printf(")\n");\r
+ crashed_940 = 1;\r
+#endif\r
+}\r
+\r
+\r
+void add_job_940(int job0, int job1)\r
+{\r
+ shared_ctl->jobs[0] = job0;\r
+ shared_ctl->jobs[1] = job1;\r
+ shared_ctl->busy = 1;\r
+ gp2x_memregs[0x3B3E>>1] = 0xffff; // cause an IRQ for 940\r
+}\r
+\r
+\r
+static int read_to_upper(void *dest, void *tmpbuf, int tmpsize, FILE *f)\r
+{\r
+ int nRead, nLen = 0;\r
+\r
+ while(1)\r
+ {\r
+ nRead = fread(tmpbuf, 1, tmpsize, f);\r
+ if(nRead <= 0)\r
+ break;\r
+ memcpy((unsigned char *)dest + nLen, tmpbuf, nRead);\r
+ nLen += nRead;\r
+ }\r
+\r
+ return nLen;\r
+}\r
+\r
+static void simpleWait(int thissec, int lim_time)\r
+{\r
+ struct timeval tval;\r
+\r
+ spend_cycles(1024);\r
+ gettimeofday(&tval, 0);\r
+ if(thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
+\r
+ while(tval.tv_usec < lim_time)\r
+ {\r
+ spend_cycles(1024);\r
+ gettimeofday(&tval, 0);\r
+ if(thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
+ }\r
+}\r
+\r
+\r
+char **g_argv;\r
+\r
+/* none of the functions in this file should be called before this one */\r
+void YM2612Init_940(int baseclock, int rate)\r
+{\r
+ printf("YM2612Init_940()\n");\r
+ printf("Mem usage: shared_data: %i, shared_ctl: %i\n", sizeof(*shared_data), sizeof(*shared_ctl));\r
+\r
+ Reset940(1, 2);\r
+ Pause940(1);\r
+\r
+ gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940\r
+ gp2x_memregs[0x3B42>>1] = 0xffff; // enable DUALCPU interrupts for 940\r
+\r
+ gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller\r
+\r
+ if (shared_mem == NULL)\r
+ {\r
+ shared_mem = (unsigned char *) mmap(0, 0x210000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2000000);\r
+ if(shared_mem == MAP_FAILED)\r
+ {\r
+ printf("mmap(shared_data) failed with %i\n", errno);\r
+ exit(1);\r
+ }\r
+ shared_data = (_940_data_t *) (shared_mem+0x100000);\r
+ /* this area must not get buffered on either side */\r
+ shared_ctl = (_940_ctl_t *) (shared_mem+0x200000);\r
+ mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x3000000);\r
+ if (mp3_mem == MAP_FAILED)\r
+ {\r
+ printf("mmap(mp3_mem) failed with %i\n", errno);\r
+ exit(1);\r
+ }\r
+ crashed_940 = 1;\r
+ }\r
+\r
+ if (crashed_940)\r
+ {\r
+ unsigned char ucData[1024];\r
+ int i;\r
+ char binpath[1024];\r
+ FILE *fp;\r
+\r
+ strncpy(binpath, g_argv[0], 1023);\r
+ binpath[1023] = 0;\r
+ for (i = strlen(binpath); i > 0; i--)\r
+ if (binpath[i] == '/') { binpath[i] = 0; break; }\r
+ strcat(binpath, "/code940.bin");\r
+\r
+ fp = fopen(binpath, "rb");\r
+ if(!fp)\r
+ {\r
+ printf("failed to open %s\n", binpath);\r
+ exit(1);\r
+ }\r
+\r
+ read_to_upper(shared_mem, ucData, sizeof(ucData), fp);\r
+ fclose(fp);\r
+ crashed_940 = 0;\r
+ }\r
+\r
+ memset(shared_data, 0, sizeof(*shared_data));\r
+ memset(shared_ctl, 0, sizeof(*shared_ctl));\r
+\r
+ /* now cause 940 to init it's ym2612 stuff */\r
+ shared_ctl->baseclock = baseclock;\r
+ shared_ctl->rate = rate;\r
+ shared_ctl->jobs[0] = JOB940_INITALL;\r
+ shared_ctl->jobs[1] = 0;\r
+ shared_ctl->busy = 1;\r
+\r
+ /* start the 940 */\r
+ Reset940(0, 2);\r
+ Pause940(0);\r
+}\r
+\r
+\r
+unsigned char *mp3_data = 0;\r
+\r
+void local_decode(void)\r
+{\r
+ int mp3_offs = shared_ctl->mp3_offs;\r
+ unsigned char *readPtr = mp3_data + mp3_offs;\r
+ int bytesLeft = shared_ctl->mp3_len - mp3_offs;\r
+ int offset; // frame offset from readPtr\r
+ int err = 0;\r
+\r
+ if (bytesLeft <= 0) return; // EOF, nothing to do\r
+\r
+ offset = MP3FindSyncWord(readPtr, bytesLeft);\r
+ if (offset < 0) {\r
+ shared_ctl->mp3_offs = shared_ctl->mp3_len;\r
+ return; // EOF\r
+ }\r
+ readPtr += offset;\r
+ bytesLeft -= offset;\r
+\r
+ err = MP3Decode(shared_data->mp3dec, &readPtr, &bytesLeft,\r
+ shared_data->mp3_buffer[shared_ctl->mp3_buffsel], 0);\r
+ if (err) {\r
+ if (err == ERR_MP3_INDATA_UNDERFLOW) {\r
+ shared_ctl->mp3_offs = shared_ctl->mp3_len; // EOF\r
+ return;\r
+ } else if (err <= -6 && err >= -12) {\r
+ // ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*\r
+ // just try to skip the offending frame..\r
+ readPtr++;\r
+ }\r
+ shared_ctl->mp3_errors++;\r
+ shared_ctl->mp3_lasterr = err;\r
+ }\r
+ shared_ctl->mp3_offs = readPtr - mp3_data;\r
+}\r
+\r
+\r
+void gp2x_sound_sync(void);\r
+\r
+#define USE_LOCAL 0\r
+#define BENCHMARK 0\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+ FILE *f;\r
+ int size;\r
+ struct timeval tval; // timing\r
+ int thissec = 0, fps = 0;\r
+ int target_frametime, frame_samples, samples_ready, mp3_buffer_offs, play_bufsel;\r
+ unsigned char play_buffer[44100/50*2*2];\r
+\r
+ if (argc != 2) {\r
+ printf("usage: %s <mp3file>\n", argv[0]);\r
+ return 1;\r
+ }\r
+\r
+ g_argv = argv;\r
+\r
+ gp2x_init();\r
+ YM2612Init_940(123, 44100);\r
+\r
+ // load a mp3\r
+ f = fopen(argv[1], "rb");\r
+ if (!f) {\r
+ printf("can't open %s\n", argv[1]);\r
+ return 1;\r
+ }\r
+\r
+ fseek(f, 0, SEEK_END);\r
+ size = (int) ftell(f);\r
+ if (size > MP3_SIZE_MAX) {\r
+ printf("size %i > %i\n", size, MP3_SIZE_MAX);\r
+ size = MP3_SIZE_MAX;\r
+ }\r
+\r
+ fseek(f, 0, SEEK_SET);\r
+ if (fread(mp3_mem, 1, size, f) != size) {\r
+ printf("read failed, errno=%i\n", errno);\r
+ fclose(f);\r
+ exit(1);\r
+ }\r
+ fclose(f);\r
+ shared_ctl->mp3_len = size;\r
+\r
+#if USE_LOCAL\r
+ shared_data->mp3dec = MP3InitDecoder();\r
+ mp3_data = malloc(size);\r
+ printf("init: dec: %p ptr: %p\n", shared_data->mp3dec, mp3_data);\r
+ if (!mp3_data) {\r
+ printf("low mem\n");\r
+ exit(1);\r
+ }\r
+ memcpy(mp3_data, mp3_mem, size);\r
+#else\r
+ //printf("YM2612UpdateOne_940()\n");\r
+ if (shared_ctl->busy) wait_busy_940();\r
+#endif\r
+\r
+ gp2x_start_sound(44100, 16, 1);\r
+\r
+ #define DESIRED_FPS 50\r
+ target_frametime = 1000000/DESIRED_FPS;\r
+ frame_samples = 44100/DESIRED_FPS;\r
+ samples_ready = mp3_buffer_offs = 0;\r
+ play_bufsel = 1;\r
+\r
+ for (;; fps++)\r
+ {\r
+ int lim_time;\r
+\r
+ gettimeofday(&tval, 0);\r
+ if (tval.tv_sec != thissec)\r
+ {\r
+ printf("fps: %i\n", fps);\r
+ thissec = tval.tv_sec;\r
+ fps = 0;\r
+#if BENCHMARK\r
+ shared_ctl->mp3_offs = 0;\r
+#endif\r
+ }\r
+\r
+#if 0\r
+ // decode\r
+#if USE_LOCAL\r
+ shared_ctl->mp3_buffsel ^= 1;\r
+ local_decode();\r
+#else\r
+ wait_busy_940();\r
+ shared_ctl->mp3_buffsel ^= 1;\r
+ add_job_940(JOB940_MP3DECODE, 0);\r
+#endif\r
+\r
+ if (shared_ctl->mp3_lasterr) {\r
+ printf("mp3_lasterr #%i: %i size: %i offs: %i\n", shared_ctl->mp3_errors, shared_ctl->mp3_lasterr,\r
+ shared_ctl->mp3_len, shared_ctl->mp3_offs);\r
+ printf("loopc: %i bytes: %08x\n",\r
+ shared_ctl->loopc, *(int *)(mp3_mem+shared_ctl->mp3_offs));\r
+ shared_ctl->mp3_lasterr = 0;\r
+ }\r
+\r
+#if !BENCHMARK\r
+ // play\r
+ gp2x_sound_sync();\r
+ gp2x_sound_write(shared_data->mp3_buffer[shared_ctl->mp3_buffsel^1], 1152*2*2);\r
+#endif\r
+#else\r
+ lim_time = (fps+1) * target_frametime;\r
+\r
+ wait_busy_940();\r
+\r
+ // decode, play\r
+ if (samples_ready >= frame_samples) {\r
+ if (1152 - mp3_buffer_offs >= frame_samples) {\r
+ memcpy(play_buffer, shared_data->mp3_buffer[play_bufsel] + mp3_buffer_offs*2,\r
+ frame_samples*2*2);\r
+ mp3_buffer_offs += frame_samples;\r
+ } else {\r
+ // collect from both buffers..\r
+ int left = 1152 - mp3_buffer_offs;\r
+ memcpy(play_buffer, shared_data->mp3_buffer[play_bufsel] + mp3_buffer_offs*2,\r
+ left*2*2);\r
+ play_bufsel ^= 1;\r
+ mp3_buffer_offs = frame_samples - left;\r
+ memcpy(play_buffer + left*2*2, shared_data->mp3_buffer[play_bufsel],\r
+ mp3_buffer_offs*2*2);\r
+ }\r
+ gp2x_sound_write(play_buffer, frame_samples*2*2);\r
+ samples_ready -= frame_samples;\r
+ }\r
+\r
+ // make sure we will have enough samples next frame\r
+ if (samples_ready < frame_samples) {\r
+// wait_busy_940();\r
+ shared_ctl->mp3_buffsel ^= 1;\r
+ add_job_940(JOB940_MP3DECODE, 0);\r
+ samples_ready += 1152;\r
+ }\r
+\r
+ gettimeofday(&tval, 0);\r
+ if(thissec != tval.tv_sec) tval.tv_usec+=1000000;\r
+ if(tval.tv_usec < lim_time)\r
+ {\r
+ // we are too fast\r
+ simpleWait(thissec, lim_time);\r
+ }\r
+#endif\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
write(sounddev, buff, len);\r
}\r
\r
+void gp2x_sound_sync(void)\r
+{\r
+ ioctl(sounddev, SOUND_PCM_SYNC, 0);\r
+}\r
\r
void gp2x_sound_volume(int l, int r)\r
{\r