mirror of
https://github.com/RaySollium99/libpicofe.git
synced 2025-09-04 14:37:46 -04:00
remove PicoDrive-specific stuff, add readme
This commit is contained in:
parent
ca69c3e5a0
commit
f506842df2
73 changed files with 13 additions and 16178 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.o
|
||||
*.swp
|
11
README
Normal file
11
README
Normal file
|
@ -0,0 +1,11 @@
|
|||
libpicofe, or LIB-PICOdrive's-FrontEnd, is an attempt to reuse PicoDrive's
|
||||
frontend code for other projects. To accommodate various needs, this is
|
||||
tripple-licensed with these licenses:
|
||||
- GNU GPL, version 2 or later.
|
||||
- GNU LGPL, version 2.1 or later.
|
||||
- MAME license.
|
||||
When used as part of another project, host project's license usually applies
|
||||
to combined source code as a whole.
|
||||
|
||||
|
||||
- notaz
|
1159
base_readme.txt
1159
base_readme.txt
File diff suppressed because it is too large
Load diff
|
@ -1,14 +0,0 @@
|
|||
// (c) Copyright 2006-2009 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
void bgr444_to_rgb32(void *to, void *from);
|
||||
void bgr444_to_rgb32_sh(void *to, void *from);
|
||||
|
||||
void vidcpy_m2(void *dest, void *src, int m32col, int with_32c_border);
|
||||
void vidcpy_m2_rot(void *dest, void *src, int m32col, int with_32c_border);
|
||||
void spend_cycles(int c); // utility
|
||||
|
||||
void rotated_blit8 (void *dst, void *linesx4, int y, int is_32col);
|
||||
void rotated_blit16(void *dst, void *linesx4, int y, int is_32col);
|
|
@ -1,337 +0,0 @@
|
|||
@ vim:filetype=armasm
|
||||
@ some color conversion and blitting routines
|
||||
|
||||
@ (c) Copyright 2006, 2007 notaz
|
||||
@ All Rights Reserved
|
||||
|
||||
@ vim:filetype=armasm
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
@ Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0
|
||||
@ to 00000000 rrr00000 ggg00000 bbb00000 ...
|
||||
|
||||
@ lr = 0x00e000e0, out: r3=lower_pix, r2=higher_pix; trashes rin
|
||||
.macro convRGB32_2 rin sh=0
|
||||
and r2, lr, \rin, lsr #4 @ blue
|
||||
and r3, \rin, lr
|
||||
orr r2, r2, r3, lsl #8 @ g0b0g0b0
|
||||
|
||||
mov r3, r2, lsl #16 @ g0b00000
|
||||
and \rin,lr, \rin, ror #12 @ 00r000r0 (reversed)
|
||||
orr r3, r3, \rin, lsr #16 @ g0b000r0
|
||||
.if \sh == 1
|
||||
mov r3, r3, ror #17 @ shadow mode
|
||||
.elseif \sh == 2
|
||||
adds r3, r3, #0x40000000 @ green
|
||||
orrcs r3, r3, #0xe0000000
|
||||
mov r3, r3, ror #8
|
||||
adds r3, r3, #0x40000000
|
||||
orrcs r3, r3, #0xe0000000
|
||||
mov r3, r3, ror #16
|
||||
adds r3, r3, #0x40000000
|
||||
orrcs r3, r3, #0xe0000000
|
||||
mov r3, r3, ror #24
|
||||
.else
|
||||
mov r3, r3, ror #16 @ r3=low
|
||||
.endif
|
||||
|
||||
orr r3, r3, r3, lsr #3
|
||||
str r3, [r0], #4
|
||||
|
||||
mov r2, r2, lsr #16
|
||||
orr r2, r2, \rin, lsl #16
|
||||
.if \sh == 1
|
||||
mov r2, r2, lsr #1
|
||||
.elseif \sh == 2
|
||||
mov r2, r2, ror #8
|
||||
adds r2, r2, #0x40000000 @ blue
|
||||
orrcs r2, r2, #0xe0000000
|
||||
mov r2, r2, ror #8
|
||||
adds r2, r2, #0x40000000
|
||||
orrcs r2, r2, #0xe0000000
|
||||
mov r2, r2, ror #8
|
||||
adds r2, r2, #0x40000000
|
||||
orrcs r2, r2, #0xe0000000
|
||||
mov r2, r2, ror #8
|
||||
.endif
|
||||
|
||||
orr r2, r2, r2, lsr #3
|
||||
.if \sh == 1
|
||||
str r2, [r0, #0x40*2*4]
|
||||
.endif
|
||||
str r2, [r0], #4
|
||||
.endm
|
||||
|
||||
|
||||
.global bgr444_to_rgb32 @ void *to, void *from
|
||||
|
||||
bgr444_to_rgb32:
|
||||
stmfd sp!, {r4-r7,lr}
|
||||
|
||||
mov r12, #0x40>>3 @ repeats
|
||||
mov lr, #0x00e00000
|
||||
orr lr, lr, #0x00e0
|
||||
|
||||
.loopRGB32:
|
||||
subs r12, r12, #1
|
||||
|
||||
ldmia r1!, {r4-r7}
|
||||
convRGB32_2 r4
|
||||
convRGB32_2 r5
|
||||
convRGB32_2 r6
|
||||
convRGB32_2 r7
|
||||
bgt .loopRGB32
|
||||
|
||||
ldmfd sp!, {r4-r7,pc}
|
||||
|
||||
|
||||
.global bgr444_to_rgb32_sh @ void *to, void *from
|
||||
|
||||
bgr444_to_rgb32_sh:
|
||||
stmfd sp!, {r4-r7,lr}
|
||||
|
||||
mov r12, #0x40>>3 @ repeats
|
||||
add r0, r0, #0x40*4
|
||||
mov lr, #0x00e00000
|
||||
orr lr, lr, #0x00e0
|
||||
|
||||
.loopRGB32sh:
|
||||
subs r12, r12, #1
|
||||
|
||||
ldmia r1!, {r4-r7}
|
||||
convRGB32_2 r4, 1
|
||||
convRGB32_2 r5, 1
|
||||
convRGB32_2 r6, 1
|
||||
convRGB32_2 r7, 1
|
||||
bgt .loopRGB32sh
|
||||
|
||||
mov r12, #0x40>>3 @ repeats
|
||||
sub r1, r1, #0x40*2
|
||||
|
||||
.loopRGB32hi:
|
||||
ldmia r1!, {r4-r7}
|
||||
convRGB32_2 r4, 2
|
||||
convRGB32_2 r5, 2
|
||||
convRGB32_2 r6, 2
|
||||
convRGB32_2 r7, 2
|
||||
|
||||
subs r12, r12, #1
|
||||
bgt .loopRGB32hi
|
||||
|
||||
ldmfd sp!, {r4-r7,lr}
|
||||
bx lr
|
||||
|
||||
|
||||
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
|
||||
@ mode2 blitter
|
||||
.global vidcpy_m2 @ void *dest, void *src, int m32col, int with_32c_border
|
||||
vidcpy_m2:
|
||||
stmfd sp!, {r4-r6,lr}
|
||||
|
||||
mov r12, #224 @ lines
|
||||
add r0, r0, #320*8
|
||||
add r1, r1, #8
|
||||
mov lr, #0
|
||||
|
||||
tst r2, r2
|
||||
movne lr, #64
|
||||
tstne r3, r3
|
||||
addne r0, r0, #32
|
||||
|
||||
vidCpyM2_loop_out:
|
||||
mov r6, #10
|
||||
sub r6, r6, lr, lsr #5 @ -= 2 in 32col mode
|
||||
vidCpyM2_loop:
|
||||
subs r6, r6, #1
|
||||
ldmia r1!, {r2-r5}
|
||||
stmia r0!, {r2-r5}
|
||||
ldmia r1!, {r2-r5}
|
||||
stmia r0!, {r2-r5}
|
||||
bne vidCpyM2_loop
|
||||
|
||||
subs r12,r12,#1
|
||||
add r0, r0, lr
|
||||
add r1, r1, #8
|
||||
add r1, r1, lr
|
||||
bne vidCpyM2_loop_out
|
||||
|
||||
ldmfd sp!, {r4-r6,pc}
|
||||
|
||||
|
||||
.global vidcpy_m2_rot @ void *dest, void *src, int m32col, int with_32c_border
|
||||
vidcpy_m2_rot:
|
||||
stmfd sp!,{r4-r8,lr}
|
||||
add r1, r1, #8
|
||||
tst r2, r2
|
||||
subne r1, r1, #32 @ adjust
|
||||
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r6, r2
|
||||
mov r7, #8+4
|
||||
|
||||
vidcpy_m2_rot_loop:
|
||||
@ a bit lame but oh well..
|
||||
mov r0, r4
|
||||
mov r1, r5
|
||||
mov r2, r7
|
||||
mov r3, r6
|
||||
mov r8, #328
|
||||
adr lr, after_rot_blit8
|
||||
stmfd sp!,{r4-r8,lr}
|
||||
b rotated_blit8_2
|
||||
|
||||
after_rot_blit8:
|
||||
add r5, r5, #328*4
|
||||
add r7, r7, #4
|
||||
cmp r7, #224+8+4
|
||||
ldmgefd sp!,{r4-r8,pc}
|
||||
b vidcpy_m2_rot_loop
|
||||
|
||||
|
||||
.global rotated_blit8 @ void *dst, void *linesx4, u32 y, int is_32col
|
||||
rotated_blit8:
|
||||
stmfd sp!,{r4-r8,lr}
|
||||
mov r8, #320
|
||||
|
||||
rotated_blit8_2:
|
||||
add r0, r0, #(240*320)
|
||||
sub r0, r0, #(240+4) @ y starts from 4
|
||||
add r0, r0, r2
|
||||
|
||||
tst r3, r3
|
||||
subne r0, r0, #(240*32)
|
||||
addne r1, r1, #32
|
||||
movne lr, #256/4
|
||||
moveq lr, #320/4
|
||||
|
||||
rotated_blit_loop8:
|
||||
mov r6, r1
|
||||
ldr r2, [r6], r8
|
||||
ldr r3, [r6], r8
|
||||
ldr r4, [r6], r8
|
||||
ldr r5, [r6], r8
|
||||
|
||||
mov r6, r2, lsl #24
|
||||
mov r6, r6, lsr #8
|
||||
orr r6, r6, r3, lsl #24
|
||||
mov r6, r6, lsr #8
|
||||
orr r6, r6, r4, lsl #24
|
||||
mov r6, r6, lsr #8
|
||||
orr r6, r6, r5, lsl #24
|
||||
str r6, [r0], #-240
|
||||
|
||||
and r6, r3, #0xff00
|
||||
and r7, r2, #0xff00
|
||||
orr r6, r6, r7, lsr #8
|
||||
and r7, r4, #0xff00
|
||||
orr r6, r6, r7, lsl #8
|
||||
and r7, r5, #0xff00
|
||||
orr r6, r6, r7, lsl #16
|
||||
str r6, [r0], #-240
|
||||
|
||||
and r6, r4, #0xff0000
|
||||
and r7, r2, #0xff0000
|
||||
orr r6, r6, r7, lsr #16
|
||||
and r7, r3, #0xff0000
|
||||
orr r6, r6, r7, lsr #8
|
||||
and r7, r5, #0xff0000
|
||||
orr r6, r6, r7, lsl #8
|
||||
str r6, [r0], #-240
|
||||
|
||||
mov r6, r5, lsr #24
|
||||
mov r6, r6, lsl #8
|
||||
orr r6, r6, r4, lsr #24
|
||||
mov r6, r6, lsl #8
|
||||
orr r6, r6, r3, lsr #24
|
||||
mov r6, r6, lsl #8
|
||||
orr r6, r6, r2, lsr #24
|
||||
str r6, [r0], #-240
|
||||
|
||||
subs lr, lr, #1
|
||||
add r1, r1, #4
|
||||
bne rotated_blit_loop8
|
||||
|
||||
ldmfd sp!,{r4-r8,pc}
|
||||
|
||||
|
||||
@ input: r2-r5
|
||||
@ output: r7,r8
|
||||
@ trash: r6
|
||||
.macro rb_line_low
|
||||
mov r6, r2, lsl #16
|
||||
mov r7, r3, lsl #16
|
||||
orr r7, r7, r6, lsr #16
|
||||
mov r6, r4, lsl #16
|
||||
mov r8, r5, lsl #16
|
||||
orr r8, r8, r6, lsr #16
|
||||
.endm
|
||||
|
||||
.macro rb_line_hi
|
||||
mov r6, r2, lsr #16
|
||||
mov r7, r3, lsr #16
|
||||
orr r7, r6, r7, lsl #16
|
||||
mov r6, r4, lsr #16
|
||||
mov r8, r5, lsr #16
|
||||
orr r8, r6, r8, lsl #16
|
||||
.endm
|
||||
|
||||
.global rotated_blit16 @ void *dst, void *linesx4, u32 y, int is_32col
|
||||
rotated_blit16:
|
||||
stmfd sp!,{r4-r8,lr}
|
||||
|
||||
add r0, r0, #(240*320)*2
|
||||
sub r0, r0, #(240+4)*2 @ y starts from 4
|
||||
add r0, r0, r2, lsl #1
|
||||
|
||||
tst r3, r3
|
||||
subne r0, r0, #(240*32)*2
|
||||
addne r1, r1, #32*2
|
||||
movne lr, #256/4
|
||||
moveq lr, #320/4
|
||||
|
||||
rotated_blit_loop16:
|
||||
ldr r2, [r1, #320*0*2]
|
||||
ldr r3, [r1, #320*1*2]
|
||||
ldr r4, [r1, #320*2*2]
|
||||
ldr r5, [r1, #320*3*2]
|
||||
rb_line_low
|
||||
stmia r0, {r7,r8}
|
||||
sub r0, r0, #240*2
|
||||
rb_line_hi
|
||||
stmia r0, {r7,r8}
|
||||
sub r0, r0, #240*2
|
||||
|
||||
ldr r2, [r1, #320*0*2+4]
|
||||
ldr r3, [r1, #320*1*2+4]
|
||||
ldr r4, [r1, #320*2*2+4]
|
||||
ldr r5, [r1, #320*3*2+4]
|
||||
rb_line_low
|
||||
stmia r0, {r7,r8}
|
||||
sub r0, r0, #240*2
|
||||
rb_line_hi
|
||||
stmia r0, {r7,r8}
|
||||
sub r0, r0, #240*2
|
||||
|
||||
subs lr, lr, #1
|
||||
add r1, r1, #8
|
||||
bne rotated_blit_loop16
|
||||
|
||||
ldmfd sp!,{r4-r8,pc}
|
||||
|
||||
|
||||
.global spend_cycles @ c
|
||||
|
||||
spend_cycles:
|
||||
mov r0, r0, lsr #2 @ 4 cycles/iteration
|
||||
sub r0, r0, #2 @ entry/exit/init
|
||||
.sc_loop:
|
||||
subs r0, r0, #1
|
||||
bpl .sc_loop
|
||||
|
||||
bx lr
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
ifneq ($(DEBUG),)
|
||||
CFLAGS += -ggdb
|
||||
endif
|
||||
ifeq "$(profile)" "1"
|
||||
CFLAGS += -fprofile-generate
|
||||
endif
|
||||
ifeq "$(profile)" "2"
|
||||
CFLAGS += -fprofile-use
|
||||
endif
|
||||
ifeq "$(pdb)" "1"
|
||||
DEFINES += PDB
|
||||
OBJS += cpu/debug.o
|
||||
ifeq "$(pdb_net)" "1"
|
||||
DEFINES += PDB_NET
|
||||
endif
|
||||
ifeq "$(readline)" "1"
|
||||
DEFINES += HAVE_READLINE
|
||||
LDFLAGS += -lreadline
|
||||
endif
|
||||
endif
|
||||
ifeq "$(pprof)" "1"
|
||||
DEFINES += PPROF
|
||||
OBJS += platform/linux/pprof.o
|
||||
endif
|
||||
|
||||
# === Pico core ===
|
||||
# Pico
|
||||
OBJS += pico/state.o pico/cart.o pico/memory.o pico/pico.o pico/sek.o pico/z80if.o \
|
||||
pico/videoport.o pico/draw2.o pico/draw.o pico/mode4.o \
|
||||
pico/misc.o pico/eeprom.o pico/patch.o pico/debug.o
|
||||
# SMS
|
||||
ifneq "$(no_sms)" "1"
|
||||
OBJS += pico/sms.o
|
||||
else
|
||||
DEFINES += NO_SMS
|
||||
endif
|
||||
# CD
|
||||
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \
|
||||
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \
|
||||
pico/cd/misc.o pico/cd/pcm.o pico/cd/buffering.o
|
||||
# 32X
|
||||
ifneq "$(no_32x)" "1"
|
||||
OBJS += pico/32x/32x.o pico/32x/memory.o pico/32x/draw.o pico/32x/pwm.o
|
||||
else
|
||||
DEFINES += NO_32X
|
||||
endif
|
||||
# Pico
|
||||
OBJS += pico/pico/pico.o pico/pico/memory.o pico/pico/xpcm.o
|
||||
# carthw
|
||||
OBJS += pico/carthw/carthw.o
|
||||
# SVP
|
||||
OBJS += pico/carthw/svp/svp.o pico/carthw/svp/memory.o \
|
||||
pico/carthw/svp/ssp16.o
|
||||
# sound
|
||||
OBJS += pico/sound/sound.o
|
||||
OBJS += pico/sound/sn76496.o pico/sound/ym2612.o
|
||||
|
||||
# === CPU cores ===
|
||||
# --- M68k ---
|
||||
ifeq "$(use_musashi)" "1"
|
||||
DEFINES += EMU_M68K
|
||||
OBJS += cpu/musashi/m68kops.o cpu/musashi/m68kcpu.o
|
||||
#OBJS += cpu/musashi/m68kdasm.o
|
||||
endif
|
||||
ifeq "$(use_cyclone)" "1"
|
||||
DEFINES += EMU_C68K
|
||||
OBJS += pico/m68kif_cyclone.o cpu/Cyclone/proj/Cyclone.o cpu/Cyclone/tools/idle.o
|
||||
endif
|
||||
ifeq "$(use_fame)" "1"
|
||||
DEFINES += EMU_F68K
|
||||
OBJS += cpu/fame/famec.o
|
||||
endif
|
||||
|
||||
# --- Z80 ---
|
||||
ifeq "$(use_drz80)" "1"
|
||||
DEFINES += _USE_DRZ80
|
||||
OBJS += cpu/DrZ80/drz80.o
|
||||
endif
|
||||
#
|
||||
ifeq "$(use_cz80)" "1"
|
||||
DEFINES += _USE_CZ80
|
||||
OBJS += cpu/cz80/cz80.o
|
||||
endif
|
||||
|
||||
# --- SH2 ---
|
||||
OBJS += cpu/drc/cmn.o
|
||||
ifneq "$(no_32x)" "1"
|
||||
OBJS += cpu/sh2/sh2.o
|
||||
#
|
||||
ifeq "$(use_sh2drc)" "1"
|
||||
DEFINES += DRC_SH2
|
||||
OBJS += cpu/sh2/compiler.o
|
||||
ifdef drc_debug
|
||||
DEFINES += DRC_DEBUG=$(drc_debug)
|
||||
OBJS += cpu/sh2/mame/sh2dasm.o
|
||||
OBJS += platform/linux/host_dasm.o
|
||||
LDFLAGS += -lbfd -lopcodes -liberty
|
||||
endif
|
||||
ifeq "$(drc_debug_interp)" "1"
|
||||
DEFINES += DRC_DEBUG_INTERP
|
||||
use_sh2mame = 1
|
||||
endif
|
||||
endif # use_sh2drc
|
||||
#
|
||||
ifeq "$(use_sh2mame)" "1"
|
||||
OBJS += cpu/sh2/mame/sh2pico.o
|
||||
endif
|
||||
endif # !no_32x
|
||||
|
||||
|
||||
DIRS += platform platform/common pico pico/cd pico/pico pico/32x pico/sound pico/carthw/svp \
|
||||
cpu cpu/musashi cpu/cz80 cpu/fame cpu/sh2/mame cpu/drc
|
||||
|
||||
|
||||
# common rules
|
||||
.c.o:
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
.s.o:
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean_prof:
|
||||
find ../.. -name '*.gcno' -delete
|
||||
find ../.. -name '*.gcda' -delete
|
||||
|
||||
mkdirs:
|
||||
mkdir -p $(DIRS)
|
||||
|
||||
../../tools/textfilter: ../../tools/textfilter.c
|
||||
make -C ../../tools/ textfilter
|
||||
|
||||
|
||||
# random deps
|
||||
pico/carthw/svp/compiler.o : ../../cpu/drc/emit_$(ARCH).c
|
||||
cpu/sh2/compiler.o : ../../cpu/drc/emit_$(ARCH).c
|
||||
cpu/sh2/mame/sh2pico.o : ../../cpu/sh2/mame/sh2.c
|
||||
pico/pico.o pico/cd/pico.o : ../../pico/pico_cmn.c ../../pico/pico_int.h
|
||||
pico/memory.o pico/cd/memory.o : ../../pico/pico_int.h ../../pico/memory.h
|
||||
|
||||
../../cpu/musashi/m68kops.c :
|
||||
@make -C ../../cpu/musashi
|
||||
|
||||
../../cpu/mz80/mz80.asm :
|
||||
@make -C ../../cpu/mz80/
|
||||
|
||||
cpu/fame/famec.o : ../../cpu/fame/famec.c ../../cpu/fame/famec_opcodes.h
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -Wno-unused -c $< -o $@
|
||||
|
||||
../../cpu/Cyclone/proj/Cyclone.s:
|
||||
@echo building Cyclone...
|
||||
@make -C ../../cpu/Cyclone/proj CONFIG_FILE=config_pico.h
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# asm stuff
|
||||
ifeq "$(asm_render)" "1"
|
||||
DEFINES += _ASM_DRAW_C
|
||||
OBJS += pico/draw_arm.o pico/draw2_arm.o
|
||||
endif
|
||||
ifeq "$(asm_memory)" "1"
|
||||
DEFINES += _ASM_MEMORY_C
|
||||
OBJS += pico/memory_arm.o
|
||||
endif
|
||||
ifeq "$(asm_ym2612)" "1"
|
||||
DEFINES += _ASM_YM2612_C
|
||||
OBJS += pico/sound/ym2612_arm.o
|
||||
endif
|
||||
ifeq "$(asm_misc)" "1"
|
||||
DEFINES += _ASM_MISC_C
|
||||
OBJS += pico/misc_arm.o
|
||||
OBJS += pico/cd/misc_arm.o
|
||||
endif
|
||||
ifeq "$(asm_cdpico)" "1"
|
||||
DEFINES += _ASM_CD_PICO_C
|
||||
OBJS += pico/cd/pico_arm.o
|
||||
endif
|
||||
ifeq "$(asm_cdmemory)" "1"
|
||||
DEFINES += _ASM_CD_MEMORY_C
|
||||
OBJS += pico/cd/memory_arm.o
|
||||
endif
|
||||
ifeq "$(asm_32xdraw)" "1"
|
||||
DEFINES += _ASM_32X_DRAW
|
||||
OBJS += pico/32x/draw_arm.o
|
||||
endif
|
||||
|
||||
|
||||
DIRS += cpu/Cyclone cpu/Cyclone/proj cpu/Cyclone/tools cpu/DrZ80
|
||||
|
||||
|
||||
# build helix libs
|
||||
../common/helix/$(CROSS)helix-mp3.a:
|
||||
make -C ../common/helix CROSS=$(CROSS) clean all
|
||||
|
840
common/config.c
840
common/config.c
|
@ -1,840 +0,0 @@
|
|||
/*
|
||||
* Human-readable config file management for PicoDrive
|
||||
* (c) notaz, 2008
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __EPOC32__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "plat.h"
|
||||
#include "input.h"
|
||||
#include "lprintf.h"
|
||||
|
||||
static char *mystrip(char *str);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#include "menu.h"
|
||||
#include "menu_pico.h"
|
||||
#include "emu.h"
|
||||
#include <pico/pico.h>
|
||||
|
||||
// always output DOS endlines
|
||||
#ifdef _WIN32
|
||||
#define NL "\n"
|
||||
#else
|
||||
#define NL "\r\n"
|
||||
#endif
|
||||
|
||||
static int seek_sect(FILE *f, const char *section)
|
||||
{
|
||||
char line[128], *tmp;
|
||||
int len;
|
||||
|
||||
len = strlen(section);
|
||||
// seek to the section needed
|
||||
while (!feof(f))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), f);
|
||||
if (tmp == NULL) break;
|
||||
|
||||
if (line[0] != '[') continue; // not section start
|
||||
if (strncmp(line + 1, section, len) == 0 && line[len+1] == ']')
|
||||
return 1; // found it
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void keys_write(FILE *fn, const char *bind_str, int dev_id, const int *binds, int no_defaults)
|
||||
{
|
||||
char act[48];
|
||||
int key_count = 0, k, i;
|
||||
const int *def_binds;
|
||||
|
||||
in_get_config(dev_id, IN_CFG_BIND_COUNT, &key_count);
|
||||
def_binds = in_get_dev_def_binds(dev_id);
|
||||
|
||||
for (k = 0; k < key_count; k++)
|
||||
{
|
||||
const char *name;
|
||||
int t, mask;
|
||||
act[0] = act[31] = 0;
|
||||
|
||||
for (t = 0; t < IN_BINDTYPE_COUNT; t++)
|
||||
if (binds[IN_BIND_OFFS(k, t)] != def_binds[IN_BIND_OFFS(k, t)])
|
||||
break;
|
||||
|
||||
if (no_defaults && t == IN_BINDTYPE_COUNT)
|
||||
continue; /* no change from defaults */
|
||||
|
||||
name = in_get_key_name(dev_id, k);
|
||||
|
||||
for (t = 0; t < IN_BINDTYPE_COUNT; t++)
|
||||
if (binds[IN_BIND_OFFS(k, t)] != 0 || def_binds[IN_BIND_OFFS(k, t)] == 0)
|
||||
break;
|
||||
|
||||
if (t == IN_BINDTYPE_COUNT) {
|
||||
/* key has default bind removed */
|
||||
fprintf(fn, "%s %s =" NL, bind_str, name);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
|
||||
mask = me_ctrl_actions[i].mask;
|
||||
if (mask & binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)]) {
|
||||
strncpy(act, me_ctrl_actions[i].name, 31);
|
||||
fprintf(fn, "%s %s = player1 %s" NL, bind_str, name, mystrip(act));
|
||||
}
|
||||
mask = me_ctrl_actions[i].mask << 16;
|
||||
if (mask & binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)]) {
|
||||
strncpy(act, me_ctrl_actions[i].name, 31);
|
||||
fprintf(fn, "%s %s = player2 %s" NL, bind_str, name, mystrip(act));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; emuctrl_actions[i].name != NULL; i++) {
|
||||
mask = emuctrl_actions[i].mask;
|
||||
if (mask & binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)]) {
|
||||
strncpy(act, emuctrl_actions[i].name, 31);
|
||||
fprintf(fn, "%s %s = %s" NL, bind_str, name, mystrip(act));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: this should go to menu structures instead */
|
||||
static int default_var(const menu_entry *me)
|
||||
{
|
||||
switch (me->id)
|
||||
{
|
||||
case MA_OPT2_ENABLE_YM2612:
|
||||
case MA_OPT2_ENABLE_SN76496:
|
||||
case MA_OPT2_ENABLE_Z80:
|
||||
case MA_OPT_6BUTTON_PAD:
|
||||
case MA_OPT_ACC_SPRITES:
|
||||
case MA_OPT_ARM940_SOUND:
|
||||
case MA_CDOPT_PCM:
|
||||
case MA_CDOPT_CDDA:
|
||||
case MA_CDOPT_SCALEROT_CHIP:
|
||||
case MA_CDOPT_BETTER_SYNC:
|
||||
case MA_CDOPT_SAVERAM:
|
||||
case MA_32XOPT_ENABLE_32X:
|
||||
case MA_32XOPT_PWM:
|
||||
case MA_OPT2_SVP_DYNAREC:
|
||||
case MA_OPT2_NO_SPRITE_LIM:
|
||||
case MA_OPT2_NO_IDLE_LOOPS:
|
||||
return defaultConfig.s_PicoOpt;
|
||||
|
||||
case MA_OPT_SRAM_STATES:
|
||||
case MA_OPT_SHOW_FPS:
|
||||
case MA_OPT_ENABLE_SOUND:
|
||||
case MA_OPT2_GZIP_STATES:
|
||||
case MA_OPT2_SQUIDGEHACK:
|
||||
case MA_OPT2_NO_LAST_ROM:
|
||||
case MA_OPT2_RAMTIMINGS:
|
||||
case MA_CDOPT_LEDS:
|
||||
case MA_OPT2_A_SN_GAMMA:
|
||||
case MA_OPT2_VSYNC:
|
||||
case MA_OPT_INTERLACED:
|
||||
case MA_OPT2_DBLBUFF:
|
||||
case MA_OPT2_STATUS_LINE:
|
||||
case MA_OPT2_NO_FRAME_LIMIT:
|
||||
case MA_OPT_TEARING_FIX:
|
||||
return defaultConfig.EmuOpt;
|
||||
|
||||
case MA_CTRL_TURBO_RATE: return defaultConfig.turbo_rate;
|
||||
case MA_OPT_SCALING: return defaultConfig.scaling;
|
||||
case MA_OPT_ROTATION: return defaultConfig.rotation;
|
||||
case MA_OPT2_GAMMA: return defaultConfig.gamma;
|
||||
case MA_OPT_FRAMESKIP: return defaultConfig.Frameskip;
|
||||
case MA_OPT_CONFIRM_STATES: return defaultConfig.confirm_save;
|
||||
case MA_OPT_CPU_CLOCKS: return defaultConfig.CPUclock;
|
||||
case MA_OPT_RENDERER: return defaultConfig.renderer;
|
||||
case MA_32XOPT_RENDERER: return defaultConfig.renderer32x;
|
||||
|
||||
case MA_OPT_SAVE_SLOT:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
lprintf("missing default for %d\n", me->id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int is_cust_val_default(const menu_entry *me)
|
||||
{
|
||||
switch (me->id)
|
||||
{
|
||||
case MA_OPT_REGION:
|
||||
return defaultConfig.s_PicoRegion == PicoRegionOverride &&
|
||||
defaultConfig.s_PicoAutoRgnOrder == PicoAutoRgnOrder;
|
||||
case MA_OPT_SOUND_QUALITY:
|
||||
return defaultConfig.s_PsndRate == PsndRate &&
|
||||
((defaultConfig.s_PicoOpt ^ PicoOpt) & POPT_EN_STEREO) == 0;
|
||||
case MA_CDOPT_READAHEAD:
|
||||
return defaultConfig.s_PicoCDBuffers == PicoCDBuffers;
|
||||
case MA_32XOPT_MSH2_CYCLES:
|
||||
return p32x_msh2_multiplier == MSH2_MULTI_DEFAULT;
|
||||
case MA_32XOPT_SSH2_CYCLES:
|
||||
return p32x_ssh2_multiplier == SSH2_MULTI_DEFAULT;
|
||||
default:break;
|
||||
}
|
||||
|
||||
lprintf("is_cust_val_default: unhandled id %i\n", me->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_writesect(const char *fname, const char *section)
|
||||
{
|
||||
FILE *fo = NULL, *fn = NULL; // old and new
|
||||
int no_defaults = 0; // avoid saving defaults
|
||||
menu_entry *me;
|
||||
int t, tlen, ret;
|
||||
char line[128], *tmp;
|
||||
|
||||
if (section != NULL)
|
||||
{
|
||||
no_defaults = 1;
|
||||
|
||||
fo = fopen(fname, "r");
|
||||
if (fo == NULL) {
|
||||
fn = fopen(fname, "w");
|
||||
goto write;
|
||||
}
|
||||
|
||||
ret = seek_sect(fo, section);
|
||||
if (!ret) {
|
||||
// sect not found, we can simply append
|
||||
fclose(fo); fo = NULL;
|
||||
fn = fopen(fname, "a");
|
||||
goto write;
|
||||
}
|
||||
|
||||
// use 2 files..
|
||||
fclose(fo);
|
||||
rename(fname, "tmp.cfg");
|
||||
fo = fopen("tmp.cfg", "r");
|
||||
fn = fopen(fname, "w");
|
||||
if (fo == NULL || fn == NULL) goto write;
|
||||
|
||||
// copy everything until sect
|
||||
tlen = strlen(section);
|
||||
while (!feof(fo))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), fo);
|
||||
if (tmp == NULL) break;
|
||||
|
||||
if (line[0] == '[' && strncmp(line + 1, section, tlen) == 0 && line[tlen+1] == ']')
|
||||
break;
|
||||
fputs(line, fn);
|
||||
}
|
||||
|
||||
// now skip to next sect
|
||||
while (!feof(fo))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), fo);
|
||||
if (tmp == NULL) break;
|
||||
if (line[0] == '[') {
|
||||
fseek(fo, -strlen(line), SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (feof(fo))
|
||||
{
|
||||
fclose(fo); fo = NULL;
|
||||
remove("tmp.cfg");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fn = fopen(fname, "w");
|
||||
}
|
||||
|
||||
write:
|
||||
if (fn == NULL) {
|
||||
if (fo) fclose(fo);
|
||||
return -1;
|
||||
}
|
||||
if (section != NULL)
|
||||
fprintf(fn, "[%s]" NL, section);
|
||||
|
||||
for (me = me_list_get_first(); me != NULL; me = me_list_get_next())
|
||||
{
|
||||
int dummy;
|
||||
if (!me->need_to_save)
|
||||
continue;
|
||||
if (me->name == NULL || me->name[0] == 0)
|
||||
continue;
|
||||
|
||||
if (me->beh == MB_OPT_ONOFF || me->beh == MB_OPT_CUSTONOFF) {
|
||||
if (!no_defaults || ((*(int *)me->var ^ default_var(me)) & me->mask))
|
||||
fprintf(fn, "%s = %i" NL, me->name, (*(int *)me->var & me->mask) ? 1 : 0);
|
||||
}
|
||||
else if (me->beh == MB_OPT_RANGE || me->beh == MB_OPT_CUSTRANGE) {
|
||||
if (!no_defaults || (*(int *)me->var ^ default_var(me)))
|
||||
fprintf(fn, "%s = %i" NL, me->name, *(int *)me->var);
|
||||
}
|
||||
else if (me->beh == MB_OPT_ENUM && me->data != NULL) {
|
||||
const char **names = (const char **)me->data;
|
||||
for (t = 0; names[t] != NULL; t++)
|
||||
if (*(int *)me->var == t && (!no_defaults || (*(int *)me->var ^ default_var(me)))) {
|
||||
strncpy(line, names[t], sizeof(line));
|
||||
goto write_line;
|
||||
}
|
||||
}
|
||||
else if (me->generate_name != NULL) {
|
||||
if (!no_defaults || !is_cust_val_default(me)) {
|
||||
strncpy(line, me->generate_name(0, &dummy), sizeof(line));
|
||||
goto write_line;
|
||||
}
|
||||
}
|
||||
else
|
||||
lprintf("config: unhandled write: %i\n", me->id);
|
||||
continue;
|
||||
|
||||
write_line:
|
||||
line[sizeof(line) - 1] = 0;
|
||||
mystrip(line);
|
||||
fprintf(fn, "%s = %s" NL, me->name, line);
|
||||
}
|
||||
|
||||
/* input: save device names */
|
||||
for (t = 0; t < IN_MAX_DEVS; t++)
|
||||
{
|
||||
const int *binds = in_get_dev_binds(t);
|
||||
const char *name = in_get_dev_name(t, 0, 0);
|
||||
if (binds == NULL || name == NULL)
|
||||
continue;
|
||||
|
||||
fprintf(fn, "input%d = %s" NL, t, name);
|
||||
}
|
||||
|
||||
/* input: save binds */
|
||||
for (t = 0; t < IN_MAX_DEVS; t++)
|
||||
{
|
||||
const int *binds = in_get_dev_binds(t);
|
||||
const char *name = in_get_dev_name(t, 0, 0);
|
||||
char strbind[16];
|
||||
int count = 0;
|
||||
|
||||
if (binds == NULL || name == NULL)
|
||||
continue;
|
||||
|
||||
sprintf(strbind, "bind%d", t);
|
||||
if (t == 0) strbind[4] = 0;
|
||||
|
||||
in_get_config(t, IN_CFG_BIND_COUNT, &count);
|
||||
keys_write(fn, strbind, t, binds, no_defaults);
|
||||
}
|
||||
|
||||
#ifndef PSP
|
||||
if (section == NULL)
|
||||
fprintf(fn, "Sound Volume = %i" NL, currentConfig.volume);
|
||||
#endif
|
||||
|
||||
fprintf(fn, NL);
|
||||
|
||||
if (fo != NULL)
|
||||
{
|
||||
// copy whatever is left
|
||||
while (!feof(fo))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), fo);
|
||||
if (tmp == NULL) break;
|
||||
|
||||
fputs(line, fn);
|
||||
}
|
||||
fclose(fo);
|
||||
remove("tmp.cfg");
|
||||
}
|
||||
|
||||
fclose(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int config_writelrom(const char *fname)
|
||||
{
|
||||
char line[128], *tmp, *optr = NULL;
|
||||
char *old_data = NULL;
|
||||
int size;
|
||||
FILE *f;
|
||||
|
||||
if (strlen(rom_fname_loaded) == 0) return -1;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
old_data = malloc(size + size/8);
|
||||
if (old_data != NULL)
|
||||
{
|
||||
optr = old_data;
|
||||
while (!feof(f))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), f);
|
||||
if (tmp == NULL) break;
|
||||
mystrip(line);
|
||||
if (strncasecmp(line, "LastUsedROM", 11) == 0)
|
||||
continue;
|
||||
sprintf(optr, "%s", line);
|
||||
optr += strlen(optr);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
f = fopen(fname, "w");
|
||||
if (f == NULL) return -1;
|
||||
|
||||
if (old_data != NULL) {
|
||||
fwrite(old_data, 1, optr - old_data, f);
|
||||
free(old_data);
|
||||
}
|
||||
fprintf(f, "LastUsedROM = %s" NL, rom_fname_loaded);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------*/
|
||||
|
||||
int config_readlrom(const char *fname)
|
||||
{
|
||||
char line[128], *tmp;
|
||||
int i, len, ret = -1;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) return -1;
|
||||
|
||||
// seek to the section needed
|
||||
while (!feof(f))
|
||||
{
|
||||
tmp = fgets(line, sizeof(line), f);
|
||||
if (tmp == NULL) break;
|
||||
|
||||
if (strncasecmp(line, "LastUsedROM", 11) != 0) continue;
|
||||
len = strlen(line);
|
||||
for (i = 0; i < len; i++)
|
||||
if (line[i] == '#' || line[i] == '\r' || line[i] == '\n') { line[i] = 0; break; }
|
||||
tmp = strchr(line, '=');
|
||||
if (tmp == NULL) break;
|
||||
tmp++;
|
||||
mystrip(tmp);
|
||||
|
||||
len = sizeof(rom_fname_loaded);
|
||||
strncpy(rom_fname_loaded, tmp, len);
|
||||
rom_fname_loaded[len-1] = 0;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int custom_read(menu_entry *me, const char *var, const char *val)
|
||||
{
|
||||
char *tmp;
|
||||
|
||||
switch (me->id)
|
||||
{
|
||||
case MA_OPT_FRAMESKIP:
|
||||
if (strcasecmp(var, "Frameskip") != 0) return 0;
|
||||
if (strcasecmp(val, "Auto") == 0)
|
||||
currentConfig.Frameskip = -1;
|
||||
else currentConfig.Frameskip = atoi(val);
|
||||
return 1;
|
||||
|
||||
case MA_OPT_SOUND_QUALITY:
|
||||
if (strcasecmp(var, "Sound Quality") != 0) return 0;
|
||||
PsndRate = strtoul(val, &tmp, 10);
|
||||
if (PsndRate < 8000 || PsndRate > 44100)
|
||||
PsndRate = 22050;
|
||||
if (*tmp == 'H' || *tmp == 'h') tmp++;
|
||||
if (*tmp == 'Z' || *tmp == 'z') tmp++;
|
||||
while (*tmp == ' ') tmp++;
|
||||
if (strcasecmp(tmp, "stereo") == 0) {
|
||||
PicoOpt |= POPT_EN_STEREO;
|
||||
} else if (strcasecmp(tmp, "mono") == 0) {
|
||||
PicoOpt &= ~POPT_EN_STEREO;
|
||||
} else
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
case MA_OPT_REGION:
|
||||
if (strcasecmp(var, "Region") != 0) return 0;
|
||||
if (strncasecmp(val, "Auto: ", 6) == 0)
|
||||
{
|
||||
const char *p = val + 5, *end = val + strlen(val);
|
||||
int i;
|
||||
PicoRegionOverride = PicoAutoRgnOrder = 0;
|
||||
for (i = 0; p < end && i < 3; i++)
|
||||
{
|
||||
while (*p == ' ') p++;
|
||||
if (p[0] == 'J' && p[1] == 'P') {
|
||||
PicoAutoRgnOrder |= 1 << (i*4);
|
||||
} else if (p[0] == 'U' && p[1] == 'S') {
|
||||
PicoAutoRgnOrder |= 4 << (i*4);
|
||||
} else if (p[0] == 'E' && p[1] == 'U') {
|
||||
PicoAutoRgnOrder |= 8 << (i*4);
|
||||
}
|
||||
while (*p != ' ' && *p != 0) p++;
|
||||
if (*p == 0) break;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(val, "Auto") == 0) {
|
||||
PicoRegionOverride = 0;
|
||||
} else if (strcasecmp(val, "Japan NTSC") == 0) {
|
||||
PicoRegionOverride = 1;
|
||||
} else if (strcasecmp(val, "Japan PAL") == 0) {
|
||||
PicoRegionOverride = 2;
|
||||
} else if (strcasecmp(val, "USA") == 0) {
|
||||
PicoRegionOverride = 4;
|
||||
} else if (strcasecmp(val, "Europe") == 0) {
|
||||
PicoRegionOverride = 8;
|
||||
} else
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
case MA_OPT2_GAMMA:
|
||||
if (strcasecmp(var, "Gamma correction") != 0) return 0;
|
||||
currentConfig.gamma = (int) (atof(val) * 100.0);
|
||||
return 1;
|
||||
|
||||
case MA_CDOPT_READAHEAD:
|
||||
if (strcasecmp(var, "ReadAhead buffer") != 0) return 0;
|
||||
PicoCDBuffers = atoi(val) / 2;
|
||||
return 1;
|
||||
|
||||
case MA_32XOPT_MSH2_CYCLES:
|
||||
case MA_32XOPT_SSH2_CYCLES: {
|
||||
int *mul = (me->id == MA_32XOPT_MSH2_CYCLES) ? &p32x_msh2_multiplier : &p32x_ssh2_multiplier;
|
||||
*mul = ((unsigned int)atoi(val) << SH2_MULTI_SHIFT) / 7670;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* PSP */
|
||||
case MA_OPT3_SCALE:
|
||||
if (strcasecmp(var, "Scale factor") != 0) return 0;
|
||||
currentConfig.scale = atof(val);
|
||||
return 1;
|
||||
case MA_OPT3_HSCALE32:
|
||||
if (strcasecmp(var, "Hor. scale (for low res. games)") != 0) return 0;
|
||||
currentConfig.hscale32 = atof(val);
|
||||
return 1;
|
||||
case MA_OPT3_HSCALE40:
|
||||
if (strcasecmp(var, "Hor. scale (for hi res. games)") != 0) return 0;
|
||||
currentConfig.hscale40 = atof(val);
|
||||
return 1;
|
||||
case MA_OPT3_VSYNC:
|
||||
// XXX: use enum
|
||||
if (strcasecmp(var, "Wait for vsync") != 0) return 0;
|
||||
if (strcasecmp(val, "never") == 0) {
|
||||
currentConfig.EmuOpt &= ~0x12000;
|
||||
} else if (strcasecmp(val, "sometimes") == 0) {
|
||||
currentConfig.EmuOpt |= 0x12000;
|
||||
} else if (strcasecmp(val, "always") == 0) {
|
||||
currentConfig.EmuOpt &= ~0x12000;
|
||||
currentConfig.EmuOpt |= 0x02000;
|
||||
} else
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
lprintf("unhandled custom_read %i: %s\n", me->id, var);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned int keys_encountered = 0;
|
||||
|
||||
static int parse_bind_val(const char *val, int *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
*type = IN_BINDTYPE_NONE;
|
||||
if (val[0] == 0)
|
||||
return 0;
|
||||
|
||||
if (strncasecmp(val, "player", 6) == 0)
|
||||
{
|
||||
int player, shift = 0;
|
||||
player = atoi(val + 6) - 1;
|
||||
|
||||
if (player > 1)
|
||||
return -1;
|
||||
if (player == 1)
|
||||
shift = 16;
|
||||
|
||||
*type = IN_BINDTYPE_PLAYER12;
|
||||
for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
|
||||
if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
|
||||
return me_ctrl_actions[i].mask << shift;
|
||||
}
|
||||
}
|
||||
for (i = 0; emuctrl_actions[i].name != NULL; i++) {
|
||||
if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
|
||||
*type = IN_BINDTYPE_EMU;
|
||||
return emuctrl_actions[i].mask;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void keys_parse(const char *key, const char *val, int dev_id)
|
||||
{
|
||||
int acts, type;
|
||||
|
||||
acts = parse_bind_val(val, &type);
|
||||
if (acts == -1) {
|
||||
lprintf("config: unhandled action \"%s\"\n", val);
|
||||
return;
|
||||
}
|
||||
|
||||
in_config_bind_key(dev_id, key, acts, type);
|
||||
}
|
||||
|
||||
static int get_numvar_num(const char *var)
|
||||
{
|
||||
char *p = NULL;
|
||||
int num;
|
||||
|
||||
if (var[0] == ' ')
|
||||
return 0;
|
||||
|
||||
num = strtoul(var, &p, 10);
|
||||
if (*p == 0 || *p == ' ')
|
||||
return num;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* map dev number in confing to input dev number */
|
||||
static unsigned char input_dev_map[IN_MAX_DEVS];
|
||||
|
||||
static void parse(const char *var, const char *val)
|
||||
{
|
||||
menu_entry *me;
|
||||
int tmp;
|
||||
|
||||
if (strcasecmp(var, "LastUsedROM") == 0)
|
||||
return; /* handled elsewhere */
|
||||
|
||||
if (strcasecmp(var, "Sound Volume") == 0) {
|
||||
currentConfig.volume = atoi(val);
|
||||
return;
|
||||
}
|
||||
|
||||
/* input: device name */
|
||||
if (strncasecmp(var, "input", 5) == 0) {
|
||||
int num = get_numvar_num(var + 5);
|
||||
if (num >= 0 && num < IN_MAX_DEVS)
|
||||
input_dev_map[num] = in_config_parse_dev(val);
|
||||
else
|
||||
lprintf("config: failed to parse: %s\n", var);
|
||||
return;
|
||||
}
|
||||
|
||||
// key binds
|
||||
if (strncasecmp(var, "bind", 4) == 0) {
|
||||
const char *p = var + 4;
|
||||
int num = get_numvar_num(p);
|
||||
if (num < 0 || num >= IN_MAX_DEVS) {
|
||||
lprintf("config: failed to parse: %s\n", var);
|
||||
return;
|
||||
}
|
||||
|
||||
num = input_dev_map[num];
|
||||
if (num < 0 || num >= IN_MAX_DEVS) {
|
||||
lprintf("config: invalid device id: %s\n", var);
|
||||
return;
|
||||
}
|
||||
|
||||
while (*p && *p != ' ') p++;
|
||||
while (*p && *p == ' ') p++;
|
||||
keys_parse(p, val, num);
|
||||
return;
|
||||
}
|
||||
|
||||
for (me = me_list_get_first(); me != NULL; me = me_list_get_next())
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!me->need_to_save)
|
||||
continue;
|
||||
if (me->name == NULL || strcasecmp(var, me->name) != 0)
|
||||
continue;
|
||||
|
||||
if (me->beh == MB_OPT_ONOFF) {
|
||||
tmp = strtol(val, &p, 0);
|
||||
if (*p != 0)
|
||||
goto bad_val;
|
||||
if (tmp) *(int *)me->var |= me->mask;
|
||||
else *(int *)me->var &= ~me->mask;
|
||||
return;
|
||||
}
|
||||
else if (me->beh == MB_OPT_RANGE) {
|
||||
tmp = strtol(val, &p, 0);
|
||||
if (*p != 0)
|
||||
goto bad_val;
|
||||
if (tmp < me->min) tmp = me->min;
|
||||
if (tmp > me->max) tmp = me->max;
|
||||
*(int *)me->var = tmp;
|
||||
return;
|
||||
}
|
||||
else if (me->beh == MB_OPT_ENUM) {
|
||||
const char **names, *p1;
|
||||
int i;
|
||||
|
||||
names = (const char **)me->data;
|
||||
if (names == NULL)
|
||||
goto bad_val;
|
||||
for (i = 0; names[i] != NULL; i++) {
|
||||
for (p1 = names[i]; *p1 == ' '; p1++)
|
||||
;
|
||||
if (strcasecmp(p1, val) == 0) {
|
||||
*(int *)me->var = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
goto bad_val;
|
||||
}
|
||||
else if (custom_read(me, var, val))
|
||||
return;
|
||||
}
|
||||
|
||||
lprintf("config_readsect: unhandled var: \"%s\"\n", var);
|
||||
return;
|
||||
|
||||
bad_val:
|
||||
lprintf("config_readsect: unhandled val for \"%s\": %s\n", var, val);
|
||||
}
|
||||
|
||||
|
||||
int config_havesect(const char *fname, const char *section)
|
||||
{
|
||||
FILE *f;
|
||||
int ret;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) return 0;
|
||||
|
||||
ret = seek_sect(f, section);
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int config_readsect(const char *fname, const char *section)
|
||||
{
|
||||
char line[128], *var, *val;
|
||||
FILE *f;
|
||||
int ret;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) return -1;
|
||||
|
||||
if (section != NULL)
|
||||
{
|
||||
ret = seek_sect(f, section);
|
||||
if (!ret) {
|
||||
lprintf("config_readsect: %s: missing section [%s]\n", fname, section);
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
keys_encountered = 0;
|
||||
memset(input_dev_map, 0xff, sizeof(input_dev_map));
|
||||
|
||||
while (!feof(f))
|
||||
{
|
||||
ret = config_get_var_val(f, line, sizeof(line), &var, &val);
|
||||
if (ret == 0) break;
|
||||
if (ret == -1) continue;
|
||||
|
||||
parse(var, val);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
static char *mystrip(char *str)
|
||||
{
|
||||
int i, len;
|
||||
|
||||
len = strlen(str);
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] != ' ') break;
|
||||
if (i > 0) memmove(str, str + i, len - i + 1);
|
||||
|
||||
len = strlen(str);
|
||||
for (i = len - 1; i >= 0; i--)
|
||||
if (str[i] != ' ') break;
|
||||
str[i+1] = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* returns:
|
||||
* 0 - EOF, end
|
||||
* 1 - parsed ok
|
||||
* -1 - failed to parse line
|
||||
*/
|
||||
int config_get_var_val(void *file, char *line, int lsize, char **rvar, char **rval)
|
||||
{
|
||||
char *var, *val, *tmp;
|
||||
FILE *f = file;
|
||||
int len, i;
|
||||
|
||||
tmp = fgets(line, lsize, f);
|
||||
if (tmp == NULL) return 0;
|
||||
|
||||
if (line[0] == '[') return 0; // other section
|
||||
|
||||
// strip comments, linefeed, spaces..
|
||||
len = strlen(line);
|
||||
for (i = 0; i < len; i++)
|
||||
if (line[i] == '#' || line[i] == '\r' || line[i] == '\n') { line[i] = 0; break; }
|
||||
mystrip(line);
|
||||
len = strlen(line);
|
||||
if (len <= 0) return -1;;
|
||||
|
||||
// get var and val
|
||||
for (i = 0; i < len; i++)
|
||||
if (line[i] == '=') break;
|
||||
if (i >= len || strchr(&line[i+1], '=') != NULL) {
|
||||
lprintf("config_readsect: can't parse: %s\n", line);
|
||||
return -1;
|
||||
}
|
||||
line[i] = 0;
|
||||
var = line;
|
||||
val = &line[i+1];
|
||||
mystrip(var);
|
||||
mystrip(val);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
if (strlen(var) == 0 || (strlen(val) == 0 && strncasecmp(var, "bind", 4) != 0)) {
|
||||
lprintf("config_readsect: something's empty: \"%s\" = \"%s\"\n", var, val);
|
||||
return -1;;
|
||||
}
|
||||
#endif
|
||||
|
||||
*rvar = var;
|
||||
*rval = val;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int config_writesect(const char *fname, const char *section);
|
||||
int config_writelrom(const char *fname);
|
||||
int config_readsect(const char *fname, const char *section);
|
||||
int config_readlrom(const char *fname);
|
||||
int config_havesect(const char *fname, const char *section);
|
||||
int config_get_var_val(void *file, char *line, int lsize, char **rvar, char **rval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
1636
common/emu.c
1636
common/emu.c
File diff suppressed because it is too large
Load diff
155
common/emu.h
155
common/emu.h
|
@ -1,155 +0,0 @@
|
|||
// (c) Copyright 2006-2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include "port_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define array_size(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
extern void *g_screen_ptr;
|
||||
|
||||
#if SCREEN_SIZE_FIXED
|
||||
#define g_screen_width SCREEN_WIDTH
|
||||
#define g_screen_height SCREEN_HEIGHT
|
||||
#else
|
||||
extern int g_screen_width;
|
||||
extern int g_screen_height;
|
||||
#endif
|
||||
|
||||
|
||||
#define EOPT_EN_SRAM (1<<0)
|
||||
#define EOPT_SHOW_FPS (1<<1)
|
||||
#define EOPT_EN_SOUND (1<<2)
|
||||
#define EOPT_GZIP_SAVES (1<<3)
|
||||
#define EOPT_MMUHACK (1<<4)
|
||||
#define EOPT_NO_AUTOSVCFG (1<<5)
|
||||
#define EOPT_16BPP (1<<7) // depreceted for .renderer
|
||||
#define EOPT_RAM_TIMINGS (1<<8)
|
||||
#define EOPT_EN_CD_LEDS (1<<10)
|
||||
#define EOPT_A_SN_GAMMA (1<<12)
|
||||
#define EOPT_VSYNC (1<<13)
|
||||
#define EOPT_GIZ_SCANLN (1<<14)
|
||||
#define EOPT_GIZ_DBLBUF (1<<15)
|
||||
#define EOPT_VSYNC_MODE (1<<16)
|
||||
#define EOPT_SHOW_RTC (1<<17)
|
||||
#define EOPT_NO_FRMLIMIT (1<<18)
|
||||
#define EOPT_WIZ_TEAR_FIX (1<<19)
|
||||
#define EOPT_EXT_FRMLIMIT (1<<20) // no internal frame limiter (limited by snd, etc)
|
||||
|
||||
enum {
|
||||
EOPT_SCALE_NONE = 0,
|
||||
EOPT_SCALE_SW,
|
||||
EOPT_SCALE_HW,
|
||||
};
|
||||
|
||||
enum {
|
||||
EOPT_CONFIRM_NONE = 0,
|
||||
EOPT_CONFIRM_SAVE = 1,
|
||||
EOPT_CONFIRM_LOAD = 2,
|
||||
EOPT_CONFIRM_BOTH = 3,
|
||||
};
|
||||
|
||||
typedef struct _currentConfig_t {
|
||||
int EmuOpt;
|
||||
int s_PicoOpt;
|
||||
int s_PsndRate;
|
||||
int s_PicoRegion;
|
||||
int s_PicoAutoRgnOrder;
|
||||
int s_PicoCDBuffers;
|
||||
int Frameskip;
|
||||
int confirm_save;
|
||||
int CPUclock;
|
||||
int volume;
|
||||
int gamma;
|
||||
int scaling; // gp2x: EOPT_SCALE_*; psp: bilinear filtering
|
||||
int vscaling;
|
||||
int rotation; // for UIQ
|
||||
float scale; // psp: screen scale
|
||||
float hscale32, hscale40; // psp: horizontal scale
|
||||
int gamma2; // psp: black level
|
||||
int turbo_rate;
|
||||
int renderer;
|
||||
int renderer32x;
|
||||
int filter; // pandora
|
||||
int analog_deadzone;
|
||||
} currentConfig_t;
|
||||
|
||||
extern currentConfig_t currentConfig, defaultConfig;
|
||||
extern char *PicoConfigFile;
|
||||
extern int rom_loaded;
|
||||
extern int state_slot;
|
||||
extern int config_slot, config_slot_current;
|
||||
extern unsigned char *movie_data;
|
||||
extern int reset_timing;
|
||||
|
||||
#define PICO_PEN_ADJUST_X 4
|
||||
#define PICO_PEN_ADJUST_Y 2
|
||||
extern int pico_pen_x, pico_pen_y;
|
||||
extern int pico_inp_mode;
|
||||
|
||||
extern char rom_fname_reload[512]; // ROM to try loading on next PGS_ReloadRom
|
||||
extern char rom_fname_loaded[512]; // currently loaded ROM filename
|
||||
|
||||
// engine states
|
||||
extern int engineState;
|
||||
enum TPicoGameState {
|
||||
PGS_Paused = 1,
|
||||
PGS_Running,
|
||||
PGS_Quit,
|
||||
PGS_KeyConfig,
|
||||
PGS_ReloadRom,
|
||||
PGS_Menu,
|
||||
PGS_TrayMenu,
|
||||
PGS_RestartRun,
|
||||
PGS_Suspending, /* PSP */
|
||||
PGS_SuspendWake, /* PSP */
|
||||
};
|
||||
|
||||
// media types
|
||||
enum {
|
||||
PM_BAD = 0,
|
||||
PM_MD_CART, /* also 32x */
|
||||
PM_MARK3,
|
||||
PM_CD,
|
||||
};
|
||||
|
||||
void emu_init(void);
|
||||
void emu_finish(void);
|
||||
void emu_loop(void);
|
||||
|
||||
int emu_reload_rom(char *rom_fname);
|
||||
int emu_swap_cd(const char *fname);
|
||||
int emu_save_load_game(int load, int sram);
|
||||
void emu_reset_game(void);
|
||||
|
||||
void emu_prep_defconfig(void);
|
||||
void emu_set_defconfig(void);
|
||||
int emu_read_config(const char *rom_fname, int no_defaults);
|
||||
int emu_write_config(int game);
|
||||
|
||||
char *emu_get_save_fname(int load, int is_sram, int slot);
|
||||
int emu_check_save_file(int slot, int *time);
|
||||
|
||||
void emu_text_out8 (int x, int y, const char *text);
|
||||
void emu_text_out16(int x, int y, const char *text);
|
||||
void emu_text_out8_rot (int x, int y, const char *text);
|
||||
void emu_text_out16_rot(int x, int y, const char *text);
|
||||
|
||||
void emu_make_path(char *buff, const char *end, int size);
|
||||
void emu_update_input(void);
|
||||
void emu_get_game_name(char *str150);
|
||||
void emu_set_fastforward(int set_on);
|
||||
void emu_status_msg(const char *format, ...);
|
||||
|
||||
/* used by some (but not all) platforms */
|
||||
void emu_cmn_forced_frame(int no_scale, int do_emu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
148
common/main.c
148
common/main.c
|
@ -1,148 +0,0 @@
|
|||
// (c) Copyright 2006-2009 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "menu.h"
|
||||
#include "emu.h"
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "plat.h"
|
||||
#include <cpu/debug.h>
|
||||
#include <version.h>
|
||||
|
||||
|
||||
extern char *PicoConfigFile;
|
||||
static int load_state_slot = -1;
|
||||
char **g_argv;
|
||||
|
||||
void parse_cmd_line(int argc, char *argv[])
|
||||
{
|
||||
int x, unrecognized = 0;
|
||||
|
||||
for (x = 1; x < argc; x++)
|
||||
{
|
||||
if (argv[x][0] == '-')
|
||||
{
|
||||
if (strcasecmp(argv[x], "-config") == 0) {
|
||||
if (x+1 < argc) { ++x; PicoConfigFile = argv[x]; }
|
||||
}
|
||||
else if (strcasecmp(argv[x], "-loadstate") == 0) {
|
||||
if (x+1 < argc) { ++x; load_state_slot = atoi(argv[x]); }
|
||||
}
|
||||
else if (strcasecmp(argv[x], "-pdb") == 0) {
|
||||
if (x+1 < argc) { ++x; pdb_command(argv[x]); }
|
||||
}
|
||||
else if (strcasecmp(argv[x], "-pdb_connect") == 0) {
|
||||
if (x+2 < argc) { pdb_net_connect(argv[x+1], argv[x+2]); x += 2; }
|
||||
}
|
||||
else {
|
||||
unrecognized = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* External Frontend: ROM Name */
|
||||
FILE *f;
|
||||
strncpy(rom_fname_reload, argv[x], sizeof(rom_fname_reload));
|
||||
rom_fname_reload[sizeof(rom_fname_reload) - 1] = 0;
|
||||
f = fopen(rom_fname_reload, "rb");
|
||||
if (f) fclose(f);
|
||||
else unrecognized = 1;
|
||||
engineState = PGS_ReloadRom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unrecognized) {
|
||||
printf("\n\n\nPicoDrive v" VERSION " (c) notaz, 2006-2009\n");
|
||||
printf("usage: %s [options] [romfile]\n", argv[0]);
|
||||
printf("options:\n"
|
||||
" -config <file> use specified config file instead of default 'config.cfg'\n"
|
||||
" -loadstate <num> if ROM is specified, try loading slot <num>\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
g_argv = argv;
|
||||
|
||||
plat_early_init();
|
||||
|
||||
in_init();
|
||||
in_probe();
|
||||
|
||||
plat_init();
|
||||
|
||||
emu_prep_defconfig(); // depends on input
|
||||
emu_read_config(NULL, 0);
|
||||
|
||||
emu_init();
|
||||
menu_init();
|
||||
|
||||
engineState = PGS_Menu;
|
||||
|
||||
if (argc > 1)
|
||||
parse_cmd_line(argc, argv);
|
||||
|
||||
if (engineState == PGS_ReloadRom)
|
||||
{
|
||||
if (emu_reload_rom(rom_fname_reload)) {
|
||||
engineState = PGS_Running;
|
||||
if (load_state_slot >= 0) {
|
||||
state_slot = load_state_slot;
|
||||
emu_save_load_game(1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (engineState)
|
||||
{
|
||||
case PGS_Menu:
|
||||
menu_loop();
|
||||
break;
|
||||
|
||||
case PGS_TrayMenu:
|
||||
menu_loop_tray();
|
||||
break;
|
||||
|
||||
case PGS_ReloadRom:
|
||||
if (emu_reload_rom(rom_fname_reload))
|
||||
engineState = PGS_Running;
|
||||
else {
|
||||
printf("PGS_ReloadRom == 0\n");
|
||||
engineState = PGS_Menu;
|
||||
}
|
||||
break;
|
||||
|
||||
case PGS_RestartRun:
|
||||
engineState = PGS_Running;
|
||||
/* vvv fallthrough */
|
||||
|
||||
case PGS_Running:
|
||||
emu_loop();
|
||||
break;
|
||||
|
||||
case PGS_Quit:
|
||||
goto endloop;
|
||||
|
||||
default:
|
||||
printf("engine got into unknown state (%i), exitting\n", engineState);
|
||||
goto endloop;
|
||||
}
|
||||
}
|
||||
|
||||
endloop:
|
||||
|
||||
emu_finish();
|
||||
plat_finish();
|
||||
|
||||
return 0;
|
||||
}
|
1080
common/menu_pico.c
1080
common/menu_pico.c
File diff suppressed because it is too large
Load diff
|
@ -1,94 +0,0 @@
|
|||
typedef enum
|
||||
{
|
||||
MA_NONE = 1,
|
||||
MA_MAIN_RESUME_GAME,
|
||||
MA_MAIN_SAVE_STATE,
|
||||
MA_MAIN_LOAD_STATE,
|
||||
MA_MAIN_RESET_GAME,
|
||||
MA_MAIN_LOAD_ROM,
|
||||
MA_MAIN_CONTROLS,
|
||||
MA_MAIN_CREDITS,
|
||||
MA_MAIN_PATCHES,
|
||||
MA_MAIN_EXIT,
|
||||
MA_OPT_RENDERER,
|
||||
MA_OPT_SCALING,
|
||||
MA_OPT_VSCALING,
|
||||
MA_OPT_ACC_SPRITES,
|
||||
MA_OPT_SHOW_FPS,
|
||||
MA_OPT_FRAMESKIP,
|
||||
MA_OPT_ENABLE_SOUND,
|
||||
MA_OPT_SOUND_QUALITY,
|
||||
MA_OPT_ARM940_SOUND,
|
||||
MA_OPT_6BUTTON_PAD,
|
||||
MA_OPT_REGION,
|
||||
MA_OPT_SRAM_STATES,
|
||||
MA_OPT_CONFIRM_STATES,
|
||||
MA_OPT_SAVE_SLOT,
|
||||
MA_OPT_CPU_CLOCKS,
|
||||
MA_OPT_SCD_OPTS,
|
||||
MA_OPT_ADV_OPTS,
|
||||
MA_OPT_DISP_OPTS, /* psp */
|
||||
MA_OPT_SAVECFG,
|
||||
MA_OPT_SAVECFG_GAME,
|
||||
MA_OPT_LOADCFG,
|
||||
MA_OPT_INTERLACED, /* giz */
|
||||
MA_OPT_ROTATION, /* uiq */
|
||||
MA_OPT_TEARING_FIX, /* wiz */
|
||||
MA_OPT2_GAMMA,
|
||||
MA_OPT2_A_SN_GAMMA,
|
||||
MA_OPT2_DBLBUFF, /* giz */
|
||||
MA_OPT2_VSYNC,
|
||||
MA_OPT2_ENABLE_Z80,
|
||||
MA_OPT2_ENABLE_YM2612,
|
||||
MA_OPT2_ENABLE_SN76496,
|
||||
MA_OPT2_GZIP_STATES,
|
||||
MA_OPT2_NO_LAST_ROM,
|
||||
MA_OPT2_RAMTIMINGS, /* gp2x */
|
||||
MA_OPT2_SQUIDGEHACK, /* gp2x */
|
||||
MA_OPT2_STATUS_LINE, /* psp */
|
||||
MA_OPT2_NO_FRAME_LIMIT, /* psp */
|
||||
MA_OPT2_SVP_DYNAREC,
|
||||
MA_OPT2_NO_SPRITE_LIM,
|
||||
MA_OPT2_NO_IDLE_LOOPS,
|
||||
MA_OPT2_DONE,
|
||||
MA_OPT3_SCALE, /* psp (all OPT3) */
|
||||
MA_OPT3_HSCALE32,
|
||||
MA_OPT3_HSCALE40,
|
||||
MA_OPT3_PRES_NOSCALE,
|
||||
MA_OPT3_PRES_SCALE43,
|
||||
MA_OPT3_PRES_FULLSCR,
|
||||
MA_OPT3_FILTERING,
|
||||
MA_OPT3_VSYNC,
|
||||
MA_OPT3_GAMMAA,
|
||||
MA_OPT3_BLACKLVL,
|
||||
MA_OPT3_LAYER_X,
|
||||
MA_OPT3_LAYER_Y,
|
||||
MA_OPT3_LAYER_W,
|
||||
MA_OPT3_LAYER_H,
|
||||
MA_OPT3_DONE,
|
||||
MA_CDOPT_TESTBIOS_USA,
|
||||
MA_CDOPT_TESTBIOS_EUR,
|
||||
MA_CDOPT_TESTBIOS_JAP,
|
||||
MA_CDOPT_LEDS,
|
||||
MA_CDOPT_CDDA,
|
||||
MA_CDOPT_PCM,
|
||||
MA_CDOPT_READAHEAD,
|
||||
MA_CDOPT_SAVERAM,
|
||||
MA_CDOPT_SCALEROT_CHIP,
|
||||
MA_CDOPT_BETTER_SYNC,
|
||||
MA_CDOPT_DONE,
|
||||
MA_32XOPT_ENABLE_32X,
|
||||
MA_32XOPT_RENDERER,
|
||||
MA_32XOPT_PWM,
|
||||
MA_32XOPT_MSH2_CYCLES,
|
||||
MA_32XOPT_SSH2_CYCLES,
|
||||
MA_CTRL_PLAYER1,
|
||||
MA_CTRL_PLAYER2,
|
||||
MA_CTRL_EMU,
|
||||
MA_CTRL_TURBO_RATE,
|
||||
MA_CTRL_DEADZONE,
|
||||
MA_CTRL_DEV_FIRST,
|
||||
MA_CTRL_DEV_NEXT,
|
||||
MA_CTRL_DONE,
|
||||
} menu_id;
|
||||
|
29
common/mp3.c
29
common/mp3.c
|
@ -1,29 +0,0 @@
|
|||
#include "mp3.h"
|
||||
|
||||
int mp3_find_sync_word(const unsigned char *buf, int size)
|
||||
{
|
||||
const unsigned char *p, *pe;
|
||||
|
||||
/* find byte-aligned syncword - need 12 (MPEG 1,2) or 11 (MPEG 2.5) matching bits */
|
||||
for (p = buf, pe = buf + size - 3; p <= pe; p++)
|
||||
{
|
||||
int pn;
|
||||
if (p[0] != 0xff)
|
||||
continue;
|
||||
pn = p[1];
|
||||
if ((pn & 0xf8) != 0xf8 || // currently must be MPEG1
|
||||
(pn & 6) == 0) { // invalid layer
|
||||
p++; continue;
|
||||
}
|
||||
pn = p[2];
|
||||
if ((pn & 0xf0) < 0x20 || (pn & 0xf0) == 0xf0 || // bitrates
|
||||
(pn & 0x0c) != 0) { // not 44kHz
|
||||
continue;
|
||||
}
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
int mp3_find_sync_word(const unsigned char *buf, int size);
|
||||
|
||||
#ifdef __GP2X__
|
||||
void mp3_update_local(int *buffer, int length, int stereo);
|
||||
void mp3_start_play_local(void *f, int pos);
|
||||
#endif
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
// Some mp3 related code for Sega/Mega CD.
|
||||
// Uses the Helix Fixed-point MP3 decoder
|
||||
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
#include <pico/sound/mix.h>
|
||||
#include "helix/pub/mp3dec.h"
|
||||
#include "mp3.h"
|
||||
#include "lprintf.h"
|
||||
|
||||
static HMP3Decoder mp3dec = 0;
|
||||
static FILE *mp3_current_file = NULL;
|
||||
static int mp3_file_len = 0, mp3_file_pos = 0;
|
||||
static int mp3_buffer_offs = 0;
|
||||
static unsigned char mp3_input_buffer[2*1024];
|
||||
|
||||
#ifdef __GP2X__
|
||||
#define mp3_update mp3_update_local
|
||||
#define mp3_start_play mp3_start_play_local
|
||||
#endif
|
||||
|
||||
static int try_get_header(unsigned char *buff, MP3FrameInfo *fi)
|
||||
{
|
||||
int ret, offs1, offs = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
offs1 = mp3_find_sync_word(buff + offs, 2048 - offs);
|
||||
if (offs1 < 0) return -2;
|
||||
offs += offs1;
|
||||
if (2048 - offs < 4) return -3;
|
||||
|
||||
// printf("trying header %08x\n", *(int *)(buff + offs));
|
||||
|
||||
ret = MP3GetNextFrameInfo(mp3dec, fi, buff + offs);
|
||||
if (ret == 0 && fi->bitrate != 0) break;
|
||||
offs++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mp3_get_bitrate(void *f_, int len)
|
||||
{
|
||||
unsigned char buff[2048];
|
||||
MP3FrameInfo fi;
|
||||
FILE *f = f_;
|
||||
int ret;
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
if (mp3dec)
|
||||
MP3FreeDecoder(mp3dec);
|
||||
mp3dec = MP3InitDecoder();
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
ret = fread(buff, 1, sizeof(buff), f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if (ret <= 0)
|
||||
return -1;
|
||||
|
||||
ret = try_get_header(buff, &fi);
|
||||
if (ret != 0 || fi.bitrate == 0) {
|
||||
// try to read somewhere around the middle
|
||||
fseek(f, len>>1, SEEK_SET);
|
||||
fread(buff, 1, 2048, f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
ret = try_get_header(buff, &fi);
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
// printf("bitrate: %i\n", fi.bitrate / 1000);
|
||||
|
||||
return fi.bitrate / 1000;
|
||||
}
|
||||
|
||||
static int mp3_decode(void)
|
||||
{
|
||||
unsigned char *readPtr;
|
||||
int bytesLeft;
|
||||
int offset; // mp3 frame offset from readPtr
|
||||
int had_err;
|
||||
int err = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (mp3_file_pos >= mp3_file_len)
|
||||
return 1; /* EOF, nothing to do */
|
||||
|
||||
fseek(mp3_current_file, mp3_file_pos, SEEK_SET);
|
||||
bytesLeft = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), mp3_current_file);
|
||||
|
||||
offset = mp3_find_sync_word(mp3_input_buffer, bytesLeft);
|
||||
if (offset < 0) {
|
||||
lprintf("find_sync_word (%i/%i) err %i\n", mp3_file_pos, mp3_file_len, offset);
|
||||
mp3_file_pos = mp3_file_len;
|
||||
return 1; // EOF
|
||||
}
|
||||
readPtr = mp3_input_buffer + offset;
|
||||
bytesLeft -= offset;
|
||||
|
||||
had_err = err;
|
||||
err = MP3Decode(mp3dec, &readPtr, &bytesLeft, cdda_out_buffer, 0);
|
||||
if (err) {
|
||||
if (err == ERR_MP3_MAINDATA_UNDERFLOW && !had_err) {
|
||||
// just need another frame
|
||||
mp3_file_pos += readPtr - mp3_input_buffer;
|
||||
continue;
|
||||
}
|
||||
if (err == ERR_MP3_INDATA_UNDERFLOW && !had_err) {
|
||||
if (offset == 0)
|
||||
// something's really wrong here, frame had to fit
|
||||
mp3_file_pos = mp3_file_len;
|
||||
else
|
||||
mp3_file_pos += offset;
|
||||
continue;
|
||||
}
|
||||
if (-12 <= err && err <= -6) {
|
||||
// ERR_MP3_INVALID_FRAMEHEADER, ERR_MP3_INVALID_*
|
||||
// just try to skip the offending frame..
|
||||
mp3_file_pos += offset + 1;
|
||||
continue;
|
||||
}
|
||||
lprintf("MP3Decode err (%i/%i) %i\n", mp3_file_pos, mp3_file_len, err);
|
||||
mp3_file_pos = mp3_file_len;
|
||||
return 1;
|
||||
}
|
||||
mp3_file_pos += readPtr - mp3_input_buffer;
|
||||
}
|
||||
while (0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mp3_start_play(void *f_, int pos)
|
||||
{
|
||||
FILE *f = f_;
|
||||
|
||||
mp3_file_len = mp3_file_pos = 0;
|
||||
mp3_current_file = NULL;
|
||||
mp3_buffer_offs = 0;
|
||||
|
||||
if (!(PicoOpt & POPT_EN_MCD_CDDA) || f == NULL) // cdda disabled or no file?
|
||||
return;
|
||||
|
||||
// must re-init decoder for new track
|
||||
if (mp3dec)
|
||||
MP3FreeDecoder(mp3dec);
|
||||
mp3dec = MP3InitDecoder();
|
||||
|
||||
mp3_current_file = f;
|
||||
fseek(f, 0, SEEK_END);
|
||||
mp3_file_len = ftell(f);
|
||||
|
||||
// search for first sync word, skipping stuff like ID3 tags
|
||||
while (mp3_file_pos < 128*1024) {
|
||||
int offs, bytes;
|
||||
|
||||
fseek(f, mp3_file_pos, SEEK_SET);
|
||||
bytes = fread(mp3_input_buffer, 1, sizeof(mp3_input_buffer), f);
|
||||
if (bytes < 4)
|
||||
break;
|
||||
offs = mp3_find_sync_word(mp3_input_buffer, bytes);
|
||||
if (offs >= 0) {
|
||||
mp3_file_pos += offs;
|
||||
break;
|
||||
}
|
||||
mp3_file_pos += bytes - 2;
|
||||
}
|
||||
|
||||
// seek..
|
||||
if (pos) {
|
||||
unsigned long long pos64 = mp3_file_len - mp3_file_pos;
|
||||
pos64 *= pos;
|
||||
mp3_file_pos += pos64 >> 10;
|
||||
}
|
||||
|
||||
mp3_decode();
|
||||
}
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
int length_mp3, shr = 0;
|
||||
void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;
|
||||
|
||||
if (mp3_current_file == NULL || mp3_file_pos >= mp3_file_len)
|
||||
return; /* no file / EOF */
|
||||
|
||||
length_mp3 = length;
|
||||
if (PsndRate <= 11025 + 100) {
|
||||
mix_samples = mix_16h_to_32_s2;
|
||||
length_mp3 <<= 2; shr = 2;
|
||||
}
|
||||
else if (PsndRate <= 22050 + 100) {
|
||||
mix_samples = mix_16h_to_32_s1;
|
||||
length_mp3 <<= 1; shr = 1;
|
||||
}
|
||||
|
||||
if (1152 - mp3_buffer_offs >= length_mp3) {
|
||||
mix_samples(buffer, cdda_out_buffer + mp3_buffer_offs*2, length<<1);
|
||||
|
||||
mp3_buffer_offs += length_mp3;
|
||||
} else {
|
||||
int ret, left = 1152 - mp3_buffer_offs;
|
||||
|
||||
mix_samples(buffer, cdda_out_buffer + mp3_buffer_offs*2, (left>>shr)<<1);
|
||||
ret = mp3_decode();
|
||||
if (ret == 0) {
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mix_samples(buffer + ((left>>shr)<<1), cdda_out_buffer, (mp3_buffer_offs>>shr)<<1);
|
||||
} else
|
||||
mp3_buffer_offs = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
platform/common/menu.o : revision.h
|
||||
|
||||
revision.h: FORCE
|
||||
ifndef NOREVISION
|
||||
@echo "#define REVISION \"`svn info -r HEAD | grep Revision | cut -c 11-`\"" > /tmp/r.tmp
|
||||
else
|
||||
@echo "#define REVISION \"0\"" > /tmp/r.tmp
|
||||
endif
|
||||
@diff -q $@ /tmp/r.tmp > /dev/null 2>&1 || mv -f /tmp/r.tmp $@
|
||||
|
||||
FORCE:
|
||||
|
166
game_def.cfg
166
game_def.cfg
|
@ -1,166 +0,0 @@
|
|||
#
|
||||
# Sega/Mega CD games
|
||||
#
|
||||
|
||||
[CD|GM MK-4432 -00|U|ADVENTURES OF BA]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM T-60055-00|U|AH3-THUNDERSTRIKE]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM MK-4401 -00|U|BATMAN RETURNS]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM T-115075-00|U|BCRACERS]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM MK-4402|U|COBRA COMMAND]
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM T-121015-00|U|DRAGONS LAIR]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-60094|J|JAGUAR XJ220]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-127015-00|U|LUNAR]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM T-111065 -0|U|MAD DOG II THE LOST GOLD]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-11105 -00|U|MAD DOG MCCREE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-81025-00|U|MORTAL KOMBAT]
|
||||
Renderer = 16bit accurate
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM T-04903-01|U|NIGHT TRAP]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-113025-00|U|NOVASTORM]
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM T-127035-00|U|Popful MAIL]
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|MK 4603-50|JUE|ROAD AVENGER]
|
||||
Renderer = 16bit accurate
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM T-50085|U|ROAD RASH]
|
||||
Renderer = 16bit accurate
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM MK-4416 -00|E|ROBO ALESTE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-06201-03|U|SEWER SHARK]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM T-113045-00|E|SHADOW OF THE BEAST TWO]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[CD|GM MK-4404|U|SOL-FEACE]
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM MK-4407-00|E|SONIC THE HEDGEHOG-CD]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM MK-4407 -00|U|SONIC THE HEDGEHOG-CD]
|
||||
Scale/Rot. fx (slow) = 1
|
||||
|
||||
[CD|GM T-22025-00|U|THE 3RD WORLD WAR]
|
||||
Better sync (slow) = 1
|
||||
|
||||
[CD|GM MK- 4430 -|E|YUMEMI MISTERY MANSION]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
#
|
||||
# Virtua Racing
|
||||
#
|
||||
[MD|GM MK-1229 -00|U|Virtua Racing]
|
||||
Renderer = 8bit fast
|
||||
Show FPS = 1
|
||||
GP2X CPU clocks = 235
|
||||
|
||||
[MD|GM G-7001 -00|J|Virtua Racing]
|
||||
Renderer = 8bit fast
|
||||
Show FPS = 1
|
||||
GP2X CPU clocks = 235
|
||||
|
||||
[MD|GM MK-1229 -00|E|Virtua Racing]
|
||||
Renderer = 8bit fast
|
||||
Show FPS = 1
|
||||
GP2X CPU clocks = 235
|
||||
|
||||
[MD|GM MK-1229 -00|E|VIRTUA RACING \00\00\00\00\00\00\00\00\00]
|
||||
Renderer = 8bit fast
|
||||
Show FPS = 1
|
||||
GP2X CPU clocks = 235
|
||||
|
||||
#
|
||||
# Genesis/MegaDrive games
|
||||
#
|
||||
[MD|GM MK-1029-00|E| BURNING FORCE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-14023 -00|J| BURNING FORCE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-14026 -00|U| BURNING FORCE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-95076-00|U|CASTLEVANIA BLOODLINES]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-95076-00|E|CASTLEVANIA THE NEW GENERATION]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM MK-1569 -50|A|COMIX ZONE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM G-4132 -00|1|]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM MK-1569 -00|4|COMIX ZONE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-097116 00|4|MORTAL KOMBAT 3]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM G-4119-00|J| OUT_RUNNERS 1994/03/03 Ver.FINAL!!]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-13096-00|U| OUT_RUNNERS]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-48376 00|JUE|RED-ZONE]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-177016-00|F|STREET RACER]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-95043-00|J|]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-25036 -00|U| SHOVE IT!]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM MK-1104 -00|U|AFTER BURNERII]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-32053 -00|U|ARCUS ODYSSEY]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM 00054010-00|JUE|RAMBO \87V]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM 00054010-01|JUE|RAMBO \87V]
|
||||
Renderer = 16bit accurate
|
||||
|
||||
[MD|GM T-50406 -01|U|GALAHAD]
|
||||
Renderer = 16bit accurate
|
||||
|
529
gp2x/940ctl.c
529
gp2x/940ctl.c
|
@ -1,529 +0,0 @@
|
|||
// Code for communication with ARM940 and control of it.
|
||||
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "code940/940shared.h"
|
||||
#include "soc_mmsp2.h"
|
||||
#include "soc.h"
|
||||
#include "../common/mp3.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/input.h"
|
||||
#include "../../pico/pico_int.h"
|
||||
#include "../../pico/sound/ym2612.h"
|
||||
#include "../../pico/sound/mix.h"
|
||||
|
||||
static unsigned char *shared_mem = 0;
|
||||
static _940_data_t *shared_data = 0;
|
||||
_940_ctl_t *shared_ctl = 0;
|
||||
unsigned char *mp3_mem = 0;
|
||||
|
||||
#define MP3_SIZE_MAX (0x400000 + 0x800000) // 12M
|
||||
#define CODE940_FILE "pico940_v3.bin"
|
||||
|
||||
int crashed_940 = 0;
|
||||
|
||||
static FILE *loaded_mp3 = 0;
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
#define MAXOUT (+32767)
|
||||
#define MINOUT (-32768)
|
||||
|
||||
/* limitter */
|
||||
#define Limit(val, max,min) { \
|
||||
if ( val > max ) val = max; \
|
||||
else if ( val < min ) val = min; \
|
||||
}
|
||||
|
||||
/* these will be managed locally on our side */
|
||||
static UINT8 ST_address; /* address register */
|
||||
static INT32 addr_A1; /* address line A1 */
|
||||
|
||||
static int writebuff_ptr = 0;
|
||||
|
||||
|
||||
/* YM2612 write */
|
||||
/* a = address */
|
||||
/* v = value */
|
||||
/* returns 1 if sample affecting state changed */
|
||||
int YM2612Write_940(unsigned int a, unsigned int v, int scanline)
|
||||
{
|
||||
int upd = 1; /* the write affects sample generation */
|
||||
|
||||
a &= 3;
|
||||
|
||||
//printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0: /* address port 0 */
|
||||
if (addr_A1 == 0 && ST_address == v)
|
||||
return 0; /* address already selected, don't send this command to 940 */
|
||||
ST_address = v;
|
||||
addr_A1 = 0;
|
||||
/* don't send DAC or timer related address changes to 940 */
|
||||
if (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a)
|
||||
return 0;
|
||||
upd = 0;
|
||||
break;
|
||||
|
||||
case 2: /* address port 1 */
|
||||
if (addr_A1 == 1 && ST_address == v)
|
||||
return 0;
|
||||
ST_address = v;
|
||||
addr_A1 = 1;
|
||||
upd = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("ym pass\n");
|
||||
|
||||
if (currentConfig.EmuOpt & 4)
|
||||
{
|
||||
UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;
|
||||
|
||||
/* detect rapid ym updates */
|
||||
if (upd && !(writebuff_ptr & 0x80000000) && scanline < 224)
|
||||
{
|
||||
int mid = Pico.m.pal ? 68 : 93;
|
||||
if (scanline > mid) {
|
||||
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, scanline);
|
||||
writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;
|
||||
writebuff_ptr |= 0x80000000;
|
||||
//printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, scanline, addr, v, upd);
|
||||
}
|
||||
}
|
||||
|
||||
/* queue this write for 940 */
|
||||
if ((writebuff_ptr&0xffff) < 2047) {
|
||||
writebuff[writebuff_ptr++ & 0xffff] = (a<<8)|v;
|
||||
} else {
|
||||
printf("warning: writebuff_ptr > 2047 ([%i] %02x)\n", a, v);
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // cause the engine to do updates once per frame only
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_BUSY(job) \
|
||||
(gp2x_memregs[0x3b46>>1] & (1<<(job-1)))
|
||||
|
||||
static void wait_busy_940(int job)
|
||||
{
|
||||
int i;
|
||||
|
||||
job--;
|
||||
for (i = 0; (gp2x_memregs[0x3b46>>1] & (1<<job)) && i < 0x10000; i++)
|
||||
spend_cycles(8*1024); // tested to be best for mp3 dec
|
||||
if (i < 0x10000) return;
|
||||
|
||||
/* 940 crashed */
|
||||
printf("940 crashed (cnt: %i, ve: ", shared_ctl->loopc);
|
||||
for (i = 0; i < 8; i++)
|
||||
printf("%i ", shared_ctl->vstarts[i]);
|
||||
printf(")\n");
|
||||
printf("irq pending flags: DUALCPU %04x, SRCPND %08lx (see 26), INTPND %08lx\n",
|
||||
gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);
|
||||
printf("last lr: %08x, lastjob: %i\n", shared_ctl->last_lr, shared_ctl->lastjob);
|
||||
printf("trying to interrupt..\n");
|
||||
gp2x_memregs[0x3B3E>>1] = 0xffff;
|
||||
for (i = 0; gp2x_memregs[0x3b46>>1] && i < 0x10000; i++)
|
||||
spend_cycles(8*1024);
|
||||
printf("i = 0x%x\n", i);
|
||||
printf("irq pending flags: DUALCPU %04x, SRCPND %08lx (see 26), INTPND %08lx\n",
|
||||
gp2x_memregs[0x3b46>>1], gp2x_memregl[0x4500>>2], gp2x_memregl[0x4510>>2]);
|
||||
printf("last lr: %08x, lastjob: %i\n", shared_ctl->last_lr, shared_ctl->lastjob);
|
||||
|
||||
me_update_msg("940 crashed, too much overclock?");
|
||||
engineState = PGS_Menu;
|
||||
crashed_940 = 1;
|
||||
}
|
||||
|
||||
|
||||
static void add_job_940(int job)
|
||||
{
|
||||
if (job <= 0 || job > 16) {
|
||||
printf("add_job_940: bad job: %i\n", job);
|
||||
return;
|
||||
}
|
||||
|
||||
// generate interrupt for this job
|
||||
job--;
|
||||
gp2x_memregs[(0x3B20+job*2)>>1] = 1;
|
||||
|
||||
// printf("added %i, pending %04x\n", job+1, gp2x_memregs[0x3b46>>1]);
|
||||
}
|
||||
|
||||
|
||||
void YM2612PicoStateLoad_940(void)
|
||||
{
|
||||
UINT8 *REGS = YM2612GetRegs();
|
||||
|
||||
/* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */
|
||||
add_job_940(JOB940_PICOSTATELOAD);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD)) wait_busy_940(JOB940_PICOSTATELOAD);
|
||||
|
||||
writebuff_ptr = 0;
|
||||
addr_A1 = *(INT32 *) (REGS + 0x200);
|
||||
}
|
||||
|
||||
void YM2612PicoStateSave2_940(int tat, int tbt)
|
||||
{
|
||||
UINT8 *ym_remote_regs, *ym_local_regs;
|
||||
add_job_940(JOB940_PICOSTATESAVE2);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATESAVE2)) wait_busy_940(JOB940_PICOSTATESAVE2);
|
||||
|
||||
ym_remote_regs = (UINT8 *) shared_ctl->writebuff0;
|
||||
ym_local_regs = YM2612GetRegs();
|
||||
if (*(UINT32 *)(ym_remote_regs + 0x100) != 0x41534d59) {
|
||||
printf("code940 didn't return valid save data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy addin data only */
|
||||
memcpy(ym_local_regs, ym_remote_regs, 0x20);
|
||||
memcpy(ym_local_regs + 0x100, ym_remote_regs + 0x100, 0x30);
|
||||
memcpy(ym_local_regs + 0x0b8, ym_remote_regs + 0x0b8, 0x48);
|
||||
memcpy(ym_local_regs + 0x1b8, ym_remote_regs + 0x1b8, 0x48);
|
||||
*(INT32 *)(ym_local_regs + 0x108) = tat;
|
||||
*(INT32 *)(ym_local_regs + 0x10c) = tbt;
|
||||
}
|
||||
|
||||
int YM2612PicoStateLoad2_940(int *tat, int *tbt)
|
||||
{
|
||||
UINT8 *ym_remote_regs, *ym_local_regs;
|
||||
ym_local_regs = YM2612GetRegs();
|
||||
ym_remote_regs = (UINT8 *) shared_ctl->writebuff0;
|
||||
|
||||
if (*(UINT32 *)(ym_local_regs + 0x100) != 0x41534d59)
|
||||
return -1;
|
||||
|
||||
*tat = *(INT32 *)(ym_local_regs + 0x108);
|
||||
*tbt = *(INT32 *)(ym_local_regs + 0x10c);
|
||||
|
||||
if (CHECK_BUSY(JOB940_YM2612UPDATEONE)) wait_busy_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
/* flush writes */
|
||||
if (shared_ctl->writebuffsel == 1) {
|
||||
shared_ctl->writebuff0[writebuff_ptr & 0xffff] = 0xffff;
|
||||
} else {
|
||||
shared_ctl->writebuff1[writebuff_ptr & 0xffff] = 0xffff;
|
||||
}
|
||||
shared_ctl->writebuffsel ^= 1;
|
||||
writebuff_ptr = 0;
|
||||
add_job_940(JOB940_PICOSTATELOAD2_PREP);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD2_PREP)) wait_busy_940(JOB940_PICOSTATELOAD2_PREP);
|
||||
|
||||
memcpy(ym_remote_regs, ym_local_regs, 0x200);
|
||||
|
||||
add_job_940(JOB940_PICOSTATELOAD2);
|
||||
if (CHECK_BUSY(JOB940_PICOSTATELOAD2)) wait_busy_940(JOB940_PICOSTATELOAD2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void internal_reset(void)
|
||||
{
|
||||
writebuff_ptr = 0;
|
||||
ST_address = addr_A1 = -1;
|
||||
}
|
||||
|
||||
|
||||
/* this must be called after mmu hack, the allocated regions must not get cached */
|
||||
void sharedmem940_init(void)
|
||||
{
|
||||
if (shared_mem != NULL) return;
|
||||
|
||||
shared_mem = (unsigned char *) mmap(0, 0x210000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2000000);
|
||||
if (shared_mem == MAP_FAILED)
|
||||
{
|
||||
printf("mmap(shared_data) failed with %i\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
shared_data = (_940_data_t *) (shared_mem+0x100000);
|
||||
/* this area must not get buffered on either side */
|
||||
shared_ctl = (_940_ctl_t *) (shared_mem+0x200000);
|
||||
mp3_mem = (unsigned char *) mmap(0, MP3_SIZE_MAX, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0x2400000);
|
||||
if (mp3_mem == MAP_FAILED)
|
||||
{
|
||||
printf("mmap(mp3_mem) failed with %i\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
crashed_940 = 1;
|
||||
}
|
||||
|
||||
|
||||
void sharedmem940_finish(void)
|
||||
{
|
||||
munmap(shared_mem, 0x210000);
|
||||
munmap(mp3_mem, MP3_SIZE_MAX);
|
||||
shared_mem = mp3_mem = NULL;
|
||||
shared_data = NULL;
|
||||
shared_ctl = NULL;
|
||||
}
|
||||
|
||||
|
||||
void YM2612Init_940(int baseclock, int rate)
|
||||
{
|
||||
printf("YM2612Init_940()\n");
|
||||
printf("Mem usage: shared_data: %i, shared_ctl: %i\n", sizeof(*shared_data), sizeof(*shared_ctl));
|
||||
|
||||
reset940(1, 2);
|
||||
pause940(1);
|
||||
|
||||
gp2x_memregs[0x3B40>>1] = 0; // disable DUALCPU interrupts for 920
|
||||
gp2x_memregs[0x3B42>>1] = 1; // enable DUALCPU interrupts for 940
|
||||
|
||||
gp2x_memregl[0x4504>>2] = 0; // make sure no FIQs will be generated
|
||||
gp2x_memregl[0x4508>>2] = ~(1<<26); // unmask DUALCPU ints in the undocumented 940's interrupt controller
|
||||
|
||||
|
||||
if (crashed_940)
|
||||
{
|
||||
unsigned char ucData[1024];
|
||||
int nRead, nLen = 0;
|
||||
char binpath[512];
|
||||
FILE *fp;
|
||||
|
||||
emu_make_path(binpath, CODE940_FILE, sizeof(binpath));
|
||||
fp = fopen(binpath, "rb");
|
||||
if(!fp)
|
||||
{
|
||||
memset(g_screen_ptr, 0, 320*240*2);
|
||||
text_out16(10, 100, "failed to open required file:");
|
||||
text_out16(10, 110, CODE940_FILE);
|
||||
gp2x_video_flip2();
|
||||
in_menu_wait(PBTN_MOK|PBTN_MBACK, 100);
|
||||
printf("failed to open %s\n", binpath);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
nRead = fread(ucData, 1, 1024, fp);
|
||||
if(nRead <= 0)
|
||||
break;
|
||||
memcpy(shared_mem + nLen, ucData, nRead);
|
||||
nLen += nRead;
|
||||
}
|
||||
fclose(fp);
|
||||
crashed_940 = 0;
|
||||
}
|
||||
|
||||
memset(shared_data, 0, sizeof(*shared_data));
|
||||
memset(shared_ctl, 0, sizeof(*shared_ctl));
|
||||
|
||||
/* cause local ym2612 to init REGS */
|
||||
YM2612Init_(baseclock, rate);
|
||||
|
||||
internal_reset();
|
||||
|
||||
loaded_mp3 = 0;
|
||||
|
||||
gp2x_memregs[0x3B46>>1] = 0xffff; // clear pending DUALCPU interrupts for 940
|
||||
gp2x_memregl[0x4500>>2] = 0xffffffff; // clear pending IRQs in SRCPND
|
||||
gp2x_memregl[0x4510>>2] = 0xffffffff; // clear pending IRQs in INTPND
|
||||
|
||||
/* start the 940 */
|
||||
reset940(0, 2);
|
||||
pause940(0);
|
||||
|
||||
// YM2612ResetChip_940(); // will be done on JOB940_YM2612INIT
|
||||
|
||||
/* now cause 940 to init it's ym2612 stuff */
|
||||
shared_ctl->baseclock = baseclock;
|
||||
shared_ctl->rate = rate;
|
||||
add_job_940(JOB940_INITALL);
|
||||
}
|
||||
|
||||
|
||||
void YM2612ResetChip_940(void)
|
||||
{
|
||||
//printf("YM2612ResetChip_940()\n");
|
||||
if (shared_data == NULL) {
|
||||
printf("YM2612ResetChip_940: reset before init?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
YM2612ResetChip_();
|
||||
internal_reset();
|
||||
|
||||
add_job_940(JOB940_YM2612RESETCHIP);
|
||||
}
|
||||
|
||||
|
||||
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty)
|
||||
{
|
||||
int *ym_buf = shared_data->ym_buffer;
|
||||
int ym_active_chs;
|
||||
|
||||
//printf("YM2612UpdateOne_940()\n");
|
||||
|
||||
if (CHECK_BUSY(JOB940_YM2612UPDATEONE)) wait_busy_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
ym_active_chs = shared_ctl->ym_active_chs;
|
||||
|
||||
// mix in ym buffer. is_buf_empty means nobody mixed there anything yet and it may contain trash
|
||||
if (is_buf_empty && ym_active_chs) memcpy32(buffer, ym_buf, length<<stereo);
|
||||
else memset32(buffer, 0, length<<stereo);
|
||||
|
||||
if (shared_ctl->writebuffsel == 1) {
|
||||
shared_ctl->writebuff0[writebuff_ptr & 0xffff] = 0xffff;
|
||||
} else {
|
||||
shared_ctl->writebuff1[writebuff_ptr & 0xffff] = 0xffff;
|
||||
}
|
||||
writebuff_ptr = 0;
|
||||
|
||||
/* predict sample counter for next frame */
|
||||
if (PsndLen_exc_add) {
|
||||
length = PsndLen;
|
||||
if (PsndLen_exc_cnt + PsndLen_exc_add >= 0x10000) length++;
|
||||
}
|
||||
|
||||
/* give 940 ym job */
|
||||
shared_ctl->writebuffsel ^= 1;
|
||||
shared_ctl->length = length;
|
||||
shared_ctl->stereo = stereo;
|
||||
|
||||
add_job_940(JOB940_YM2612UPDATEONE);
|
||||
|
||||
return ym_active_chs;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
static int mp3_samples_ready = 0, mp3_buffer_offs = 0;
|
||||
static int mp3_play_bufsel = 0, mp3_job_started = 0;
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
int length_mp3;
|
||||
|
||||
if (!(PicoOpt & POPT_EXT_FM)) {
|
||||
mp3_update_local(buffer, length, stereo);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if playback was started, track not ended
|
||||
if (loaded_mp3 == NULL || shared_ctl->mp3_offs >= shared_ctl->mp3_len)
|
||||
return;
|
||||
|
||||
length_mp3 = length;
|
||||
if (PsndRate == 22050) length_mp3 <<= 1; // mp3s are locked to 44100Hz stereo
|
||||
else if (PsndRate == 11025) length_mp3 <<= 2; // so make length 44100ish
|
||||
|
||||
/* do we have to wait? */
|
||||
if (mp3_job_started && mp3_samples_ready < length_mp3) {
|
||||
if (CHECK_BUSY(JOB940_MP3DECODE)) wait_busy_940(JOB940_MP3DECODE);
|
||||
mp3_job_started = 0;
|
||||
mp3_samples_ready += 1152;
|
||||
}
|
||||
|
||||
/* mix mp3 data, only stereo */
|
||||
if (mp3_samples_ready >= length_mp3)
|
||||
{
|
||||
int shr = 0;
|
||||
void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;
|
||||
if (PsndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }
|
||||
else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }
|
||||
|
||||
if (1152 - mp3_buffer_offs >= length_mp3) {
|
||||
mix_samples(buffer, shared_data->mp3_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length<<1);
|
||||
|
||||
mp3_buffer_offs += length_mp3;
|
||||
} else {
|
||||
// collect samples from both buffers..
|
||||
int left = 1152 - mp3_buffer_offs;
|
||||
if (mp3_play_bufsel == 0)
|
||||
{
|
||||
mix_samples(buffer, shared_data->mp3_buffer[0] + mp3_buffer_offs*2, length<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mp3_play_bufsel = 1;
|
||||
} else {
|
||||
mix_samples(buffer, shared_data->mp3_buffer[1] + mp3_buffer_offs*2, (left>>shr)<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mix_samples(buffer + ((left>>shr)<<1),
|
||||
shared_data->mp3_buffer[0], (mp3_buffer_offs>>shr)<<1);
|
||||
mp3_play_bufsel = 0;
|
||||
}
|
||||
}
|
||||
mp3_samples_ready -= length_mp3;
|
||||
}
|
||||
|
||||
// ask to decode more if we already can
|
||||
if (!mp3_job_started)
|
||||
{
|
||||
mp3_job_started = 1;
|
||||
shared_ctl->mp3_buffsel ^= 1;
|
||||
add_job_940(JOB940_MP3DECODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mp3_start_play(void *f_, int pos) // pos is 0-1023
|
||||
{
|
||||
int byte_offs = 0;
|
||||
FILE *f = f_;
|
||||
|
||||
if (!(PicoOpt & POPT_EN_MCD_CDDA) || f == NULL)
|
||||
return;
|
||||
|
||||
if (!(PicoOpt & POPT_EXT_FM)) {
|
||||
mp3_start_play_local(f, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (loaded_mp3 != f)
|
||||
{
|
||||
if (PicoMessage != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
if (ftell(f) > 2*1024*1024)
|
||||
PicoMessage("Loading MP3...");
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(mp3_mem, 1, MP3_SIZE_MAX, f);
|
||||
if (!feof(f)) printf("Warning: mp3 was too large, not all data loaded.\n");
|
||||
shared_ctl->mp3_len = ftell(f);
|
||||
loaded_mp3 = f;
|
||||
|
||||
if (PicoOpt & POPT_EXT_FM) {
|
||||
// as we are going to change 940's cacheable area, we must invalidate it's cache..
|
||||
if (CHECK_BUSY(JOB940_MP3DECODE)) wait_busy_940(JOB940_MP3DECODE);
|
||||
add_job_940(JOB940_INVALIDATE_DCACHE);
|
||||
}
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
// seek..
|
||||
if (pos) {
|
||||
byte_offs = (shared_ctl->mp3_len << 6) >> 10;
|
||||
byte_offs *= pos;
|
||||
byte_offs >>= 6;
|
||||
}
|
||||
printf(" mp3 pos1024: %i, byte_offs %i/%i\n", pos, byte_offs, shared_ctl->mp3_len);
|
||||
|
||||
shared_ctl->mp3_offs = byte_offs;
|
||||
|
||||
// reset buffer pointers and stuff..
|
||||
mp3_samples_ready = mp3_buffer_offs = mp3_play_bufsel = 0;
|
||||
mp3_job_started = 0;
|
||||
shared_ctl->mp3_buffsel = 1; // will change to 0 on first decode
|
||||
|
||||
add_job_940(JOB940_MP3RESET);
|
||||
if (CHECK_BUSY(JOB940_MP3RESET)) wait_busy_940(JOB940_MP3RESET);
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
void sharedmem940_init(void);
|
||||
void sharedmem940_finish(void);
|
||||
|
||||
void YM2612Init_940(int baseclock, int rate);
|
||||
void YM2612ResetChip_940(void);
|
||||
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);
|
||||
|
||||
int YM2612Write_940(unsigned int a, unsigned int v, int scanline);
|
||||
|
||||
int YM2612PicoTick_940(int n);
|
||||
void YM2612PicoStateLoad_940(void);
|
||||
void YM2612PicoStateSave2_940(int tat, int tbt);
|
||||
int YM2612PicoStateLoad2_940(int *tat, int *tbt);
|
128
gp2x/Makefile
128
gp2x/Makefile
|
@ -1,128 +0,0 @@
|
|||
CROSS ?= arm-linux-
|
||||
|
||||
# settings
|
||||
use_cyclone = 1
|
||||
#use_musashi = 1
|
||||
use_drz80 = 1
|
||||
use_sh2drc = 1
|
||||
#use_sh2mame = 1
|
||||
|
||||
asm_memory = 1
|
||||
asm_render = 1
|
||||
asm_ym2612 = 1
|
||||
asm_misc = 1
|
||||
asm_cdpico = 1
|
||||
asm_cdmemory = 1
|
||||
asm_32xdraw = 1
|
||||
#profile = 1
|
||||
#drc_debug = 3
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ifeq "$(debug_cyclone)" "1"
|
||||
use_cyclone = 1
|
||||
use_musashi = 1
|
||||
endif
|
||||
ifeq "$(use_musashi)" "1"
|
||||
# due to CPU stop flag acces
|
||||
asm_cdpico = 0
|
||||
asm_cdmemory = 0
|
||||
endif
|
||||
|
||||
ARCH = arm
|
||||
DEFINES += ARM __GP2X__ IN_GP2X IN_EVDEV # BENCHMARK
|
||||
CFLAGS += -Wall -Winline -I../.. -I.
|
||||
ifeq ($(DEBUG),)
|
||||
CFLAGS += -O3 -fomit-frame-pointer -fstrict-aliasing -ffast-math
|
||||
endif
|
||||
CFLAGS += -mcpu=arm920t -mtune=arm920t
|
||||
ASFLAGS = -mcpu=arm920t -mfloat-abi=soft
|
||||
LDFLAGS += -lm -lpng
|
||||
|
||||
CC = $(CROSS)gcc
|
||||
STRIP = $(CROSS)strip
|
||||
AS = $(CROSS)as
|
||||
LD = $(CROSS)ld
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
# frontend
|
||||
OBJS += plat.o warm.o pollux_set.o soc.o soc_mmsp2.o soc_pollux.o soc_dummy.o emu.o in_gp2x.o
|
||||
# 940 core control
|
||||
OBJS += 940ctl.o
|
||||
|
||||
# ARM stuff
|
||||
OBJS += pico/carthw/svp/compiler.o pico/carthw/svp/stub_arm.o
|
||||
OBJS += pico/sound/mix_arm.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/emu.o platform/common/menu_pico.o platform/common/fonts.o platform/common/config.o \
|
||||
platform/common/arm_utils.o platform/common/arm_linux.o platform/common/readpng.o \
|
||||
platform/common/mp3_helix.o platform/common/input.o platform/common/main.o platform/common/mp3.o \
|
||||
platform/linux/sndout_oss.o platform/linux/plat.o platform/linux/in_evdev.o
|
||||
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
# zlib
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o
|
||||
|
||||
vpath %.c = ../..
|
||||
vpath %.s = ../..
|
||||
vpath %.S = ../..
|
||||
|
||||
DIRS += platform/gp2x platform/linux zlib unzip
|
||||
|
||||
|
||||
all: mkdirs PicoDrive
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/common_arm.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||
|
||||
# partial linking helps profiled builds due to section merging
|
||||
PicoDrive.o : $(OBJS) ../common/helix/$(CROSS)helix-mp3.a
|
||||
$(LD) -r -o $@ $^
|
||||
|
||||
# still using static, dynamic linking slows Wiz 1-10%
|
||||
# also libm on F100 is not compatible
|
||||
PicoDrive : PicoDrive.o
|
||||
@echo ">>>" $@
|
||||
$(CC) -static -o $@ $(CFLAGS) $^ $(LDFLAGS) -Wl,-Map=$@.map
|
||||
ifeq ($(DEBUG),)
|
||||
$(STRIP) $@
|
||||
endif
|
||||
|
||||
up: PicoDrive
|
||||
@cp -v PicoDrive /mnt/gp2x/mnt/sd/emus/PicoDrive/
|
||||
|
||||
clean: tidy
|
||||
$(RM) PicoDrive
|
||||
tidy:
|
||||
$(RM) $(OBJS)
|
||||
|
||||
readme.txt: ../../tools/textfilter ../base_readme.txt
|
||||
../../tools/textfilter ../base_readme.txt $@ GP2X
|
||||
|
||||
# ----------- release -----------
|
||||
VER ?= $(shell head -n 1 version.h | sed 's/.*"\(.*\)\.\(.*\)".*/\1\2/g')
|
||||
CODE940 = code940/pico940_v3.bin
|
||||
|
||||
rel: PicoDrive PicoDrive.gpe $(CODE940) readme.txt ../game_def.cfg \
|
||||
PicoDrive.png PicoDrive_s.png PicoDrive_t.png \
|
||||
warm_2.4.25.o warm_2.4.26-open2x.o warm_2.6.24.ko \
|
||||
../../pico/carthw.cfg
|
||||
mkdir -p out/PicoDrive/skin/
|
||||
cp $^ out/PicoDrive/
|
||||
cp PicoDrive.ini out/
|
||||
cp skin/*.png out/PicoDrive/skin/
|
||||
cp skin/*.txt out/PicoDrive/skin/
|
||||
mkdir out/bin_to_cso_mp3
|
||||
cp ../../tools/bin_to_cso_mp3/* out/bin_to_cso_mp3/
|
||||
cd out && zip -9 -r ../../../PicoDrive_$(VER).zip *
|
||||
rm -rf out
|
||||
|
||||
$(CODE940):
|
||||
make -C code940/
|
||||
|
915
gp2x/emu.c
915
gp2x/emu.c
|
@ -1,915 +0,0 @@
|
|||
/*
|
||||
* (c) Copyright 2006-2010 notaz, All rights reserved.
|
||||
*
|
||||
* For performance reasons 3 renderers are exported for both MD and 32x modes:
|
||||
* - 16bpp line renderer
|
||||
* - 8bpp line renderer (slightly faster)
|
||||
* - 8bpp tile renderer
|
||||
* In 32x mode:
|
||||
* - 32x layer is overlayed on top of 16bpp one
|
||||
* - line internal one done on PicoDraw2FB, then mixed with 32x
|
||||
* - tile internal one done on PicoDraw2FB, then mixed with 32x
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "plat_gp2x.h"
|
||||
#include "soc.h"
|
||||
#include "soc_pollux.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../common/fonts.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/input.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
#include <pico/patch.h>
|
||||
#include <pico/sound/mix.h>
|
||||
#include <zlib/zlib.h>
|
||||
|
||||
#ifdef BENCHMARK
|
||||
#define OSD_FPS_X 220
|
||||
#else
|
||||
#define OSD_FPS_X 260
|
||||
#endif
|
||||
|
||||
|
||||
extern int crashed_940;
|
||||
|
||||
static short __attribute__((aligned(4))) sndBuffer[2*(44100+100)/50];
|
||||
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
|
||||
unsigned char *PicoDraw2FB = PicoDraw2FB_;
|
||||
static int osd_fps_x, osd_y, doing_bg_frame;
|
||||
const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL };
|
||||
const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL };
|
||||
enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT };
|
||||
|
||||
static int (*emu_scan_begin)(unsigned int num) = NULL;
|
||||
static int (*emu_scan_end)(unsigned int num) = NULL;
|
||||
|
||||
extern void *gp2x_screens[4];
|
||||
|
||||
|
||||
void pemu_prep_defconfig(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
defaultConfig.CPUclock = default_cpu_clock;
|
||||
defaultConfig.renderer32x = RT_8BIT_FAST;
|
||||
defaultConfig.analog_deadzone = 50;
|
||||
|
||||
soc = soc_detect();
|
||||
if (soc == SOCID_MMSP2)
|
||||
defaultConfig.s_PicoOpt |= POPT_EXT_FM;
|
||||
else if (soc == SOCID_POLLUX) {
|
||||
defaultConfig.EmuOpt |= EOPT_WIZ_TEAR_FIX|EOPT_SHOW_RTC;
|
||||
defaultConfig.s_PicoOpt |= POPT_EN_MCD_GFX;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
if (gp2x_dev_id != GP2X_DEV_GP2X)
|
||||
PicoOpt &= ~POPT_EXT_FM;
|
||||
if (gp2x_dev_id != GP2X_DEV_WIZ)
|
||||
currentConfig.EmuOpt &= ~EOPT_WIZ_TEAR_FIX;
|
||||
|
||||
if (currentConfig.gamma < 10 || currentConfig.gamma > 300)
|
||||
currentConfig.gamma = 100;
|
||||
|
||||
if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 1024)
|
||||
currentConfig.CPUclock = default_cpu_clock;
|
||||
}
|
||||
|
||||
static int get_renderer(void)
|
||||
{
|
||||
if (PicoAHW & PAHW_32X)
|
||||
return currentConfig.renderer32x;
|
||||
else
|
||||
return currentConfig.renderer;
|
||||
}
|
||||
|
||||
static void change_renderer(int diff)
|
||||
{
|
||||
int *r;
|
||||
if (PicoAHW & PAHW_32X)
|
||||
r = ¤tConfig.renderer32x;
|
||||
else
|
||||
r = ¤tConfig.renderer;
|
||||
*r += diff;
|
||||
|
||||
// 8bpp fast is not there (yet?)
|
||||
if ((PicoAHW & PAHW_SMS) && *r == RT_8BIT_FAST)
|
||||
(*r)++;
|
||||
|
||||
if (*r >= RT_COUNT)
|
||||
*r = 0;
|
||||
else if (*r < 0)
|
||||
*r = RT_COUNT - 1;
|
||||
}
|
||||
|
||||
#define is_16bit_mode() \
|
||||
(get_renderer() == RT_16BIT || (PicoAHW & PAHW_32X))
|
||||
|
||||
static void (*osd_text)(int x, int y, const char *text);
|
||||
|
||||
static void osd_text8(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+3) >> 2;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~3;
|
||||
p = (int *) ((char *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = 0xe0e0e0e0;
|
||||
}
|
||||
emu_text_out8(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text16(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+1) >> 1;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~1;
|
||||
p = (int *) ((short *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = (*p >> 2) & 0x39e7;
|
||||
}
|
||||
emu_text_out16(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text8_rot(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text) * 8;
|
||||
char *p = (char *)g_screen_ptr + 240*(320-x) + y;
|
||||
|
||||
while (len--) {
|
||||
memset(p, 0xe0, 8);
|
||||
p -= 240;
|
||||
}
|
||||
|
||||
emu_text_out8_rot(x, y, text);
|
||||
}
|
||||
|
||||
static void osd_text16_rot(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text) * 8;
|
||||
short *p = (short *)g_screen_ptr + 240*(320-x) + y;
|
||||
|
||||
while (len--) {
|
||||
memset(p, 0, 8*2);
|
||||
p -= 240;
|
||||
}
|
||||
|
||||
emu_text_out16_rot(x, y, text);
|
||||
}
|
||||
|
||||
static void draw_cd_leds(void)
|
||||
{
|
||||
int led_reg, pitch, scr_offs, led_offs;
|
||||
led_reg = Pico_mcd->s68k_regs[0];
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
pitch = 240;
|
||||
led_offs = -pitch * 6;
|
||||
scr_offs = pitch * (320 - 4);
|
||||
} else {
|
||||
pitch = 320;
|
||||
led_offs = 4;
|
||||
scr_offs = pitch * 2 + 4;
|
||||
}
|
||||
|
||||
if (!is_16bit_mode()) {
|
||||
#define p(x) px[(x) >> 2]
|
||||
// 8-bit modes
|
||||
unsigned int *px = (unsigned int *)((char *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
} else {
|
||||
#define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]
|
||||
// 16-bit modes
|
||||
unsigned int *px = (unsigned int *)((short *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0x06000600 : 0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xc000c000 : 0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_pico_ptr(void)
|
||||
{
|
||||
unsigned short *p = (unsigned short *)g_screen_ptr;
|
||||
int x, y, pitch = 320;
|
||||
|
||||
// only if pen enabled and for 16bit modes
|
||||
if (pico_inp_mode == 0 || currentConfig.EmuOpt != RT_16BIT)
|
||||
return;
|
||||
|
||||
x = pico_pen_x + PICO_PEN_ADJUST_X;
|
||||
y = pico_pen_y + PICO_PEN_ADJUST_Y;
|
||||
if (!(Pico.video.reg[12]&1) && !(PicoOpt & POPT_DIS_32C_BORDER))
|
||||
x += 32;
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
pitch = 240;
|
||||
p += (319 - x) * pitch + y;
|
||||
} else
|
||||
p += x + y * pitch;
|
||||
|
||||
p[0] ^= 0xffff;
|
||||
p[pitch-1] ^= 0xffff;
|
||||
p[pitch] ^= 0xffff;
|
||||
p[pitch+1] ^= 0xffff;
|
||||
p[pitch*2] ^= 0xffff;
|
||||
}
|
||||
|
||||
/* rot thing for Wiz */
|
||||
static unsigned char __attribute__((aligned(4))) rot_buff[320*4*2];
|
||||
|
||||
static int EmuScanBegin16_rot(unsigned int num)
|
||||
{
|
||||
DrawLineDest = rot_buff + (num & 3) * 320 * 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd16_rot(unsigned int num)
|
||||
{
|
||||
if ((num & 3) != 3)
|
||||
return 0;
|
||||
rotated_blit16(g_screen_ptr, rot_buff, num + 1,
|
||||
!(Pico.video.reg[12] & 1) && !(PicoOpt & POPT_EN_SOFTSCALE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanBegin8_rot(unsigned int num)
|
||||
{
|
||||
DrawLineDest = rot_buff + (num & 3) * 320;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd8_rot(unsigned int num)
|
||||
{
|
||||
if ((num & 3) != 3)
|
||||
return 0;
|
||||
rotated_blit8(g_screen_ptr, rot_buff, num + 1,
|
||||
!(Pico.video.reg[12] & 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* line doublers */
|
||||
static unsigned int ld_counter;
|
||||
static int ld_left, ld_lines;
|
||||
|
||||
static int EmuScanBegin16_ld(unsigned int num)
|
||||
{
|
||||
if ((signed int)(ld_counter - num) > 100)
|
||||
ld_counter = 0;
|
||||
|
||||
if (emu_scan_begin)
|
||||
return emu_scan_begin(ld_counter);
|
||||
else
|
||||
DrawLineDest = (char *)g_screen_ptr + 320 * ld_counter * gp2x_current_bpp / 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int EmuScanEnd16_ld(unsigned int num)
|
||||
{
|
||||
void *oldline = DrawLineDest;
|
||||
|
||||
if (emu_scan_end)
|
||||
emu_scan_end(ld_counter);
|
||||
|
||||
ld_counter++;
|
||||
ld_left--;
|
||||
if (ld_left <= 0) {
|
||||
ld_left = ld_lines;
|
||||
|
||||
EmuScanBegin16_ld(num);
|
||||
memcpy32(DrawLineDest, oldline, 320 * gp2x_current_bpp / 8 / 4);
|
||||
if (emu_scan_end)
|
||||
emu_scan_end(ld_counter);
|
||||
|
||||
ld_counter++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int localPal[0x100];
|
||||
static void (*vidcpyM2)(void *dest, void *src, int m32col, int with_32c_border);
|
||||
static int (*make_local_pal)(int fast_mode);
|
||||
|
||||
static int make_local_pal_md(int fast_mode)
|
||||
{
|
||||
int pallen = 0xc0;
|
||||
|
||||
bgr444_to_rgb32(localPal, Pico.cram);
|
||||
if (fast_mode)
|
||||
return 0x40;
|
||||
|
||||
if (Pico.video.reg[0xC] & 8) { // shadow/hilight mode
|
||||
bgr444_to_rgb32_sh(localPal, Pico.cram);
|
||||
localPal[0xc0] = 0x0000c000;
|
||||
localPal[0xd0] = 0x00c00000;
|
||||
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
|
||||
localPal[0xf0] = 0x00ffffff;
|
||||
pallen = 0x100;
|
||||
}
|
||||
else if (rendstatus & PDRAW_SONIC_MODE) { // mid-frame palette changes
|
||||
bgr444_to_rgb32(localPal+0x40, HighPal);
|
||||
bgr444_to_rgb32(localPal+0x80, HighPal+0x40);
|
||||
}
|
||||
else
|
||||
memcpy32(localPal+0x80, localPal, 0x40); // for spr prio mess
|
||||
|
||||
return pallen;
|
||||
}
|
||||
|
||||
static int make_local_pal_sms(int fast_mode)
|
||||
{
|
||||
unsigned short *spal = Pico.cram;
|
||||
unsigned int *dpal = (void *)localPal;
|
||||
unsigned int i, t;
|
||||
|
||||
for (i = 0x40; i > 0; i--) {
|
||||
t = *spal++;
|
||||
t = ((t & 0x0003) << 22) | ((t & 0x000c) << 12) | ((t & 0x0030) << 2);
|
||||
t |= t >> 2;
|
||||
t |= t >> 4;
|
||||
*dpal++ = t;
|
||||
}
|
||||
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
void pemu_finalize_frame(const char *fps, const char *notice)
|
||||
{
|
||||
int emu_opt = currentConfig.EmuOpt;
|
||||
int ret;
|
||||
|
||||
if (PicoAHW & PAHW_32X)
|
||||
; // nothing to do
|
||||
else if (get_renderer() == RT_8BIT_FAST)
|
||||
{
|
||||
// 8bit fast renderer
|
||||
if (Pico.m.dirtyPal) {
|
||||
Pico.m.dirtyPal = 0;
|
||||
ret = make_local_pal(1);
|
||||
// feed new palette to our device
|
||||
gp2x_video_setpalette(localPal, ret);
|
||||
}
|
||||
// a hack for VR
|
||||
if (PicoAHW & PAHW_SVP)
|
||||
memset32((int *)(PicoDraw2FB+328*8+328*223), 0xe0e0e0e0, 328);
|
||||
// do actual copy
|
||||
vidcpyM2(g_screen_ptr, PicoDraw2FB+328*8,
|
||||
!(Pico.video.reg[12] & 1), !(PicoOpt & POPT_DIS_32C_BORDER));
|
||||
}
|
||||
else if (get_renderer() == RT_8BIT_ACC)
|
||||
{
|
||||
// 8bit accurate renderer
|
||||
if (Pico.m.dirtyPal)
|
||||
{
|
||||
Pico.m.dirtyPal = 0;
|
||||
ret = make_local_pal(0);
|
||||
gp2x_video_setpalette(localPal, ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (notice)
|
||||
osd_text(4, osd_y, notice);
|
||||
if (emu_opt & EOPT_SHOW_FPS)
|
||||
osd_text(osd_fps_x, osd_y, fps);
|
||||
if ((PicoAHW & PAHW_MCD) && (emu_opt & EOPT_EN_CD_LEDS))
|
||||
draw_cd_leds();
|
||||
if (PicoAHW & PAHW_PICO)
|
||||
draw_pico_ptr();
|
||||
}
|
||||
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
int stride = g_screen_width;
|
||||
gp2x_video_flip();
|
||||
|
||||
if (is_16bit_mode())
|
||||
stride *= 2;
|
||||
PicoDrawSetOutBuf(g_screen_ptr, stride);
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
#ifdef __GP2X__
|
||||
unsigned int plat_get_ticks_ms(void)
|
||||
{
|
||||
return gp2x_get_ticks_ms();
|
||||
}
|
||||
|
||||
unsigned int plat_get_ticks_us(void)
|
||||
{
|
||||
return gp2x_get_ticks_us();
|
||||
}
|
||||
#endif
|
||||
|
||||
void plat_wait_till_us(unsigned int us_to)
|
||||
{
|
||||
unsigned int now;
|
||||
|
||||
spend_cycles(1024);
|
||||
now = plat_get_ticks_us();
|
||||
|
||||
while ((signed int)(us_to - now) > 512)
|
||||
{
|
||||
spend_cycles(1024);
|
||||
now = plat_get_ticks_us();
|
||||
}
|
||||
}
|
||||
|
||||
void plat_video_wait_vsync(void)
|
||||
{
|
||||
gp2x_video_wait_vsync();
|
||||
}
|
||||
|
||||
void plat_status_msg_clear(void)
|
||||
{
|
||||
int is_8bit = !is_16bit_mode();
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
/* ugh.. */
|
||||
int i, u, *p;
|
||||
if (is_8bit) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
p = (int *)gp2x_screens[i] + (240-8) / 4;
|
||||
for (u = 320; u > 0; u--, p += 240/4)
|
||||
p[0] = p[1] = 0xe0e0e0e0;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
p = (int *)gp2x_screens[i] + (240-8)*2 / 4;
|
||||
for (u = 320; u > 0; u--, p += 240*2/4)
|
||||
p[0] = p[1] = p[2] = p[3] = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_8bit)
|
||||
gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
|
||||
else
|
||||
gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_next(const char *msg)
|
||||
{
|
||||
plat_status_msg_clear();
|
||||
pemu_finalize_frame("", msg);
|
||||
plat_video_flip();
|
||||
emu_status_msg("");
|
||||
|
||||
/* assumption: msg_busy_next gets called only when
|
||||
* something slow is about to happen */
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_first(const char *msg)
|
||||
{
|
||||
gp2x_memcpy_all_buffers(g_screen_ptr, 0, 320*240*2);
|
||||
plat_status_msg_busy_next(msg);
|
||||
}
|
||||
|
||||
static void vid_reset_mode(void)
|
||||
{
|
||||
int gp2x_mode = 16;
|
||||
int renderer = get_renderer();
|
||||
|
||||
PicoOpt &= ~POPT_ALT_RENDERER;
|
||||
emu_scan_begin = NULL;
|
||||
emu_scan_end = NULL;
|
||||
|
||||
switch (renderer) {
|
||||
case RT_16BIT:
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 0);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
break;
|
||||
case RT_8BIT_ACC:
|
||||
PicoDrawSetOutFormat(PDF_8BIT, 0);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width);
|
||||
gp2x_mode = 8;
|
||||
break;
|
||||
case RT_8BIT_FAST:
|
||||
PicoOpt |= POPT_ALT_RENDERER;
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
vidcpyM2 = vidcpy_m2;
|
||||
gp2x_mode = 8;
|
||||
break;
|
||||
default:
|
||||
printf("bad renderer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (PicoAHW & PAHW_32X) {
|
||||
// Wiz 16bit is an exception, uses line rendering due to rotation mess
|
||||
if (renderer == RT_16BIT && (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)) {
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
PicoDraw32xSetFrameMode(0, 0);
|
||||
}
|
||||
else {
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
PicoDraw32xSetFrameMode(1, 0);
|
||||
}
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
gp2x_mode = 16;
|
||||
}
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) {
|
||||
if ((PicoAHW & PAHW_32X) || renderer == RT_16BIT) {
|
||||
emu_scan_begin = EmuScanBegin16_rot;
|
||||
emu_scan_end = EmuScanEnd16_rot;
|
||||
}
|
||||
else if (renderer == RT_8BIT_ACC) {
|
||||
emu_scan_begin = EmuScanBegin8_rot;
|
||||
emu_scan_end = EmuScanEnd8_rot;
|
||||
}
|
||||
else if (renderer == RT_8BIT_FAST)
|
||||
vidcpyM2 = vidcpy_m2_rot;
|
||||
}
|
||||
|
||||
PicoDrawSetCallbacks(emu_scan_begin, emu_scan_end);
|
||||
|
||||
if (is_16bit_mode())
|
||||
osd_text = (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) ? osd_text16_rot : osd_text16;
|
||||
else
|
||||
osd_text = (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX) ? osd_text8_rot : osd_text8;
|
||||
|
||||
gp2x_video_wait_vsync();
|
||||
if (!is_16bit_mode()) {
|
||||
// setup pal for 8-bit modes
|
||||
localPal[0xc0] = 0x0000c000; // MCD LEDs
|
||||
localPal[0xd0] = 0x00c00000;
|
||||
localPal[0xe0] = 0x00000000; // reserved pixels for OSD
|
||||
localPal[0xf0] = 0x00ffffff;
|
||||
gp2x_video_setpalette(localPal, 0x100);
|
||||
gp2x_memset_all_buffers(0, 0xe0, 320*240);
|
||||
}
|
||||
else
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_WIZ_TEAR_FIX)
|
||||
gp2x_mode = -gp2x_mode;
|
||||
|
||||
gp2x_video_changemode(gp2x_mode);
|
||||
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
PicoOpt &= ~POPT_EN_SOFTSCALE;
|
||||
if (currentConfig.scaling == EOPT_SCALE_SW)
|
||||
PicoOpt |= POPT_EN_SOFTSCALE;
|
||||
|
||||
// palette converters for 8bit modes
|
||||
make_local_pal = (PicoAHW & PAHW_SMS) ? make_local_pal_sms : make_local_pal_md;
|
||||
}
|
||||
|
||||
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||
{
|
||||
int scalex = 320, scaley = 240;
|
||||
int ln_offs = 0;
|
||||
|
||||
if (doing_bg_frame)
|
||||
return;
|
||||
|
||||
osd_fps_x = OSD_FPS_X;
|
||||
osd_y = 232;
|
||||
|
||||
/* set up hwscaling here */
|
||||
PicoOpt &= ~POPT_DIS_32C_BORDER;
|
||||
if (is_32cols && currentConfig.scaling == EOPT_SCALE_HW) {
|
||||
scalex = 256;
|
||||
PicoOpt |= POPT_DIS_32C_BORDER;
|
||||
osd_fps_x = OSD_FPS_X - 64;
|
||||
}
|
||||
|
||||
if (currentConfig.vscaling == EOPT_SCALE_HW) {
|
||||
ln_offs = start_line;
|
||||
scaley = line_count;
|
||||
osd_y = start_line + line_count - 8;
|
||||
}
|
||||
|
||||
gp2x_video_RGB_setscaling(ln_offs, scalex, scaley);
|
||||
|
||||
/* line doubling */
|
||||
if (currentConfig.vscaling == EOPT_SCALE_SW && line_count < 240) {
|
||||
ld_lines = ld_left = line_count / (240 - line_count);
|
||||
PicoDrawSetCallbacks(EmuScanBegin16_ld, EmuScanEnd16_ld);
|
||||
}
|
||||
|
||||
// clear whole screen in all buffers
|
||||
if (!is_16bit_mode())
|
||||
gp2x_memset_all_buffers(0, 0xe0, 320*240);
|
||||
else
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
}
|
||||
|
||||
void plat_video_toggle_renderer(int change, int is_menu_call)
|
||||
{
|
||||
change_renderer(change);
|
||||
|
||||
if (is_menu_call)
|
||||
return;
|
||||
|
||||
vid_reset_mode();
|
||||
rendstatus_old = -1;
|
||||
|
||||
if (PicoAHW & PAHW_32X)
|
||||
emu_status_msg(renderer_names32x[get_renderer()]);
|
||||
else
|
||||
emu_status_msg(renderer_names[get_renderer()]);
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
static void RunEventsPico(unsigned int events)
|
||||
{
|
||||
int ret, px, py, lim_x;
|
||||
static int pdown_frames = 0;
|
||||
|
||||
// for F200
|
||||
ret = gp2x_touchpad_read(&px, &py);
|
||||
if (ret >= 0)
|
||||
{
|
||||
if (ret > 35000)
|
||||
{
|
||||
if (pdown_frames++ > 5)
|
||||
PicoPad[0] |= 0x20;
|
||||
|
||||
pico_pen_x = px;
|
||||
pico_pen_y = py;
|
||||
if (!(Pico.video.reg[12]&1)) {
|
||||
pico_pen_x -= 32;
|
||||
if (pico_pen_x < 0) pico_pen_x = 0;
|
||||
if (pico_pen_x > 248) pico_pen_x = 248;
|
||||
}
|
||||
if (pico_pen_y > 224) pico_pen_y = 224;
|
||||
}
|
||||
else
|
||||
pdown_frames = 0;
|
||||
|
||||
//if (ret == 0)
|
||||
// PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void plat_update_volume(int has_changed, int is_up)
|
||||
{
|
||||
static int prev_frame = 0, wait_frames = 0;
|
||||
int vol = currentConfig.volume;
|
||||
int need_low_volume = 0;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
if ((PicoOpt & POPT_EN_STEREO) && soc == SOCID_MMSP2)
|
||||
need_low_volume = 1;
|
||||
|
||||
if (has_changed)
|
||||
{
|
||||
if (need_low_volume && vol < 5 && prev_frame == Pico.m.frame_count - 1 && wait_frames < 12)
|
||||
wait_frames++;
|
||||
else {
|
||||
if (is_up) {
|
||||
if (vol < 99) vol++;
|
||||
} else {
|
||||
if (vol > 0) vol--;
|
||||
}
|
||||
wait_frames = 0;
|
||||
sndout_oss_setvol(vol, vol);
|
||||
currentConfig.volume = vol;
|
||||
}
|
||||
emu_status_msg("VOL: %02i", vol);
|
||||
prev_frame = Pico.m.frame_count;
|
||||
}
|
||||
|
||||
if (!need_low_volume)
|
||||
return;
|
||||
|
||||
/* set the right mixer func */
|
||||
if (vol >= 5)
|
||||
PsndMix_32_to_16l = mix_32_to_16l_stereo;
|
||||
else {
|
||||
mix_32_to_16l_level = 5 - vol;
|
||||
PsndMix_32_to_16l = mix_32_to_16l_stereo_lvl;
|
||||
}
|
||||
}
|
||||
|
||||
static void oss_write_nonblocking(int len)
|
||||
{
|
||||
// sndout_oss_can_write() is not reliable, only use with no_frmlimit
|
||||
if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len))
|
||||
return;
|
||||
|
||||
sndout_oss_write_nb(PsndOut, len);
|
||||
}
|
||||
|
||||
void pemu_sound_start(void)
|
||||
{
|
||||
static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;
|
||||
|
||||
PsndOut = NULL;
|
||||
|
||||
// prepare sound stuff
|
||||
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||
{
|
||||
int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;
|
||||
int snd_rate_oss = PsndRate;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
memset(sndBuffer, 0, sizeof(sndBuffer));
|
||||
PsndOut = sndBuffer;
|
||||
PicoWriteSound = oss_write_nonblocking;
|
||||
plat_update_volume(0, 0);
|
||||
|
||||
printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
|
||||
PsndRate, PsndLen, is_stereo, Pico.m.pal);
|
||||
sndout_oss_start(snd_rate_oss, is_stereo, 1);
|
||||
sndout_oss_setvol(currentConfig.volume, currentConfig.volume);
|
||||
|
||||
soc = soc_detect();
|
||||
if (soc == SOCID_POLLUX)
|
||||
PsndRate = pollux_get_real_snd_rate(PsndRate);
|
||||
|
||||
#define SOUND_RERATE_FLAGS (POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO|POPT_EXT_FM|POPT_EN_MCD_CDDA)
|
||||
if (PsndRate != PsndRate_old || Pico.m.pal != pal_old || ((PicoOpt & POPT_EXT_FM) && crashed_940) ||
|
||||
((PicoOpt ^ PicoOpt_old) & SOUND_RERATE_FLAGS)) {
|
||||
PsndRerate(Pico.m.frame_count ? 1 : 0);
|
||||
}
|
||||
|
||||
PsndRate_old = PsndRate;
|
||||
PicoOpt_old = PicoOpt;
|
||||
pal_old = Pico.m.pal;
|
||||
}
|
||||
}
|
||||
|
||||
static const int sound_rates[] = { 44100, 32000, 22050, 16000, 11025, 8000 };
|
||||
|
||||
void pemu_sound_stop(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* get back from Pollux pain */
|
||||
PsndRate += 1000;
|
||||
for (i = 0; i < ARRAY_SIZE(sound_rates); i++) {
|
||||
if (PsndRate >= sound_rates[i]) {
|
||||
PsndRate = sound_rates[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_sound_wait(void)
|
||||
{
|
||||
// don't need to do anything, writes will block by themselves
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
doing_bg_frame = 1;
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
PicoDraw32xSetFrameMode(0, 0);
|
||||
PicoDrawSetCallbacks(NULL, NULL);
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
emu_cmn_forced_frame(no_scale, do_emu);
|
||||
|
||||
g_menubg_src_ptr = g_screen_ptr;
|
||||
doing_bg_frame = 0;
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void tga_dump(void)
|
||||
{
|
||||
#define BYTE unsigned char
|
||||
#define WORD unsigned short
|
||||
struct
|
||||
{
|
||||
BYTE IDLength; /* 00h Size of Image ID field */
|
||||
BYTE ColorMapType; /* 01h Color map type */
|
||||
BYTE ImageType; /* 02h Image type code */
|
||||
WORD CMapStart; /* 03h Color map origin */
|
||||
WORD CMapLength; /* 05h Color map length */
|
||||
BYTE CMapDepth; /* 07h Depth of color map entries */
|
||||
WORD XOffset; /* 08h X origin of image */
|
||||
WORD YOffset; /* 0Ah Y origin of image */
|
||||
WORD Width; /* 0Ch Width of image */
|
||||
WORD Height; /* 0Eh Height of image */
|
||||
BYTE PixelDepth; /* 10h Image pixel size */
|
||||
BYTE ImageDescriptor; /* 11h Image descriptor byte */
|
||||
} __attribute__((packed)) TGAHEAD;
|
||||
static unsigned short oldscr[320*240];
|
||||
FILE *f; char name[128]; int i;
|
||||
|
||||
memset(&TGAHEAD, 0, sizeof(TGAHEAD));
|
||||
TGAHEAD.ImageType = 2;
|
||||
TGAHEAD.Width = 320;
|
||||
TGAHEAD.Height = 240;
|
||||
TGAHEAD.PixelDepth = 16;
|
||||
TGAHEAD.ImageDescriptor = 2<<4; // image starts at top-left
|
||||
|
||||
#define CONV(X) (((X>>1)&0x7fe0)|(X&0x1f)) // 555?
|
||||
|
||||
for (i = 0; i < 320*240; i++)
|
||||
if(oldscr[i] != CONV(((unsigned short *)g_screen_ptr)[i])) break;
|
||||
if (i < 320*240)
|
||||
{
|
||||
for (i = 0; i < 320*240; i++)
|
||||
oldscr[i] = CONV(((unsigned short *)g_screen_ptr)[i]);
|
||||
sprintf(name, "%05i.tga", Pico.m.frame_count);
|
||||
f = fopen(name, "wb");
|
||||
if (!f) { printf("!f\n"); exit(1); }
|
||||
fwrite(&TGAHEAD, 1, sizeof(TGAHEAD), f);
|
||||
fwrite(oldscr, 1, 320*240*2, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
static int gp2x_old_clock = -1, EmuOpt_old = 0, pal_old = 0;
|
||||
static int gp2x_old_gamma = 100;
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
|
||||
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_RAM_TIMINGS) {
|
||||
if (currentConfig.EmuOpt & EOPT_RAM_TIMINGS)
|
||||
set_ram_timings();
|
||||
else
|
||||
unset_ram_timings();
|
||||
}
|
||||
|
||||
if (gp2x_old_clock < 0)
|
||||
gp2x_old_clock = default_cpu_clock;
|
||||
if (gp2x_old_clock != currentConfig.CPUclock && gp2x_set_cpuclk != NULL) {
|
||||
printf("changing clock to %i...", currentConfig.CPUclock); fflush(stdout);
|
||||
gp2x_set_cpuclk(currentConfig.CPUclock);
|
||||
gp2x_old_clock = currentConfig.CPUclock;
|
||||
printf(" done\n");
|
||||
}
|
||||
|
||||
if (gp2x_old_gamma != currentConfig.gamma || ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_A_SN_GAMMA)) {
|
||||
set_lcd_gamma(currentConfig.gamma, !!(currentConfig.EmuOpt & EOPT_A_SN_GAMMA));
|
||||
gp2x_old_gamma = currentConfig.gamma;
|
||||
printf("updated gamma to %i, A_SN's curve: %i\n", currentConfig.gamma, !!(currentConfig.EmuOpt&0x1000));
|
||||
}
|
||||
|
||||
if (((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_VSYNC) || Pico.m.pal != pal_old) {
|
||||
if ((currentConfig.EmuOpt & EOPT_VSYNC) || soc == SOCID_POLLUX)
|
||||
set_lcd_custom_rate(Pico.m.pal);
|
||||
else if (EmuOpt_old & EOPT_VSYNC)
|
||||
unset_lcd_custom_rate();
|
||||
}
|
||||
|
||||
if (gp2x_dev_id == GP2X_DEV_CAANOO)
|
||||
in_set_config_int(in_name_to_id("evdev:pollux-analog"), IN_CFG_ABS_DEAD_ZONE,
|
||||
currentConfig.analog_deadzone);
|
||||
|
||||
if ((EmuOpt_old ^ currentConfig.EmuOpt) & EOPT_MMUHACK)
|
||||
gp2x_make_fb_bufferable(currentConfig.EmuOpt & EOPT_MMUHACK);
|
||||
|
||||
EmuOpt_old = currentConfig.EmuOpt;
|
||||
pal_old = Pico.m.pal;
|
||||
|
||||
// make sure we are in correct mode
|
||||
change_renderer(0);
|
||||
vid_reset_mode();
|
||||
|
||||
// dirty buffers better go now than during gameplay
|
||||
sync();
|
||||
sleep(0);
|
||||
|
||||
pemu_sound_start();
|
||||
}
|
||||
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
|
||||
/* do one more frame for menu bg */
|
||||
pemu_forced_frame(0, 1);
|
||||
}
|
||||
|
128
gp2x/menu.c
128
gp2x/menu.c
|
@ -1,128 +0,0 @@
|
|||
#include <time.h>
|
||||
#include "soc.h"
|
||||
#include "plat_gp2x.h"
|
||||
|
||||
static void menu_main_plat_draw(void)
|
||||
{
|
||||
static time_t last_bat_read = 0;
|
||||
static int last_bat_val = -1;
|
||||
unsigned short *bp = g_screen_ptr;
|
||||
int bat_h = me_mfont_h * 2 / 3;
|
||||
int i, u, w, wfill, batt_val;
|
||||
struct tm *tmp;
|
||||
time_t ltime;
|
||||
char time_s[16];
|
||||
|
||||
if (!(currentConfig.EmuOpt & EOPT_SHOW_RTC))
|
||||
return;
|
||||
|
||||
ltime = time(NULL);
|
||||
tmp = gmtime(<ime);
|
||||
strftime(time_s, sizeof(time_s), "%H:%M", tmp);
|
||||
|
||||
text_out16(g_screen_width - me_mfont_w * 6, me_mfont_h + 2, time_s);
|
||||
|
||||
if (ltime - last_bat_read > 10) {
|
||||
last_bat_read = ltime;
|
||||
last_bat_val = batt_val = gp2x_read_battery();
|
||||
}
|
||||
else
|
||||
batt_val = last_bat_val;
|
||||
|
||||
if (batt_val < 0 || batt_val > 100)
|
||||
return;
|
||||
|
||||
/* battery info */
|
||||
bp += (me_mfont_h * 2 + 2) * g_screen_width + g_screen_width - me_mfont_w * 3 - 3;
|
||||
for (i = 0; i < me_mfont_w * 2; i++)
|
||||
bp[i] = menu_text_color;
|
||||
for (i = 0; i < me_mfont_w * 2; i++)
|
||||
bp[i + g_screen_width * bat_h] = menu_text_color;
|
||||
for (i = 0; i <= bat_h; i++)
|
||||
bp[i * g_screen_width] =
|
||||
bp[i * g_screen_width + me_mfont_w * 2] = menu_text_color;
|
||||
for (i = 2; i < bat_h - 1; i++)
|
||||
bp[i * g_screen_width - 1] =
|
||||
bp[i * g_screen_width - 2] = menu_text_color;
|
||||
|
||||
w = me_mfont_w * 2 - 1;
|
||||
wfill = batt_val * w / 100;
|
||||
for (u = 1; u < bat_h; u++)
|
||||
for (i = 0; i < wfill; i++)
|
||||
bp[(w - i) + g_screen_width * u] = menu_text_color;
|
||||
}
|
||||
|
||||
// ------------ gfx options menu ------------
|
||||
|
||||
static const char *mgn_aopt_gamma(int id, int *offs)
|
||||
{
|
||||
sprintf(static_buff, "%i.%02i", currentConfig.gamma / 100, currentConfig.gamma % 100);
|
||||
return static_buff;
|
||||
}
|
||||
|
||||
|
||||
const char *men_scaling_opts[] = { "OFF", "software", "hardware", NULL };
|
||||
|
||||
#define MENU_OPTIONS_GFX \
|
||||
mee_enum ("Horizontal scaling", MA_OPT_SCALING, currentConfig.scaling, men_scaling_opts), \
|
||||
mee_enum ("Vertical scaling", MA_OPT_VSCALING, currentConfig.vscaling, men_scaling_opts), \
|
||||
mee_onoff ("Tearing Fix", MA_OPT_TEARING_FIX, currentConfig.EmuOpt, EOPT_WIZ_TEAR_FIX), \
|
||||
mee_range_cust("Gamma correction", MA_OPT2_GAMMA, currentConfig.gamma, 1, 300, mgn_aopt_gamma), \
|
||||
mee_onoff ("A_SN's gamma curve", MA_OPT2_A_SN_GAMMA, currentConfig.EmuOpt, EOPT_A_SN_GAMMA), \
|
||||
mee_onoff ("Vsync", MA_OPT2_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC),
|
||||
|
||||
#define MENU_OPTIONS_ADV \
|
||||
mee_onoff ("Use second CPU for sound", MA_OPT_ARM940_SOUND, PicoOpt, POPT_EXT_FM), \
|
||||
mee_onoff ("RAM overclock", MA_OPT2_RAMTIMINGS, currentConfig.EmuOpt, EOPT_RAM_TIMINGS), \
|
||||
mee_onoff ("MMU hack", MA_OPT2_SQUIDGEHACK, currentConfig.EmuOpt, EOPT_MMUHACK), \
|
||||
mee_onoff ("SVP dynarec", MA_OPT2_SVP_DYNAREC, PicoOpt, POPT_EN_SVP_DRC), \
|
||||
mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC),
|
||||
|
||||
|
||||
static menu_entry e_menu_adv_options[];
|
||||
static menu_entry e_menu_gfx_options[];
|
||||
static menu_entry e_menu_options[];
|
||||
static menu_entry e_menu_keyconfig[];
|
||||
|
||||
void gp2x_menu_init(void)
|
||||
{
|
||||
static menu_entry *cpu_clk_ent;
|
||||
int i;
|
||||
|
||||
i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
|
||||
cpu_clk_ent = &e_menu_options[i];
|
||||
|
||||
/* disable by default.. */
|
||||
me_enable(e_menu_adv_options, MA_OPT_ARM940_SOUND, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT_TEARING_FIX, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_GAMMA, 0);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_A_SN_GAMMA, 0);
|
||||
|
||||
switch (gp2x_dev_id) {
|
||||
case GP2X_DEV_GP2X:
|
||||
me_enable(e_menu_adv_options, MA_OPT_ARM940_SOUND, 1);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_GAMMA, 1);
|
||||
me_enable(e_menu_gfx_options, MA_OPT2_A_SN_GAMMA, 1);
|
||||
cpu_clk_ent->name = "GP2X CPU clocks";
|
||||
break;
|
||||
case GP2X_DEV_WIZ:
|
||||
me_enable(e_menu_gfx_options, MA_OPT_TEARING_FIX, 1);
|
||||
cpu_clk_ent->name = "Wiz/Caanoo CPU clock";
|
||||
break;
|
||||
case GP2X_DEV_CAANOO:
|
||||
cpu_clk_ent->name = "Wiz/Caanoo CPU clock";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gp2x_set_cpuclk == NULL)
|
||||
cpu_clk_ent->name = "";
|
||||
|
||||
if (gp2x_dev_id != GP2X_DEV_GP2X)
|
||||
men_scaling_opts[2] = NULL; /* leave only off and sw */
|
||||
|
||||
if (gp2x_dev_id != GP2X_DEV_CAANOO)
|
||||
me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
|
||||
}
|
||||
|
233
gp2x/plat.c
233
gp2x/plat.c
|
@ -1,233 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "plat_gp2x.h"
|
||||
#include "soc.h"
|
||||
#include "warm.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/readpng.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/input.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
|
||||
#include <pico/pico.h>
|
||||
|
||||
/* GP2X local */
|
||||
int default_cpu_clock;
|
||||
int gp2x_dev_id;
|
||||
int gp2x_current_bpp;
|
||||
void *gp2x_screens[4];
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
static const char * const caanoo_keys[KEY_MAX + 1] = {
|
||||
[0 ... KEY_MAX] = NULL,
|
||||
[KEY_UP] = "Up",
|
||||
[KEY_LEFT] = "Left",
|
||||
[KEY_RIGHT] = "Right",
|
||||
[KEY_DOWN] = "Down",
|
||||
[BTN_TRIGGER] = "A",
|
||||
[BTN_THUMB] = "X",
|
||||
[BTN_THUMB2] = "B",
|
||||
[BTN_TOP] = "Y",
|
||||
[BTN_TOP2] = "L",
|
||||
[BTN_PINKIE] = "R",
|
||||
[BTN_BASE] = "Home",
|
||||
[BTN_BASE2] = "Lock",
|
||||
[BTN_BASE3] = "I",
|
||||
[BTN_BASE4] = "II",
|
||||
[BTN_BASE5] = "Push",
|
||||
};
|
||||
|
||||
struct in_default_bind in_evdev_defbinds[] =
|
||||
{
|
||||
/* MXYZ SACB RLDU */
|
||||
{ KEY_UP, IN_BINDTYPE_PLAYER12, 0 },
|
||||
{ KEY_DOWN, IN_BINDTYPE_PLAYER12, 1 },
|
||||
{ KEY_LEFT, IN_BINDTYPE_PLAYER12, 2 },
|
||||
{ KEY_RIGHT, IN_BINDTYPE_PLAYER12, 3 },
|
||||
{ KEY_S, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ KEY_D, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ KEY_A, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ KEY_ENTER, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ KEY_BACKSLASH, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
/* Caanoo */
|
||||
{ BTN_THUMB, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ BTN_THUMB2, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ BTN_TRIGGER, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ BTN_BASE3, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ BTN_TOP2, IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
|
||||
{ BTN_PINKIE, IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
|
||||
{ BTN_BASE, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
void gp2x_video_changemode(int bpp)
|
||||
{
|
||||
gp2x_video_changemode_ll(bpp);
|
||||
|
||||
gp2x_current_bpp = bpp < 0 ? -bpp : bpp;
|
||||
}
|
||||
|
||||
static void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)
|
||||
{
|
||||
char *dst;
|
||||
if (buffers & (1<<0)) { dst = (char *)gp2x_screens[0] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<1)) { dst = (char *)gp2x_screens[1] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<2)) { dst = (char *)gp2x_screens[2] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
if (buffers & (1<<3)) { dst = (char *)gp2x_screens[3] + offset; if (dst != data) memcpy(dst, data, len); }
|
||||
}
|
||||
|
||||
void gp2x_memcpy_all_buffers(void *data, int offset, int len)
|
||||
{
|
||||
gp2x_memcpy_buffers(0xf, data, offset, len);
|
||||
}
|
||||
|
||||
void gp2x_memset_all_buffers(int offset, int byte, int len)
|
||||
{
|
||||
memset((char *)gp2x_screens[0] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[1] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[2] + offset, byte, len);
|
||||
memset((char *)gp2x_screens[3] + offset, byte, len);
|
||||
}
|
||||
|
||||
void gp2x_make_fb_bufferable(int yes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
yes = yes ? 1 : 0;
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[0], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[1], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[2], 320*240*2);
|
||||
ret |= warm_change_cb_range(WCB_B_BIT, yes, gp2x_screens[3], 320*240*2);
|
||||
|
||||
if (ret)
|
||||
fprintf(stderr, "could not make fb buferable.\n");
|
||||
else
|
||||
printf("made fb buferable.\n");
|
||||
}
|
||||
|
||||
/* common */
|
||||
void plat_video_menu_enter(int is_rom_loaded)
|
||||
{
|
||||
if (gp2x_current_bpp != 16 || gp2x_dev_id == GP2X_DEV_WIZ) {
|
||||
/* try to switch nicely avoiding glitches */
|
||||
gp2x_video_wait_vsync();
|
||||
memset(gp2x_screens[0], 0, 320*240*2);
|
||||
memset(gp2x_screens[1], 0, 320*240*2);
|
||||
gp2x_video_flip2(); // might flip to fb2/3
|
||||
gp2x_video_flip2(); // ..so we do it again
|
||||
}
|
||||
else
|
||||
gp2x_video_flip2();
|
||||
|
||||
// switch to 16bpp
|
||||
gp2x_video_changemode_ll(16);
|
||||
gp2x_video_RGB_setscaling(0, 320, 240);
|
||||
}
|
||||
|
||||
void plat_video_menu_begin(void)
|
||||
{
|
||||
g_menuscreen_ptr = g_screen_ptr;
|
||||
}
|
||||
|
||||
void plat_video_menu_end(void)
|
||||
{
|
||||
gp2x_video_flip2();
|
||||
}
|
||||
|
||||
void plat_early_init(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
FILE *f;
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
default_cpu_clock = 200;
|
||||
gp2x_dev_id = GP2X_DEV_GP2X;
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
default_cpu_clock = 533;
|
||||
f = fopen("/dev/accel", "rb");
|
||||
if (f) {
|
||||
printf("detected Caanoo\n");
|
||||
gp2x_dev_id = GP2X_DEV_CAANOO;
|
||||
fclose(f);
|
||||
}
|
||||
else {
|
||||
printf("detected Wiz\n");
|
||||
gp2x_dev_id = GP2X_DEV_WIZ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("could not recognize SoC, running in dummy mode.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// just use gettimeofday until plat_init()
|
||||
gp2x_get_ticks_ms = plat_get_ticks_ms_good;
|
||||
gp2x_get_ticks_us = plat_get_ticks_us_good;
|
||||
}
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
mmsp2_init();
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
pollux_init();
|
||||
break;
|
||||
default:
|
||||
dummy_init();
|
||||
break;
|
||||
}
|
||||
|
||||
warm_init();
|
||||
|
||||
gp2x_memset_all_buffers(0, 0, 320*240*2);
|
||||
|
||||
// use buffer2 for menubg to save mem (using only buffers 0, 1 in menu)
|
||||
g_menubg_ptr = gp2x_screens[2];
|
||||
|
||||
// snd
|
||||
sndout_oss_init();
|
||||
|
||||
if (gp2x_dev_id == GP2X_DEV_CAANOO)
|
||||
in_set_config(in_name_to_id("evdev:pollux-analog"), IN_CFG_KEY_NAMES,
|
||||
caanoo_keys, sizeof(caanoo_keys));
|
||||
|
||||
gp2x_menu_init();
|
||||
}
|
||||
|
||||
void plat_finish(void)
|
||||
{
|
||||
gp2x_soc_t soc;
|
||||
|
||||
warm_finish();
|
||||
|
||||
soc = soc_detect();
|
||||
switch (soc)
|
||||
{
|
||||
case SOCID_MMSP2:
|
||||
mmsp2_finish();
|
||||
break;
|
||||
case SOCID_POLLUX:
|
||||
pollux_finish();
|
||||
break;
|
||||
default:
|
||||
dummy_finish();
|
||||
break;
|
||||
}
|
||||
|
||||
sndout_oss_exit();
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define CASE_SENSITIVE_FS 1 // CS filesystem
|
||||
#define DONT_OPEN_MANY_FILES 0
|
||||
#define REDUCE_IO_CALLS 0
|
||||
#define SIMPLE_WRITE_SOUND 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 1
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define MSCREEN_SIZE_FIXED 1
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
|
||||
// pico.c
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
// logging emu events
|
||||
#define EL_LOGMASK (EL_STATUS)
|
||||
// (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL|EL_IDLE)
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "/"
|
||||
#define PATH_SEP_C '/'
|
||||
#define MENU_X2 0
|
||||
|
||||
#endif //PORT_CONFIG_H
|
|
@ -1,13 +0,0 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
@ .equiv START_ROW, 1
|
||||
@ .equiv END_ROW, 27
|
||||
@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
|
||||
.equiv START_ROW, 0
|
||||
.equiv END_ROW, 28
|
||||
|
||||
.equiv UNALIGNED_DRAWLINEDEST, 0
|
||||
|
||||
@ this should be set to one only for GP2X port
|
||||
.equiv EXTERNAL_YM2612, 1
|
||||
|
37
gp2x/test.c
37
gp2x/test.c
|
@ -1,37 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "gp2x.h"
|
||||
|
||||
void spend_cycles(int c);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct timeval tval; // timing
|
||||
int thissec = 0, frames_done = 0;
|
||||
|
||||
gp2x_init();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
gettimeofday(&tval, 0);
|
||||
|
||||
if(thissec != tval.tv_sec)
|
||||
{
|
||||
thissec = tval.tv_sec;
|
||||
|
||||
printf("frames_done: %i\n", frames_done);
|
||||
frames_done = 0;
|
||||
}
|
||||
|
||||
|
||||
//gp2x_video_wait_vsync();
|
||||
//usleep(1); // sleeps a minimum of ~20ms
|
||||
//gp2x_video_flip(); // can be called ~430000 times/sec
|
||||
spend_cycles(1000);
|
||||
frames_done++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#define VERSION "1.80"
|
||||
|
254
gp2x/warm.c
254
gp2x/warm.c
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* wARM - exporting ARM processor specific privileged services to userspace
|
||||
* userspace part
|
||||
*
|
||||
* Copyright (c) Gražvydas "notaz" Ignotas, 2009
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the organization 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define WARM_CODE
|
||||
#include "warm.h"
|
||||
|
||||
/* provided by glibc */
|
||||
extern long init_module(void *, unsigned long, const char *);
|
||||
extern long delete_module(const char *, unsigned int);
|
||||
|
||||
static int warm_fd = -1;
|
||||
static int kernel_version;
|
||||
|
||||
static void sys_cacheflush(void *start, void *end)
|
||||
{
|
||||
#ifdef __ARM_EABI__
|
||||
/* EABI version */
|
||||
int num = __ARM_NR_cacheflush;
|
||||
__asm__("mov r0, %0 ;"
|
||||
"mov r1, %1 ;"
|
||||
"mov r2, #0 ;"
|
||||
"mov r7, %2 ;"
|
||||
"swi 0" : : "r" (start), "r" (end), "r" (num)
|
||||
: "r0", "r1", "r2", "r3", "r7");
|
||||
#else
|
||||
/* OABI */
|
||||
__asm__("mov r0, %0 ;"
|
||||
"mov r1, %1 ;"
|
||||
"mov r2, #0 ;"
|
||||
"swi %2" : : "r" (start), "r" (end), "i" __ARM_NR_cacheflush
|
||||
: "r0", "r1", "r2", "r3");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Those are here because system() occasionaly fails on Wiz
|
||||
* with errno 12 for some unknown reason */
|
||||
static int manual_insmod_26(const char *fname, const char *opts)
|
||||
{
|
||||
unsigned long len, read_len;
|
||||
int ret = -1;
|
||||
void *buff;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(fname, "rb");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
buff = malloc(len);
|
||||
if (buff == NULL)
|
||||
goto fail0;
|
||||
|
||||
read_len = fread(buff, 1, len, f);
|
||||
if (read_len != len) {
|
||||
fprintf(stderr, "failed to read module\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
ret = init_module(buff, len, opts);
|
||||
|
||||
fail1:
|
||||
free(buff);
|
||||
fail0:
|
||||
fclose(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int manual_rmmod(const char *name)
|
||||
{
|
||||
return delete_module(name, O_NONBLOCK|O_EXCL);
|
||||
}
|
||||
|
||||
int warm_init(void)
|
||||
{
|
||||
struct utsname unm;
|
||||
char buff1[32], buff2[128];
|
||||
int ret;
|
||||
|
||||
memset(&unm, 0, sizeof(unm));
|
||||
uname(&unm);
|
||||
|
||||
if (strlen(unm.release) < 3 || unm.release[1] != '.') {
|
||||
fprintf(stderr, "unexpected version string: %s\n", unm.release);
|
||||
goto fail;
|
||||
}
|
||||
kernel_version = ((unm.release[0] - '0') << 4) | (unm.release[2] - '0');
|
||||
|
||||
warm_fd = open("/proc/warm", O_RDWR);
|
||||
if (warm_fd >= 0)
|
||||
return 0;
|
||||
|
||||
snprintf(buff1, sizeof(buff1), "warm_%s.%s", unm.release, kernel_version >= 0x26 ? "ko" : "o");
|
||||
snprintf(buff2, sizeof(buff2), "/sbin/insmod %s verbose=1", buff1);
|
||||
|
||||
/* try to insmod */
|
||||
ret = system(buff2);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "system/insmod failed: %d %d\n", ret, errno);
|
||||
if (kernel_version >= 0x26) {
|
||||
ret = manual_insmod_26(buff1, "verbose=1");
|
||||
if (ret != 0)
|
||||
fprintf(stderr, "manual insmod also failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
warm_fd = open("/proc/warm", O_RDWR);
|
||||
if (warm_fd >= 0)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "wARM: can't init, acting as sys_cacheflush wrapper\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void warm_finish(void)
|
||||
{
|
||||
char name[32], cmd[64];
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0)
|
||||
return;
|
||||
|
||||
close(warm_fd);
|
||||
warm_fd = -1;
|
||||
|
||||
if (kernel_version < 0x26) {
|
||||
struct utsname unm;
|
||||
memset(&unm, 0, sizeof(unm));
|
||||
uname(&unm);
|
||||
snprintf(name, sizeof(name), "warm_%s", unm.release);
|
||||
}
|
||||
else
|
||||
strcpy(name, "warm");
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/rmmod %s", name);
|
||||
ret = system(cmd);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "system/rmmod failed: %d %d\n", ret, errno);
|
||||
manual_rmmod(name);
|
||||
}
|
||||
}
|
||||
|
||||
int warm_cache_op_range(int op, void *addr, unsigned long size)
|
||||
{
|
||||
struct warm_cache_op wop;
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0) {
|
||||
/* note that this won't work for warm_cache_op_all */
|
||||
sys_cacheflush(addr, (char *)addr + size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wop.ops = op;
|
||||
wop.addr = (unsigned long)addr;
|
||||
wop.size = size;
|
||||
|
||||
ret = ioctl(warm_fd, WARMC_CACHE_OP, &wop);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_CACHE_OP failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int warm_cache_op_all(int op)
|
||||
{
|
||||
return warm_cache_op_range(op, NULL, (unsigned long)-1);
|
||||
}
|
||||
|
||||
int warm_change_cb_range(int cb, int is_set, void *addr, unsigned long size)
|
||||
{
|
||||
struct warm_change_cb ccb;
|
||||
int ret;
|
||||
|
||||
if (warm_fd < 0)
|
||||
return -1;
|
||||
|
||||
ccb.addr = (unsigned long)addr;
|
||||
ccb.size = size;
|
||||
ccb.cb = cb;
|
||||
ccb.is_set = is_set;
|
||||
|
||||
ret = ioctl(warm_fd, WARMC_CHANGE_CB, &ccb);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_CHANGE_CB failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int warm_change_cb_upper(int cb, int is_set)
|
||||
{
|
||||
return warm_change_cb_range(cb, is_set, 0, 0);
|
||||
}
|
||||
|
||||
unsigned long warm_virt2phys(const void *ptr)
|
||||
{
|
||||
unsigned long ptrio;
|
||||
int ret;
|
||||
|
||||
ptrio = (unsigned long)ptr;
|
||||
ret = ioctl(warm_fd, WARMC_VIRT2PHYS, &ptrio);
|
||||
if (ret != 0) {
|
||||
perror("WARMC_VIRT2PHYS failed");
|
||||
return (unsigned long)-1;
|
||||
}
|
||||
|
||||
return ptrio;
|
||||
}
|
||||
|
100
gp2x/warm.h
100
gp2x/warm.h
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* wARM - exporting ARM processor specific privileged services to userspace
|
||||
* library functions
|
||||
*
|
||||
* Copyright (c) Gražvydas "notaz" Ignotas, 2009
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of the organization 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
#ifndef __WARM_H__
|
||||
#define __WARM_H__ 1
|
||||
|
||||
/* cache operations (warm_cache_op_*):
|
||||
* o clean - write dirty data to memory, but also leave in cache.
|
||||
* o invalidate - throw away everything in cache, losing dirty data.
|
||||
*
|
||||
* Write buffer is always drained, no ops will only drain WB
|
||||
*/
|
||||
#define WOP_D_CLEAN (1 << 0)
|
||||
#define WOP_D_INVALIDATE (1 << 1)
|
||||
#define WOP_I_INVALIDATE (1 << 2)
|
||||
|
||||
/* change C and B bits (warm_change_cb_*)
|
||||
* if is_set in not zero, bits are set, else cleared.
|
||||
* the address for range function is virtual address.
|
||||
*/
|
||||
#define WCB_C_BIT (1 << 0)
|
||||
#define WCB_B_BIT (1 << 1)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int warm_init(void);
|
||||
|
||||
int warm_cache_op_range(int ops, void *virt_addr, unsigned long size);
|
||||
int warm_cache_op_all(int ops);
|
||||
|
||||
int warm_change_cb_upper(int cb, int is_set);
|
||||
int warm_change_cb_range(int cb, int is_set, void *virt_addr, unsigned long size);
|
||||
|
||||
unsigned long warm_virt2phys(const void *ptr);
|
||||
|
||||
void warm_finish(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* internal */
|
||||
#ifdef WARM_CODE
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define WARM_IOCTL_BASE 'A'
|
||||
|
||||
struct warm_cache_op
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
int ops;
|
||||
};
|
||||
|
||||
struct warm_change_cb
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long size;
|
||||
int cb;
|
||||
int is_set;
|
||||
};
|
||||
|
||||
#define WARMC_CACHE_OP _IOW(WARM_IOCTL_BASE, 0, struct warm_cache_op)
|
||||
#define WARMC_CHANGE_CB _IOW(WARM_IOCTL_BASE, 1, struct warm_change_cb)
|
||||
#define WARMC_VIRT2PHYS _IOWR(WARM_IOCTL_BASE, 2, unsigned long)
|
||||
|
||||
#endif /* WARM_CODE */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
#endif /* __WARM_H__ */
|
|
@ -1,97 +0,0 @@
|
|||
# settings
|
||||
#use_fbdev = 1
|
||||
#fake_in_gp2x = 1
|
||||
|
||||
use_musashi = 1
|
||||
#use_fame = 1
|
||||
use_cz80 = 1
|
||||
use_sh2drc = 1
|
||||
#use_sh2mame = 1
|
||||
|
||||
#drc_debug = 3
|
||||
#drc_debug_interp = 1
|
||||
#profile = 1
|
||||
|
||||
all: mkdirs PicoDrive
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ifndef ARCH
|
||||
ARCH = x86
|
||||
endif
|
||||
|
||||
DEFINES = _UNZIP_SUPPORT IO_STATS IN_EVDEV
|
||||
CFLAGS += -ggdb -Wall -falign-functions=2
|
||||
CFLAGS += -I../.. -I.
|
||||
LDFLAGS += -lm -lpng
|
||||
ifeq "$(ARCH)" "arm"
|
||||
CFLAGS += -mcpu=arm920t
|
||||
DEFINES += ARM
|
||||
endif
|
||||
|
||||
CC ?= $(CROSS)gcc
|
||||
|
||||
# frontend
|
||||
OBJS += io.o emu.o blit.o in_evdev.o plat.o sndout_oss.o log_io.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/main.o platform/common/emu.o platform/common/menu_pico.o \
|
||||
platform/common/config.o platform/common/fonts.o platform/common/readpng.o \
|
||||
platform/common/input.o
|
||||
|
||||
ifeq "$(use_fbdev)" "1"
|
||||
DEFINES += FBDEV
|
||||
OBJS += fbdev.o
|
||||
else
|
||||
LDFLAGS += -lpthread
|
||||
LDFLAGS += -lX11
|
||||
endif
|
||||
|
||||
ifeq "$(fake_in_gp2x)" "1"
|
||||
DEFINES += IN_GP2X FAKE_IN_GP2X
|
||||
OBJS += platform/gp2x/in_gp2x.o
|
||||
DIRS += platform/gp2x
|
||||
endif
|
||||
|
||||
ifeq "$(ARCH)" "arm"
|
||||
OBJS += pico/carthw/svp/stub_arm.o
|
||||
endif
|
||||
OBJS += pico/sound/mix.o
|
||||
OBJS += pico/carthw/svp/compiler.o
|
||||
|
||||
# zlib
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
|
||||
vpath %.c = ../..
|
||||
vpath %.s = ../..
|
||||
vpath %.S = ../..
|
||||
vpath %.asm = ../..
|
||||
|
||||
DIRS += platform/linux zlib unzip
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||
|
||||
clean: tidy
|
||||
@$(RM) PicoDrive
|
||||
tidy:
|
||||
$(RM) $(OBJS)
|
||||
rm -rf $(DIRS)
|
||||
@make -C ../../cpu/mz80/ clean
|
||||
|
||||
PicoDrive : $(OBJS)
|
||||
@echo ">>>" $@
|
||||
$(CC) $(CFLAGS) $^ $(LDFLAGS) -Wl,-Map=PicoDrive.map -o $@
|
||||
|
||||
pprof: pprof.c
|
||||
$(CROSS)gcc -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@
|
||||
|
||||
%.o : %.asm
|
||||
@echo ">>>" $<
|
||||
nasm -f elf $< -o $@
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
This port tries to emulate gp2x environment on a standard linux box for testing
|
||||
(i.e. to be able to use things like valgrind and efence, gcc runtime
|
||||
optimizations, etc.).
|
||||
|
83
linux/blit.c
83
linux/blit.c
|
@ -1,83 +0,0 @@
|
|||
|
||||
// Convert 0000bbb0 ggg0rrr0 0000bbb0 ggg0rrr0
|
||||
// to 00000000 rrr00000 ggg00000 bbb00000 ...
|
||||
// TODO: rm when gp2x/emu.c is no longer used
|
||||
|
||||
void bgr444_to_rgb32(void *to, void *from)
|
||||
{
|
||||
unsigned short *ps = from;
|
||||
unsigned int *pd = to;
|
||||
int pixels;
|
||||
|
||||
for (pixels = 0x40; pixels; pixels--, ps++, pd++)
|
||||
{
|
||||
*pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0);
|
||||
*pd |= *pd >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
void bgr444_to_rgb32_sh(void *to, void *from)
|
||||
{
|
||||
unsigned short *ps = from;
|
||||
unsigned int *pd = to;
|
||||
int pixels;
|
||||
|
||||
pd += 0x40;
|
||||
for (pixels = 0x40; pixels; pixels--, ps++, pd++)
|
||||
{
|
||||
*pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0);
|
||||
*pd >>= 1;
|
||||
*pd |= *pd >> 3;
|
||||
pd[0x40*2] = *pd;
|
||||
}
|
||||
|
||||
ps -= 0x40;
|
||||
for (pixels = 0x40; pixels; pixels--, ps++, pd++)
|
||||
{
|
||||
*pd = ((*ps<<20)&0xe00000) | ((*ps<<8)&0xe000) | ((*ps>>4)&0xe0);
|
||||
continue;
|
||||
*pd += 0x00404040;
|
||||
if (*pd & 0x01000000) *pd |= 0x00e00000;
|
||||
if (*pd & 0x00010000) *pd |= 0x0000e000;
|
||||
if (*pd & 0x00000100) *pd |= 0x000000e0;
|
||||
*pd &= 0x00e0e0e0;
|
||||
*pd |= *pd >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
void vidcpy_m2(void *dest, void *src, int m32col, int with_32c_border)
|
||||
{
|
||||
unsigned char *pd = dest, *ps = src;
|
||||
int i, u;
|
||||
|
||||
if (m32col) {
|
||||
for (i = 0; i < 224; i++)
|
||||
{
|
||||
ps += 8;
|
||||
pd += 32;
|
||||
for (u = 0; u < 256; u++)
|
||||
*pd++ = *ps++;
|
||||
ps += 64;
|
||||
pd += 32;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 224; i++)
|
||||
{
|
||||
ps += 8;
|
||||
for (u = 0; u < 320; u++)
|
||||
*pd++ = *ps++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vidcpy_m2_rot(void *dest, void *src, int m32col, int with_32c_border)
|
||||
{
|
||||
}
|
||||
|
||||
void rotated_blit8 (void *dst, void *linesx4, int y, int is_32col)
|
||||
{
|
||||
}
|
||||
|
||||
void rotated_blit16(void *dst, void *linesx4, int y, int is_32col)
|
||||
{
|
||||
}
|
300
linux/emu.c
300
linux/emu.c
|
@ -1,300 +0,0 @@
|
|||
// (c) Copyright 2006-2009 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../common/emu.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
|
||||
|
||||
static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
|
||||
const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL };
|
||||
const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL };
|
||||
enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT };
|
||||
|
||||
|
||||
void pemu_prep_defconfig(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
extern int PicoOpt;
|
||||
// PicoOpt &= ~POPT_EXT_FM;
|
||||
PicoOpt &= ~POPT_EN_SVP_DRC;
|
||||
}
|
||||
|
||||
// FIXME: dupes from GP2X, need cleanup
|
||||
static void (*osd_text)(int x, int y, const char *text);
|
||||
|
||||
/*
|
||||
static void osd_text8(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+3) >> 2;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~3;
|
||||
p = (int *) ((char *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = 0xe0e0e0e0;
|
||||
}
|
||||
emu_text_out8(x, y, text);
|
||||
}
|
||||
*/
|
||||
|
||||
static void osd_text16(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int *p, i, h, offs;
|
||||
|
||||
len = (len+1) >> 1;
|
||||
for (h = 0; h < 8; h++) {
|
||||
offs = (x + g_screen_width * (y+h)) & ~1;
|
||||
p = (int *) ((short *)g_screen_ptr + offs);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = (*p >> 2) & 0x39e7;
|
||||
}
|
||||
emu_text_out16(x, y, text);
|
||||
}
|
||||
|
||||
static void draw_cd_leds(void)
|
||||
{
|
||||
int led_reg, pitch, scr_offs, led_offs;
|
||||
led_reg = Pico_mcd->s68k_regs[0];
|
||||
|
||||
pitch = 320;
|
||||
led_offs = 4;
|
||||
scr_offs = pitch * 2 + 4;
|
||||
|
||||
if (currentConfig.renderer != RT_16BIT) {
|
||||
#define p(x) px[(x) >> 2]
|
||||
// 8-bit modes
|
||||
unsigned int *px = (unsigned int *)((char *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
} else {
|
||||
#define p(x) px[(x)*2 >> 2] = px[((x)*2 >> 2) + 1]
|
||||
// 16-bit modes
|
||||
unsigned int *px = (unsigned int *)((short *)g_screen_ptr + scr_offs);
|
||||
unsigned int col_g = (led_reg & 2) ? 0x06000600 : 0;
|
||||
unsigned int col_r = (led_reg & 1) ? 0xc000c000 : 0;
|
||||
p(pitch*0) = p(pitch*1) = p(pitch*2) = col_g;
|
||||
p(pitch*0 + led_offs) = p(pitch*1 + led_offs) = p(pitch*2 + led_offs) = col_r;
|
||||
#undef p
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_finalize_frame(const char *fps, const char *notice)
|
||||
{
|
||||
if (currentConfig.renderer != RT_16BIT && !(PicoAHW & PAHW_32X)) {
|
||||
unsigned short *pd = (unsigned short *)g_screen_ptr + 8 * g_screen_width;
|
||||
unsigned char *ps = PicoDraw2FB + 328*8 + 8;
|
||||
unsigned short *pal = HighPal;
|
||||
int i, x;
|
||||
if (Pico.m.dirtyPal)
|
||||
PicoDrawUpdateHighPal();
|
||||
for (i = 0; i < 224; i++, ps += 8)
|
||||
for (x = 0; x < 320; x++)
|
||||
*pd++ = pal[*ps++];
|
||||
}
|
||||
|
||||
if (notice || (currentConfig.EmuOpt & EOPT_SHOW_FPS)) {
|
||||
if (notice)
|
||||
osd_text(4, g_screen_height - 8, notice);
|
||||
if (currentConfig.EmuOpt & EOPT_SHOW_FPS)
|
||||
osd_text(g_screen_width - 60, g_screen_height - 8, fps);
|
||||
}
|
||||
if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS))
|
||||
draw_cd_leds();
|
||||
}
|
||||
|
||||
static void apply_renderer(void)
|
||||
{
|
||||
switch (currentConfig.renderer) {
|
||||
case RT_16BIT:
|
||||
PicoOpt &= ~POPT_ALT_RENDERER;
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 0);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
break;
|
||||
case RT_8BIT_ACC:
|
||||
PicoOpt &= ~POPT_ALT_RENDERER;
|
||||
PicoDrawSetOutFormat(PDF_8BIT, 0);
|
||||
PicoDrawSetOutBuf(PicoDraw2FB + 8, 328);
|
||||
break;
|
||||
case RT_8BIT_FAST:
|
||||
PicoOpt |= POPT_ALT_RENDERER;
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (PicoAHW & PAHW_32X) {
|
||||
int only_32x = 0;
|
||||
if (currentConfig.renderer == RT_16BIT)
|
||||
only_32x = 1;
|
||||
else
|
||||
PicoDrawSetOutFormat(PDF_NONE, 0);
|
||||
PicoDraw32xSetFrameMode(1, only_32x);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
}
|
||||
//PicoDraw32xSetFrameMode(0, 0);
|
||||
//PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
}
|
||||
|
||||
void plat_video_toggle_renderer(int change, int is_menu)
|
||||
{
|
||||
currentConfig.renderer += change;
|
||||
if (currentConfig.renderer >= RT_COUNT)
|
||||
currentConfig.renderer = 0;
|
||||
else if (currentConfig.renderer < 0)
|
||||
currentConfig.renderer = RT_COUNT - 1;
|
||||
|
||||
if (!is_menu)
|
||||
apply_renderer();
|
||||
|
||||
emu_status_msg(renderer_names[currentConfig.renderer]);
|
||||
}
|
||||
|
||||
void plat_video_menu_enter(int is_rom_loaded)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_begin(void)
|
||||
{
|
||||
g_menuscreen_ptr = g_screen_ptr;
|
||||
}
|
||||
|
||||
void plat_video_menu_end(void)
|
||||
{
|
||||
plat_video_flip();
|
||||
}
|
||||
|
||||
void plat_status_msg_clear(void)
|
||||
{
|
||||
unsigned short *d = (unsigned short *)g_screen_ptr + g_screen_width * g_screen_height;
|
||||
int l = g_screen_width * 8;
|
||||
memset32((int *)(d - l), 0, l * 2 / 4);
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_next(const char *msg)
|
||||
{
|
||||
plat_status_msg_clear();
|
||||
pemu_finalize_frame("", msg);
|
||||
plat_video_flip();
|
||||
emu_status_msg("");
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_first(const char *msg)
|
||||
{
|
||||
// memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);
|
||||
plat_status_msg_busy_next(msg);
|
||||
}
|
||||
|
||||
void plat_update_volume(int has_changed, int is_up)
|
||||
{
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
PicoDraw32xSetFrameMode(0, 0);
|
||||
PicoDrawSetCallbacks(NULL, NULL);
|
||||
Pico.m.dirtyPal = 1;
|
||||
|
||||
emu_cmn_forced_frame(no_scale, do_emu);
|
||||
|
||||
g_menubg_src_ptr = g_screen_ptr;
|
||||
}
|
||||
|
||||
static void oss_write_nonblocking(int len)
|
||||
{
|
||||
// sndout_oss_can_write() is not reliable, only use with no_frmlimit
|
||||
if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len))
|
||||
return;
|
||||
|
||||
sndout_oss_write_nb(PsndOut, len);
|
||||
}
|
||||
|
||||
void pemu_sound_start(void)
|
||||
{
|
||||
PsndOut = NULL;
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||
{
|
||||
int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;
|
||||
|
||||
PsndRerate(Pico.m.frame_count ? 1 : 0);
|
||||
|
||||
printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
|
||||
PsndRate, PsndLen, is_stereo, Pico.m.pal);
|
||||
sndout_oss_start(PsndRate, is_stereo, 1);
|
||||
sndout_oss_setvol(currentConfig.volume, currentConfig.volume);
|
||||
PicoWriteSound = oss_write_nonblocking;
|
||||
plat_update_volume(0, 0);
|
||||
memset(sndBuffer, 0, sizeof(sndBuffer));
|
||||
PsndOut = sndBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_sound_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pemu_sound_wait(void)
|
||||
{
|
||||
// don't need to do anything, writes will block by themselves
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str)
|
||||
{
|
||||
}
|
||||
|
||||
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||
{
|
||||
// clear whole screen in all buffers
|
||||
memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);
|
||||
}
|
||||
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
apply_renderer();
|
||||
osd_text = osd_text16;
|
||||
|
||||
pemu_sound_start();
|
||||
}
|
||||
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
|
||||
/* do one more frame for menu bg */
|
||||
pemu_forced_frame(0, 1);
|
||||
}
|
||||
|
||||
void plat_wait_till_us(unsigned int us_to)
|
||||
{
|
||||
unsigned int now;
|
||||
|
||||
now = plat_get_ticks_us();
|
||||
|
||||
while ((signed int)(us_to - now) > 512)
|
||||
{
|
||||
usleep(1024);
|
||||
now = plat_get_ticks_us();
|
||||
}
|
||||
}
|
||||
|
383
linux/io.c
383
linux/io.c
|
@ -1,383 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../common/emu.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/input.h"
|
||||
#include "sndout_oss.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "log_io.h"
|
||||
|
||||
int current_keys;
|
||||
unsigned char *PicoDraw2FB;
|
||||
|
||||
#ifdef FBDEV
|
||||
|
||||
#include "fbdev.h"
|
||||
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
static int current_bpp = 16;
|
||||
static int current_pal[256];
|
||||
static const char *verstring = "PicoDrive " VERSION;
|
||||
static int scr_changed = 0, scr_w = SCREEN_WIDTH, scr_h = SCREEN_HEIGHT;
|
||||
|
||||
/* faking GP2X pad */
|
||||
enum { GP2X_UP=0x1, GP2X_LEFT=0x4, GP2X_DOWN=0x10, GP2X_RIGHT=0x40,
|
||||
GP2X_START=1<<8, GP2X_SELECT=1<<9, GP2X_L=1<<10, GP2X_R=1<<11,
|
||||
GP2X_A=1<<12, GP2X_B=1<<13, GP2X_X=1<<14, GP2X_Y=1<<15,
|
||||
GP2X_VOL_UP=1<<23, GP2X_VOL_DOWN=1<<22, GP2X_PUSH=1<<27 };
|
||||
|
||||
static void key_press_event(int keycode)
|
||||
{
|
||||
switch (keycode)
|
||||
{
|
||||
case 111:
|
||||
case 0x62: current_keys |= GP2X_UP; break;
|
||||
case 116:
|
||||
case 0x68: current_keys |= GP2X_DOWN; break;
|
||||
case 113:
|
||||
case 0x64: current_keys |= GP2X_LEFT; break;
|
||||
case 114:
|
||||
case 0x66: current_keys |= GP2X_RIGHT; break;
|
||||
case 0x24: current_keys |= GP2X_START; break; // enter
|
||||
case 0x23: current_keys |= GP2X_SELECT;break; // ]
|
||||
case 0x34: current_keys |= GP2X_A; break; // z
|
||||
case 0x35: current_keys |= GP2X_X; break; // x
|
||||
case 0x36: current_keys |= GP2X_B; break; // c
|
||||
case 0x37: current_keys |= GP2X_Y; break; // v
|
||||
case 0x27: current_keys |= GP2X_L; break; // s
|
||||
case 0x28: current_keys |= GP2X_R; break; // d
|
||||
case 0x29: current_keys |= GP2X_PUSH; break; // f
|
||||
case 0x18: current_keys |= GP2X_VOL_DOWN;break; // q
|
||||
case 0x19: current_keys |= GP2X_VOL_UP;break; // w
|
||||
case 0x2d: log_io_clear(); break; // k
|
||||
case 0x2e: log_io_dump(); break; // l
|
||||
case 0x17: { // tab
|
||||
extern int PicoReset(void);
|
||||
PicoReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void key_release_event(int keycode)
|
||||
{
|
||||
switch (keycode)
|
||||
{
|
||||
case 111:
|
||||
case 0x62: current_keys &= ~GP2X_UP; break;
|
||||
case 116:
|
||||
case 0x68: current_keys &= ~GP2X_DOWN; break;
|
||||
case 113:
|
||||
case 0x64: current_keys &= ~GP2X_LEFT; break;
|
||||
case 114:
|
||||
case 0x66: current_keys &= ~GP2X_RIGHT; break;
|
||||
case 0x24: current_keys &= ~GP2X_START; break; // enter
|
||||
case 0x23: current_keys &= ~GP2X_SELECT;break; // ]
|
||||
case 0x34: current_keys &= ~GP2X_A; break; // z
|
||||
case 0x35: current_keys &= ~GP2X_X; break; // x
|
||||
case 0x36: current_keys &= ~GP2X_B; break; // c
|
||||
case 0x37: current_keys &= ~GP2X_Y; break; // v
|
||||
case 0x27: current_keys &= ~GP2X_L; break; // s
|
||||
case 0x28: current_keys &= ~GP2X_R; break; // d
|
||||
case 0x29: current_keys &= ~GP2X_PUSH; break; // f
|
||||
case 0x18: current_keys &= ~GP2X_VOL_DOWN;break; // q
|
||||
case 0x19: current_keys &= ~GP2X_VOL_UP;break; // w
|
||||
}
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
static Display *xlib_display;
|
||||
static Window xlib_window;
|
||||
static XImage *ximage;
|
||||
|
||||
static void ximage_realloc(Display *display, Visual *visual)
|
||||
{
|
||||
void *xlib_screen;
|
||||
|
||||
XLockDisplay(xlib_display);
|
||||
|
||||
if (ximage != NULL)
|
||||
XDestroyImage(ximage);
|
||||
ximage = NULL;
|
||||
|
||||
xlib_screen = calloc(scr_w * scr_h, 4);
|
||||
if (xlib_screen != NULL)
|
||||
ximage = XCreateImage(display, visual, 24, ZPixmap, 0,
|
||||
xlib_screen, scr_w, scr_h, 32, 0);
|
||||
if (ximage == NULL)
|
||||
fprintf(stderr, "failed to alloc ximage\n");
|
||||
|
||||
XUnlockDisplay(xlib_display);
|
||||
}
|
||||
|
||||
static void xlib_update(void)
|
||||
{
|
||||
Status xstatus;
|
||||
|
||||
XLockDisplay(xlib_display);
|
||||
|
||||
xstatus = XPutImage(xlib_display, xlib_window, DefaultGC(xlib_display, 0), ximage,
|
||||
0, 0, 0, 0, g_screen_width, g_screen_height);
|
||||
if (xstatus != 0)
|
||||
fprintf(stderr, "XPutImage %d\n", xstatus);
|
||||
|
||||
XUnlockDisplay(xlib_display);
|
||||
}
|
||||
|
||||
static void *xlib_threadf(void *targ)
|
||||
{
|
||||
unsigned int width, height, display_width, display_height;
|
||||
sem_t *sem = targ;
|
||||
XTextProperty windowName;
|
||||
Window win;
|
||||
XEvent report;
|
||||
Display *display;
|
||||
Visual *visual;
|
||||
int screen;
|
||||
|
||||
XInitThreads();
|
||||
|
||||
xlib_display = display = XOpenDisplay(NULL);
|
||||
if (display == NULL)
|
||||
{
|
||||
fprintf(stderr, "cannot connect to X server %s\n",
|
||||
XDisplayName(NULL));
|
||||
sem_post(sem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
visual = DefaultVisual(display, 0);
|
||||
if (visual->class != TrueColor)
|
||||
{
|
||||
fprintf(stderr, "cannot handle non true color visual\n");
|
||||
XCloseDisplay(display);
|
||||
sem_post(sem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("X vendor: %s, rel: %d, display: %s, protocol ver: %d.%d\n", ServerVendor(display),
|
||||
VendorRelease(display), DisplayString(display), ProtocolVersion(display),
|
||||
ProtocolRevision(display));
|
||||
|
||||
screen = DefaultScreen(display);
|
||||
|
||||
ximage_realloc(display, visual);
|
||||
sem_post(sem);
|
||||
|
||||
display_width = DisplayWidth(display, screen);
|
||||
display_height = DisplayHeight(display, screen);
|
||||
|
||||
xlib_window = win = XCreateSimpleWindow(display,
|
||||
RootWindow(display, screen),
|
||||
display_width / 2 - scr_w / 2,
|
||||
display_height / 2 - scr_h / 2,
|
||||
scr_w + 2, scr_h + 2, 1,
|
||||
BlackPixel(display, screen),
|
||||
BlackPixel(display, screen));
|
||||
|
||||
XStringListToTextProperty((char **)&verstring, 1, &windowName);
|
||||
XSetWMName(display, win, &windowName);
|
||||
|
||||
XSelectInput(display, win, ExposureMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
StructureNotifyMask);
|
||||
|
||||
XMapWindow(display, win);
|
||||
|
||||
while (1)
|
||||
{
|
||||
XNextEvent(display, &report);
|
||||
switch (report.type)
|
||||
{
|
||||
case Expose:
|
||||
while (XCheckTypedEvent(display, Expose, &report))
|
||||
;
|
||||
xlib_update();
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
width = report.xconfigure.width;
|
||||
height = report.xconfigure.height;
|
||||
if (scr_w != width - 2 || scr_h != height - 2) {
|
||||
scr_w = width - 2;
|
||||
scr_h = height - 2;
|
||||
scr_changed = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
break;
|
||||
|
||||
case KeyPress:
|
||||
key_press_event(report.xkey.keycode);
|
||||
break;
|
||||
|
||||
case KeyRelease:
|
||||
key_release_event(report.xkey.keycode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xlib_init(void)
|
||||
{
|
||||
pthread_t x_thread;
|
||||
sem_t xlib_sem;
|
||||
|
||||
sem_init(&xlib_sem, 0, 0);
|
||||
|
||||
pthread_create(&x_thread, NULL, xlib_threadf, &xlib_sem);
|
||||
pthread_detach(x_thread);
|
||||
|
||||
sem_wait(&xlib_sem);
|
||||
sem_destroy(&xlib_sem);
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
static void realloc_screen(void)
|
||||
{
|
||||
int size = scr_w * scr_h * 2;
|
||||
g_screen_width = g_menuscreen_w = scr_w;
|
||||
g_screen_height = g_menuscreen_h = scr_h;
|
||||
g_screen_ptr = realloc(g_screen_ptr, size);
|
||||
g_menubg_ptr = realloc(g_menubg_ptr, size);
|
||||
memset(g_screen_ptr, 0, size);
|
||||
memset(g_menubg_ptr, 0, size);
|
||||
PicoDraw2FB = g_menubg_ptr;
|
||||
scr_changed = 0;
|
||||
}
|
||||
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
unsigned int *image;
|
||||
int pixel_count, i;
|
||||
|
||||
if (ximage == NULL)
|
||||
return;
|
||||
|
||||
pixel_count = g_screen_width * g_screen_height;
|
||||
image = (void *)ximage->data;
|
||||
|
||||
if (current_bpp == 8)
|
||||
{
|
||||
unsigned char *pixels = g_screen_ptr;
|
||||
int pix;
|
||||
|
||||
for (i = 0; i < pixel_count; i++)
|
||||
{
|
||||
pix = current_pal[pixels[i]];
|
||||
image[i] = pix;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short *pixels = g_screen_ptr;
|
||||
|
||||
for (i = 0; i < pixel_count; i++)
|
||||
{
|
||||
/* in: rrrr rggg gggb bbbb */
|
||||
/* out: rrrr r000 gggg gg00 bbbb b000 */
|
||||
image[i] = (pixels[i] << 8) & 0xf80000;
|
||||
image[i] |= (pixels[i] << 5) & 0x00fc00;
|
||||
image[i] |= (pixels[i] << 3) & 0x0000f8;
|
||||
}
|
||||
}
|
||||
xlib_update();
|
||||
|
||||
if (scr_changed) {
|
||||
realloc_screen();
|
||||
ximage_realloc(xlib_display, DefaultVisual(xlib_display, 0));
|
||||
|
||||
// propagate new ponters to renderers
|
||||
plat_video_toggle_renderer(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void plat_video_wait_vsync(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // !FBDEV
|
||||
|
||||
void plat_early_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
#ifdef FBDEV
|
||||
int ret, w, h;
|
||||
ret = vout_fbdev_init(&w, &h);
|
||||
if (ret != 0)
|
||||
exit(1);
|
||||
g_screen_width = g_menuscreen_w = w;
|
||||
g_screen_height = g_menuscreen_h = h;
|
||||
g_menubg_ptr = realloc(g_menubg_ptr, w * g_screen_height * 2);
|
||||
PicoDraw2FB = g_menubg_ptr;
|
||||
#else
|
||||
realloc_screen();
|
||||
memset(g_screen_ptr, 0, g_screen_width * g_screen_height * 2);
|
||||
xlib_init();
|
||||
#endif
|
||||
|
||||
// snd
|
||||
sndout_oss_init();
|
||||
}
|
||||
|
||||
void plat_finish(void)
|
||||
{
|
||||
#ifdef FBDEV
|
||||
vout_fbdev_finish();
|
||||
#else
|
||||
free(g_screen_ptr);
|
||||
#endif
|
||||
sndout_oss_exit();
|
||||
}
|
||||
|
||||
/* misc */
|
||||
int mp3_get_bitrate(void *f, int size)
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
void mp3_start_play(void *f, int pos)
|
||||
{
|
||||
}
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
}
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
struct in_default_bind in_evdev_defbinds[] =
|
||||
{
|
||||
/* MXYZ SACB RLDU */
|
||||
{ KEY_UP, IN_BINDTYPE_PLAYER12, 0 },
|
||||
{ KEY_DOWN, IN_BINDTYPE_PLAYER12, 1 },
|
||||
{ KEY_LEFT, IN_BINDTYPE_PLAYER12, 2 },
|
||||
{ KEY_RIGHT, IN_BINDTYPE_PLAYER12, 3 },
|
||||
{ KEY_S, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ KEY_D, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ KEY_A, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ KEY_ENTER, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ KEY_BACKSLASH, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int addr_min, addr_max;
|
||||
int r8, r16, r32, w8, w16, w32;
|
||||
} io_log_location;
|
||||
|
||||
static io_log_location io_locations[] =
|
||||
{
|
||||
{ 0x400000, 0x9FFFFF, 0, }, // unused
|
||||
{ 0xa00000, 0xa03fff, 0, }, // z80 RAM
|
||||
{ 0xa04000, 0xa05fff, 0, }, // ym2612
|
||||
{ 0xa06000, 0xa060ff, 0, }, // bank reg
|
||||
{ 0xa06100, 0xa07eff, 0, }, // unused
|
||||
{ 0xa07f00, 0xa07fff, 0, }, // vdp
|
||||
{ 0xa08000, 0xa0ffff, 0, }, // 0xa00000-0xa07fff mirror
|
||||
{ 0xa10000, 0xa1001f, 0, }, // i/o
|
||||
{ 0xa10020, 0xa10fff, 0, }, // expansion
|
||||
{ 0xa11000, 0xa110ff, 0, }, // expansion
|
||||
{ 0xa11100, 0xa11101, 0, }, // z80 busreq
|
||||
{ 0xa11102, 0xa111ff, 0, }, // expansion
|
||||
{ 0xa11200, 0xa11201, 0, }, // z80 reset
|
||||
{ 0xa11202, 0xbfffff, 0, }, // expansion
|
||||
{ 0xc00000, 0xc00003, 0, }, // vdp data port
|
||||
{ 0xc00004, 0xc00007, 0, }, // vdp control
|
||||
{ 0xc00009, 0xc0000f, 0, }, // hv counter
|
||||
{ 0xc00010, 0xc00017, 0, }, // PSG
|
||||
{ 0xc00018, 0xc0001f, 0, }, // unused
|
||||
{ 0xc00020, 0xdfffff, 0, } // vdp mirrors
|
||||
};
|
||||
|
||||
|
||||
void log_io(unsigned int a, int bits, int is_write)
|
||||
{
|
||||
int i;
|
||||
a &= 0x00ffffff;
|
||||
if (bits > 8) a&=~1;
|
||||
|
||||
for (i = 0; i < sizeof(io_locations)/sizeof(io_locations[0]); i++)
|
||||
{
|
||||
if (a >= io_locations[i].addr_min && a <= io_locations[i].addr_max)
|
||||
{
|
||||
switch (bits|(is_write<<8)) {
|
||||
case 0x008: io_locations[i].r8 ++; break;
|
||||
case 0x010: io_locations[i].r16++; break;
|
||||
case 0x020: io_locations[i].r32++; break;
|
||||
case 0x108: io_locations[i].w8 ++; break;
|
||||
case 0x110: io_locations[i].w16++; break;
|
||||
case 0x120: io_locations[i].w32++; break;
|
||||
default: printf("%06x %i %i\n", a, bits, is_write); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_io_clear(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof(io_locations)/sizeof(io_locations[0]); i++)
|
||||
{
|
||||
io_log_location *iol = &io_locations[i];
|
||||
iol->r8 = iol->r16 = iol->r32 = iol->w8 = iol->w16 = iol->w32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void log_io_dump(void)
|
||||
{
|
||||
int i;
|
||||
printf(" range : r8 r16 r32 w8 w16 w32\n");
|
||||
for (i = 0; i < sizeof(io_locations)/sizeof(io_locations[0]); i++)
|
||||
{
|
||||
io_log_location *iol = &io_locations[i];
|
||||
if (iol->r8 == 0 && iol->r16 == 0 && iol->r32 == 0 && iol->w8 == 0 && iol->w16 == 0 && iol->w32 == 0)
|
||||
continue;
|
||||
printf("%06x - %06x : %8i %8i %8i %8i %8i %8i\n", iol->addr_min, iol->addr_max,
|
||||
iol->r8, iol->r16, iol->r32, iol->w8, iol->w16, iol->w32);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
void log_io_clear(void);
|
||||
void log_io_dump(void);
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define NO_SYNC
|
||||
|
||||
#define CASE_SENSITIVE_FS 1 // CS filesystem
|
||||
#define DONT_OPEN_MANY_FILES 0
|
||||
#define REDUCE_IO_CALLS 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 0
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define MSCREEN_SIZE_FIXED 0
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
|
||||
// pico.c
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
#define SIMPLE_WRITE_SOUND 0
|
||||
#define mix_32_to_16l_stereo_lvl mix_32_to_16l_stereo
|
||||
|
||||
#define EL_LOGMASK (EL_STATUS|EL_ANOMALY|EL_UIO)
|
||||
// EL_VDPDMA|EL_ASVDP|EL_SR | EL_IDLE | EL_BUSREQ|EL_Z80BNK | EL_32X)
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "/"
|
||||
#define PATH_SEP_C '/'
|
||||
#define MENU_X2 0
|
||||
|
||||
#endif //PORT_CONFIG_H
|
||||
|
126
linux/pprof.c
126
linux/pprof.c
|
@ -1,126 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
|
||||
struct pp_counters *pp_counters;
|
||||
static int shmemid;
|
||||
|
||||
void pprof_init(void)
|
||||
{
|
||||
int this_is_new_shmem = 1;
|
||||
key_t shmemkey;
|
||||
void *shmem;
|
||||
|
||||
#ifndef PPROF_TOOL
|
||||
unsigned int tmp = pprof_get_one();
|
||||
printf("pprof: measured diff is %u\n", pprof_get_one() - tmp);
|
||||
#endif
|
||||
|
||||
shmemkey = ftok(".", 0x02ABC32E);
|
||||
if (shmemkey == -1)
|
||||
{
|
||||
perror("pprof: ftok failed");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef PPROF_TOOL
|
||||
shmemid = shmget(shmemkey, sizeof(*pp_counters),
|
||||
IPC_CREAT | IPC_EXCL | 0644);
|
||||
if (shmemid == -1)
|
||||
#endif
|
||||
{
|
||||
shmemid = shmget(shmemkey, sizeof(*pp_counters),
|
||||
0644);
|
||||
if (shmemid == -1)
|
||||
{
|
||||
perror("pprof: shmget failed");
|
||||
return;
|
||||
}
|
||||
this_is_new_shmem = 0;
|
||||
}
|
||||
|
||||
shmem = shmat(shmemid, NULL, 0);
|
||||
if (shmem == (void *)-1)
|
||||
{
|
||||
perror("pprof: shmat failed");
|
||||
return;
|
||||
}
|
||||
|
||||
pp_counters = shmem;
|
||||
if (this_is_new_shmem) {
|
||||
memset(pp_counters, 0, sizeof(*pp_counters));
|
||||
printf("pprof: pp_counters cleared.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void pprof_finish(void)
|
||||
{
|
||||
shmdt(pp_counters);
|
||||
shmctl(shmemid, IPC_RMID, NULL);
|
||||
}
|
||||
|
||||
#ifdef PPROF_TOOL
|
||||
|
||||
#define IT(n) { pp_##n, #n }
|
||||
static const struct {
|
||||
enum pprof_points pp;
|
||||
const char *name;
|
||||
} pp_tab[] = {
|
||||
IT(main),
|
||||
IT(frame),
|
||||
IT(draw),
|
||||
IT(sound),
|
||||
IT(m68k),
|
||||
IT(z80),
|
||||
IT(msh2),
|
||||
IT(ssh2),
|
||||
IT(dummy),
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long long old[pp_total_points], new[pp_total_points];
|
||||
int base = 0;
|
||||
int l, i;
|
||||
|
||||
pprof_init();
|
||||
if (pp_counters == NULL)
|
||||
return 1;
|
||||
|
||||
if (argc >= 2)
|
||||
base = atoi(argv[1]);
|
||||
|
||||
memset(old, 0, sizeof(old));
|
||||
for (l = 0; ; l++)
|
||||
{
|
||||
if ((l & 0x1f) == 0) {
|
||||
for (i = 0; i < ARRAY_SIZE(pp_tab); i++)
|
||||
printf("%6s ", pp_tab[i].name);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
memcpy(new, pp_counters->counter, sizeof(new));
|
||||
for (i = 0; i < ARRAY_SIZE(pp_tab); i++)
|
||||
{
|
||||
unsigned long long idiff = new[i] - old[i];
|
||||
unsigned long long bdiff = (new[base] - old[base]) | 1;
|
||||
printf("%6.2f ", (double)idiff * 100.0 / bdiff);
|
||||
}
|
||||
printf("\n");
|
||||
memcpy(old, new, sizeof(old));
|
||||
|
||||
if (argc < 3)
|
||||
break;
|
||||
usleep(atoi(argv[2]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // PPROF_TOOL
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#ifndef __PPROF_H__
|
||||
#define __PPROF_H__
|
||||
|
||||
enum pprof_points {
|
||||
pp_main,
|
||||
pp_frame,
|
||||
pp_draw,
|
||||
pp_sound,
|
||||
pp_m68k,
|
||||
pp_z80,
|
||||
pp_msh2,
|
||||
pp_ssh2,
|
||||
pp_dummy,
|
||||
pp_total_points
|
||||
};
|
||||
|
||||
struct pp_counters
|
||||
{
|
||||
unsigned long long counter[pp_total_points];
|
||||
};
|
||||
|
||||
extern struct pp_counters *pp_counters;
|
||||
|
||||
#ifdef __i386__
|
||||
static __attribute__((always_inline)) inline unsigned int pprof_get_one(void)
|
||||
{
|
||||
unsigned long long ret;
|
||||
__asm__ __volatile__ ("rdtsc" : "=A" (ret));
|
||||
return (unsigned int)ret;
|
||||
}
|
||||
#define unglitch_timer(x)
|
||||
|
||||
#elif defined(__GP2X__)
|
||||
// XXX: MMSP2 only, timer sometimes seems to return lower vals?
|
||||
extern volatile unsigned long *gp2x_memregl;
|
||||
#define pprof_get_one() (unsigned int)gp2x_memregl[0x0a00 >> 2]
|
||||
#define unglitch_timer(di) \
|
||||
if ((signed int)(di) < 0) di = 0
|
||||
|
||||
#else
|
||||
#error no timer
|
||||
#endif
|
||||
|
||||
#define pprof_start(point) { \
|
||||
unsigned int pp_start_##point = pprof_get_one()
|
||||
|
||||
#define pprof_end(point) \
|
||||
{ \
|
||||
unsigned int di = pprof_get_one() - pp_start_##point; \
|
||||
unglitch_timer(di); \
|
||||
pp_counters->counter[pp_##point] += di; \
|
||||
} \
|
||||
}
|
||||
|
||||
// subtract for recursive stuff
|
||||
#define pprof_end_sub(point) \
|
||||
{ \
|
||||
unsigned int di = pprof_get_one() - pp_start_##point; \
|
||||
unglitch_timer(di); \
|
||||
pp_counters->counter[pp_##point] -= di; \
|
||||
} \
|
||||
}
|
||||
|
||||
extern void pprof_init(void);
|
||||
extern void pprof_finish(void);
|
||||
|
||||
#endif // __PPROF_H__
|
|
@ -1,2 +0,0 @@
|
|||
#include "../gp2x/version.h"
|
||||
|
107
pandora/Makefile
107
pandora/Makefile
|
@ -1,107 +0,0 @@
|
|||
#export CROSS = arm-none-linux-gnueabi-
|
||||
CROSS ?= $(CROSS_COMPILE)
|
||||
LIBROOT = /home/notaz/dev/pnd/libroot
|
||||
PND_MAKE ?= $(HOME)/dev/pnd/src/pandora-libraries/testdata/scripts/pnd_make.sh
|
||||
|
||||
# settings
|
||||
use_cyclone = 1
|
||||
#use_musashi = 1
|
||||
use_drz80 = 1
|
||||
use_sh2drc = 1
|
||||
#use_sh2mame = 1
|
||||
|
||||
asm_memory = 1
|
||||
asm_render = 1
|
||||
asm_ym2612 = 1
|
||||
asm_misc = 1
|
||||
asm_cdpico = 1
|
||||
asm_cdmemory = 1
|
||||
#profile = 1
|
||||
#drc_debug = 3
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ifeq "$(use_musashi)" "1"
|
||||
# due to CPU stop flag acces
|
||||
asm_cdpico = 0
|
||||
asm_cdmemory = 0
|
||||
endif
|
||||
|
||||
ARCH = arm
|
||||
DEFINES += ARM PANDORA IN_EVDEV
|
||||
CFLAGS += -I../.. -I. -I$(LIBROOT)/include
|
||||
CFLAGS += -Wall -Winline -mcpu=cortex-a8 -mtune=cortex-a8 -march=armv7-a
|
||||
ifeq ($(DEBUG),)
|
||||
CFLAGS += -O2 -fomit-frame-pointer -fstrict-aliasing -ffast-math
|
||||
endif
|
||||
LDFLAGS += -L$(LIBROOT)/lib -Wl,-Bstatic -lpng -Wl,-Bdynamic -lm -lpthread -ldl
|
||||
ASFLAGS = -mcpu=cortex-a8
|
||||
CC = $(CROSS)gcc
|
||||
STRIP = $(CROSS)strip
|
||||
AS = $(CROSS)as
|
||||
LD = $(CROSS)ld
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
# frontend
|
||||
OBJS += plat.o asm_utils.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/emu.o platform/common/menu_pico.o platform/common/fonts.o platform/common/config.o \
|
||||
platform/common/arm_utils.o platform/common/mp3_helix.o platform/common/arm_linux.o \
|
||||
platform/common/readpng.o platform/common/input.o platform/common/main.o platform/common/mp3.o \
|
||||
platform/linux/fbdev.o platform/linux/in_evdev.o platform/linux/sndout_oss.o \
|
||||
platform/linux/plat.o platform/linux/xenv.o
|
||||
|
||||
# ARM stuff
|
||||
OBJS += pico/carthw/svp/compiler.o pico/carthw/svp/stub_arm.o
|
||||
OBJS += pico/sound/mix_arm.o
|
||||
|
||||
# zlib
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
|
||||
vpath %.c = ../..
|
||||
vpath %.s = ../..
|
||||
vpath %.S = ../..
|
||||
DIRS += platform/linux zlib unzip
|
||||
|
||||
all: mkdirs PicoDrive picorestore
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/common_arm.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||
|
||||
PicoDrive : $(OBJS) ../common/helix/$(CROSS)helix-mp3.a
|
||||
@echo ">>>" $@
|
||||
$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS) -Wl,-Map=PicoDrive.map
|
||||
ifeq ($(DEBUG),)
|
||||
$(STRIP) $@
|
||||
endif
|
||||
|
||||
clean: tidy
|
||||
$(RM) PicoDrive
|
||||
tidy:
|
||||
$(RM) $(OBJS)
|
||||
|
||||
readme.txt: ../../tools/textfilter ../base_readme.txt
|
||||
../../tools/textfilter ../base_readme.txt $@ PANDORA
|
||||
|
||||
PicoDrive.pxml: PicoDrive.pxml.template
|
||||
./make_pxml.sh PicoDrive.pxml.template PicoDrive.pxml
|
||||
|
||||
platform/common/menu_pico.o: platform/common/menu.c menu.c
|
||||
|
||||
# ----------- release -----------
|
||||
|
||||
VER ?= $(shell head -n 1 version.h | sed 's/.*"\(.*\)\.\(.*\)".*/\1\2/g')
|
||||
|
||||
rel: PicoDrive PicoDrive.run picorestore ../../pico/carthw.cfg readme.txt \
|
||||
skin PicoDrive.png PicoDrive_p.png PicoDrive.pxml
|
||||
rm -rf out
|
||||
mkdir out
|
||||
cp -r $^ out/
|
||||
$(PND_MAKE) -p PicoDrive_$(VER).pnd -d out -x PicoDrive.pxml -i PicoDrive.png -c
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
void clut_line2x2(void *dest, const void *src, const unsigned short *pal, int pixels_mask);
|
||||
void clut_line3x2(void *dest, const void *src, const unsigned short *pal, int pixels_mask);
|
|
@ -1,108 +0,0 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
|
||||
@ FIXME: handle dual issue
|
||||
.global clut_line2x2 @ void *dest, void *src, unsigned short *pal, int pixels_mask
|
||||
|
||||
clut_line2x2:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
|
||||
and lr, r3, #0xff0000
|
||||
mov lr, lr, lsr #15 @ mask
|
||||
mov r3, r3, lsr #3
|
||||
and r3, r3, #0xff @ counter
|
||||
add r11,r0, #800*2
|
||||
|
||||
clut_line_2x2_loop:
|
||||
ldmia r1!, {r10,r12}
|
||||
|
||||
and r4, lr, r10, lsl #1
|
||||
ldrh r4, [r2, r4]
|
||||
and r5, lr, r10, lsr #7
|
||||
ldrh r5, [r2, r5]
|
||||
orr r4, r4, r4, lsl #16
|
||||
|
||||
and r6, lr, r10, lsr #15
|
||||
ldrh r6, [r2, r6]
|
||||
orr r5, r5, r5, lsl #16
|
||||
|
||||
and r7, lr, r10, lsr #23
|
||||
ldrh r7, [r2, r7]
|
||||
orr r6, r6, r6, lsl #16
|
||||
|
||||
and r8, lr, r12, lsl #1
|
||||
ldrh r8, [r2, r8]
|
||||
orr r7, r7, r7, lsl #16
|
||||
|
||||
and r9, lr, r12, lsr #7
|
||||
ldrh r9, [r2, r9]
|
||||
orr r8, r8, r8, lsl #16
|
||||
|
||||
and r10,lr, r12, lsr #15
|
||||
ldrh r10,[r2, r10]
|
||||
orr r9, r9, r9, lsl #16
|
||||
|
||||
and r12,lr, r12, lsr #23
|
||||
ldrh r12,[r2, r12]
|
||||
orr r10,r10,r10, lsl #16
|
||||
|
||||
subs r3, r3, #1
|
||||
orr r12,r12,r12, lsl #16
|
||||
|
||||
stmia r0!, {r4-r10,r12}
|
||||
stmia r11!,{r4-r10,r12}
|
||||
bne clut_line_2x2_loop
|
||||
|
||||
ldmfd sp!, {r4-r11,pc}
|
||||
|
||||
|
||||
@ 00 01 11 22 23 33
|
||||
@ r4 r5 r6 r7 r8 r9
|
||||
|
||||
.macro do_4_to_12 rs
|
||||
and r4, lr, \rs, lsl #1
|
||||
and r6, lr, \rs, lsr #7
|
||||
and r7, lr, \rs, lsr #15
|
||||
and r9, lr, \rs, lsr #23
|
||||
ldrh r4, [r2, r4]
|
||||
ldrh r6, [r2, r6]
|
||||
ldrh r7, [r2, r7]
|
||||
ldrh r9, [r2, r9]
|
||||
|
||||
orr r5, r4, r6, lsl #16
|
||||
orr r4, r4, r4, lsl #16
|
||||
orr r6, r6, r6, lsl #16
|
||||
|
||||
orr r8, r7, r9, lsl #16
|
||||
orr r7, r7, r7, lsl #16
|
||||
orr r9, r9, r9, lsl #16
|
||||
.endm
|
||||
|
||||
|
||||
.global clut_line3x2 @ void *dest, void *src, unsigned short *pal, int pixels_mask
|
||||
|
||||
clut_line3x2:
|
||||
stmfd sp!, {r4-r11,lr}
|
||||
|
||||
and lr, r3, #0xff0000
|
||||
mov lr, lr, lsr #15 @ mask
|
||||
mov r3, r3, lsr #3
|
||||
and r3, r3, #0xff @ counter
|
||||
add r11,r0, #800*2
|
||||
|
||||
clut_line3x2_loop:
|
||||
ldmia r1!, {r10,r12}
|
||||
|
||||
do_4_to_12 r10
|
||||
stmia r0!, {r4-r9}
|
||||
stmia r11!,{r4-r9}
|
||||
|
||||
do_4_to_12 r12
|
||||
subs r3, r3, #1
|
||||
stmia r0!, {r4-r9}
|
||||
stmia r11!,{r4-r9}
|
||||
|
||||
bne clut_line3x2_loop
|
||||
|
||||
ldmfd sp!, {r4-r11,pc}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
sed -i
|
||||
|
||||
major=`head -n 1 version.h | sed 's/.*"\([0-9]*\)\.\([0-9]*\).*/\1/g'`
|
||||
minor=`head -n 1 version.h | sed 's/.*"\([0-9]*\)\.\([0-9]*\).*/\2/g'`
|
||||
revision=`head -n 1 revision.h | sed 's/.*"\([0-9]*\)".*/\1/g'`
|
||||
|
||||
sed 's/@major@/'$major'/' "$1" > "$2"
|
||||
sed -i 's/@minor@/'$minor'/' "$2"
|
||||
sed -i 's/@revision@/'$revision'/' "$2"
|
148
pandora/menu.c
148
pandora/menu.c
|
@ -1,148 +0,0 @@
|
|||
#include "plat.h"
|
||||
|
||||
static const char *men_scaler[] = { "1x1, 1x1", "2x2, 3x2", "2x2, 2x2", "fullscreen", "custom", NULL };
|
||||
static const char h_scaler[] = "Scalers for 40 and 32 column modes\n"
|
||||
"(320 and 256 pixel wide horizontal)";
|
||||
static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
|
||||
"using d-pad or move it using R+d-pad";
|
||||
static const char *men_dummy[] = { NULL };
|
||||
char **pnd_filter_list;
|
||||
|
||||
static int menu_loop_cscaler(int id, int keys)
|
||||
{
|
||||
unsigned int inp;
|
||||
|
||||
currentConfig.scaling = SCALE_CUSTOM;
|
||||
|
||||
pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
|
||||
pnd_restore_layer_data();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
menu_draw_begin(0);
|
||||
memset(g_menuscreen_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2);
|
||||
text_out16(2, 480 - 18, "%dx%d | d-pad to resize, R+d-pad to move", g_layer_cw, g_layer_ch);
|
||||
menu_draw_end();
|
||||
|
||||
inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
|
||||
if (inp & PBTN_UP) g_layer_cy--;
|
||||
if (inp & PBTN_DOWN) g_layer_cy++;
|
||||
if (inp & PBTN_LEFT) g_layer_cx--;
|
||||
if (inp & PBTN_RIGHT) g_layer_cx++;
|
||||
if (!(inp & PBTN_R)) {
|
||||
if (inp & PBTN_UP) g_layer_ch += 2;
|
||||
if (inp & PBTN_DOWN) g_layer_ch -= 2;
|
||||
if (inp & PBTN_LEFT) g_layer_cw += 2;
|
||||
if (inp & PBTN_RIGHT) g_layer_cw -= 2;
|
||||
}
|
||||
if (inp & (PBTN_MOK|PBTN_MBACK))
|
||||
break;
|
||||
|
||||
if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
|
||||
if (g_layer_cx < 0) g_layer_cx = 0;
|
||||
if (g_layer_cx > 640) g_layer_cx = 640;
|
||||
if (g_layer_cy < 0) g_layer_cy = 0;
|
||||
if (g_layer_cy > 420) g_layer_cy = 420;
|
||||
if (g_layer_cw < 160) g_layer_cw = 160;
|
||||
if (g_layer_ch < 60) g_layer_ch = 60;
|
||||
if (g_layer_cx + g_layer_cw > 800)
|
||||
g_layer_cw = 800 - g_layer_cx;
|
||||
if (g_layer_cy + g_layer_ch > 480)
|
||||
g_layer_ch = 480 - g_layer_cy;
|
||||
pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
|
||||
}
|
||||
}
|
||||
|
||||
pnd_setup_layer(0, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MENU_OPTIONS_GFX \
|
||||
mee_enum_h ("Scaler", MA_OPT_SCALING, currentConfig.scaling, \
|
||||
men_scaler, h_scaler), \
|
||||
mee_enum ("Filter", MA_OPT3_FILTERING, currentConfig.filter, men_dummy), \
|
||||
mee_onoff ("Vsync", MA_OPT2_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC), \
|
||||
mee_cust_h ("Setup custom scaler", MA_NONE, menu_loop_cscaler, NULL, h_cscaler), \
|
||||
mee_range_hide("layer_x", MA_OPT3_LAYER_X, g_layer_cx, 0, 640), \
|
||||
mee_range_hide("layer_y", MA_OPT3_LAYER_Y, g_layer_cy, 0, 420), \
|
||||
mee_range_hide("layer_w", MA_OPT3_LAYER_W, g_layer_cw, 160, 800), \
|
||||
mee_range_hide("layer_h", MA_OPT3_LAYER_H, g_layer_ch, 60, 480), \
|
||||
|
||||
#define MENU_OPTIONS_ADV \
|
||||
mee_onoff ("SVP dynarec", MA_OPT2_SVP_DYNAREC, PicoOpt, POPT_EN_SVP_DRC), \
|
||||
mee_onoff ("Status line in main menu", MA_OPT2_STATUS_LINE, currentConfig.EmuOpt, EOPT_SHOW_RTC),
|
||||
|
||||
#define menu_main_plat_draw NULL
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
static menu_entry e_menu_gfx_options[];
|
||||
static menu_entry e_menu_options[];
|
||||
static menu_entry e_menu_keyconfig[];
|
||||
|
||||
void pnd_menu_init(void)
|
||||
{
|
||||
struct dirent *ent;
|
||||
int i, count = 0;
|
||||
char **mfilters;
|
||||
char buff[64], *p;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir("/etc/pandora/conf/dss_fir");
|
||||
if (dir == NULL) {
|
||||
perror("filter opendir");
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
errno = 0;
|
||||
ent = readdir(dir);
|
||||
if (ent == NULL) {
|
||||
if (errno != 0)
|
||||
perror("readdir");
|
||||
break;
|
||||
}
|
||||
p = strstr(ent->d_name, "_up");
|
||||
if (p != NULL && (p[3] == 0 || !strcmp(p + 3, "_h")))
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
mfilters = calloc(count + 1, sizeof(mfilters[0]));
|
||||
if (mfilters == NULL)
|
||||
return;
|
||||
|
||||
rewinddir(dir);
|
||||
for (i = 0; (ent = readdir(dir)); ) {
|
||||
size_t len;
|
||||
|
||||
p = strstr(ent->d_name, "_up");
|
||||
if (p == NULL || (p[3] != 0 && strcmp(p + 3, "_h")))
|
||||
continue;
|
||||
|
||||
len = p - ent->d_name;
|
||||
if (len > sizeof(buff) - 1)
|
||||
continue;
|
||||
|
||||
strncpy(buff, ent->d_name, len);
|
||||
buff[len] = 0;
|
||||
mfilters[i] = strdup(buff);
|
||||
if (mfilters[i] != NULL)
|
||||
i++;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
i = me_id2offset(e_menu_gfx_options, MA_OPT3_FILTERING);
|
||||
e_menu_gfx_options[i].data = (void *)mfilters;
|
||||
pnd_filter_list = mfilters;
|
||||
|
||||
i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
|
||||
e_menu_options[i].name = "Max CPU clock";
|
||||
|
||||
me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
|
||||
}
|
||||
|
639
pandora/plat.c
639
pandora/plat.c
|
@ -1,639 +0,0 @@
|
|||
// (c) Copyright 2006-2009 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#include "../common/emu.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/arm_utils.h"
|
||||
#include "../common/input.h"
|
||||
#include "../linux/sndout_oss.h"
|
||||
#include "../linux/fbdev.h"
|
||||
#include "../linux/xenv.h"
|
||||
#include "plat.h"
|
||||
#include "asm_utils.h"
|
||||
#include "version.h"
|
||||
|
||||
#include <pico/pico_int.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
static struct vout_fbdev *main_fb, *layer_fb;
|
||||
// g_layer_* - in use, g_layer_c* - configured custom
|
||||
int g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch;
|
||||
static int g_layer_x, g_layer_y;
|
||||
static int g_layer_w = 320, g_layer_h = 240;
|
||||
static int g_osd_fps_x, g_osd_y, doing_bg_frame;
|
||||
|
||||
static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
|
||||
static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
|
||||
static unsigned char __attribute__((aligned(4))) fb_copy[g_screen_width * g_screen_height * 2];
|
||||
static void *temp_frame;
|
||||
unsigned char *PicoDraw2FB;
|
||||
const char *renderer_names[] = { NULL };
|
||||
const char *renderer_names32x[] = { NULL };
|
||||
|
||||
static const char * const pandora_gpio_keys[KEY_MAX + 1] = {
|
||||
[0 ... KEY_MAX] = NULL,
|
||||
[KEY_UP] = "Up",
|
||||
[KEY_LEFT] = "Left",
|
||||
[KEY_RIGHT] = "Right",
|
||||
[KEY_DOWN] = "Down",
|
||||
[KEY_HOME] = "A",
|
||||
[KEY_PAGEDOWN] = "X",
|
||||
[KEY_END] = "B",
|
||||
[KEY_PAGEUP] = "Y",
|
||||
[KEY_RIGHTSHIFT]= "L",
|
||||
[KEY_RIGHTCTRL] = "R",
|
||||
[KEY_LEFTALT] = "Start",
|
||||
[KEY_LEFTCTRL] = "Select",
|
||||
[KEY_MENU] = "Pandora",
|
||||
};
|
||||
|
||||
struct in_default_bind in_evdev_defbinds[] =
|
||||
{
|
||||
/* MXYZ SACB RLDU */
|
||||
{ KEY_UP, IN_BINDTYPE_PLAYER12, 0 },
|
||||
{ KEY_DOWN, IN_BINDTYPE_PLAYER12, 1 },
|
||||
{ KEY_LEFT, IN_BINDTYPE_PLAYER12, 2 },
|
||||
{ KEY_RIGHT, IN_BINDTYPE_PLAYER12, 3 },
|
||||
{ KEY_S, IN_BINDTYPE_PLAYER12, 4 }, /* B */
|
||||
{ KEY_D, IN_BINDTYPE_PLAYER12, 5 }, /* C */
|
||||
{ KEY_A, IN_BINDTYPE_PLAYER12, 6 }, /* A */
|
||||
{ KEY_ENTER, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ KEY_BACKSLASH, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
{ KEY_SPACE, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
/* Pandora */
|
||||
{ KEY_PAGEDOWN, IN_BINDTYPE_PLAYER12, 4 },
|
||||
{ KEY_END, IN_BINDTYPE_PLAYER12, 5 },
|
||||
{ KEY_HOME, IN_BINDTYPE_PLAYER12, 6 },
|
||||
{ KEY_LEFTALT, IN_BINDTYPE_PLAYER12, 7 },
|
||||
{ KEY_RIGHTSHIFT,IN_BINDTYPE_EMU, PEVB_STATE_SAVE },
|
||||
{ KEY_RIGHTCTRL, IN_BINDTYPE_EMU, PEVB_STATE_LOAD },
|
||||
{ KEY_LEFTCTRL, IN_BINDTYPE_EMU, PEVB_MENU },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
static int get_cpu_clock(void)
|
||||
{
|
||||
FILE *f;
|
||||
int ret = 0;
|
||||
f = fopen("/proc/pandora/cpu_mhz_max", "r");
|
||||
if (f) {
|
||||
fscanf(f, "%d", &ret);
|
||||
fclose(f);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pemu_prep_defconfig(void)
|
||||
{
|
||||
defaultConfig.EmuOpt |= EOPT_VSYNC|EOPT_16BPP;
|
||||
defaultConfig.s_PicoOpt |= POPT_EN_MCD_GFX|POPT_EN_MCD_PSYNC;
|
||||
defaultConfig.scaling = SCALE_2x2_3x2;
|
||||
}
|
||||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
currentConfig.CPUclock = get_cpu_clock();
|
||||
}
|
||||
|
||||
static void osd_text(int x, int y, const char *text)
|
||||
{
|
||||
int len = strlen(text)*8;
|
||||
int i, h;
|
||||
|
||||
len++;
|
||||
for (h = 0; h < 8; h++) {
|
||||
unsigned short *p;
|
||||
p = (unsigned short *)g_screen_ptr + x + g_screen_width*(y + h);
|
||||
for (i = len; i; i--, p++)
|
||||
*p = (*p>>2) & 0x39e7;
|
||||
}
|
||||
emu_text_out16(x, y, text);
|
||||
}
|
||||
|
||||
static void draw_cd_leds(void)
|
||||
{
|
||||
int old_reg;
|
||||
old_reg = Pico_mcd->s68k_regs[0];
|
||||
|
||||
if (0) {
|
||||
// 8-bit modes
|
||||
unsigned int col_g = (old_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
|
||||
unsigned int col_r = (old_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*2+ 4) =
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*3+ 4) =
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*4+ 4) = col_g;
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*2+12) =
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*3+12) =
|
||||
*(unsigned int *)((char *)g_screen_ptr + g_screen_width*4+12) = col_r;
|
||||
} else {
|
||||
// 16-bit modes
|
||||
unsigned int *p = (unsigned int *)((short *)g_screen_ptr + g_screen_width*2+4);
|
||||
unsigned int col_g = (old_reg & 2) ? 0x06000600 : 0;
|
||||
unsigned int col_r = (old_reg & 1) ? 0xc000c000 : 0;
|
||||
*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += g_screen_width/2 - 12/2;
|
||||
*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += g_screen_width/2 - 12/2;
|
||||
*p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r;
|
||||
}
|
||||
}
|
||||
|
||||
static int emuscan(unsigned int num)
|
||||
{
|
||||
DrawLineDest = (unsigned short *)g_screen_ptr + num * g_screen_width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pemu_finalize_frame(const char *fps, const char *notice)
|
||||
{
|
||||
if (notice && notice[0])
|
||||
osd_text(2, g_osd_y, notice);
|
||||
if (fps && fps[0] && (currentConfig.EmuOpt & EOPT_SHOW_FPS))
|
||||
osd_text(g_osd_fps_x, g_osd_y, fps);
|
||||
if ((PicoAHW & PAHW_MCD) && (currentConfig.EmuOpt & EOPT_EN_CD_LEDS))
|
||||
draw_cd_leds();
|
||||
}
|
||||
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
g_screen_ptr = vout_fbdev_flip(layer_fb);
|
||||
|
||||
// XXX: drain OS event queue here, maybe we'll actually use it someday..
|
||||
int dummy;
|
||||
xenv_update(&dummy);
|
||||
}
|
||||
|
||||
void plat_video_toggle_renderer(int change, int is_menu)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_enter(int is_rom_loaded)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_begin(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_end(void)
|
||||
{
|
||||
g_menuscreen_ptr = vout_fbdev_flip(main_fb);
|
||||
}
|
||||
|
||||
void plat_video_wait_vsync(void)
|
||||
{
|
||||
vout_fbdev_wait_vsync(main_fb);
|
||||
}
|
||||
|
||||
void plat_status_msg_clear(void)
|
||||
{
|
||||
vout_fbdev_clear_lines(layer_fb, g_osd_y, 8);
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_next(const char *msg)
|
||||
{
|
||||
plat_status_msg_clear();
|
||||
pemu_finalize_frame("", msg);
|
||||
plat_video_flip();
|
||||
emu_status_msg("");
|
||||
reset_timing = 1;
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_first(const char *msg)
|
||||
{
|
||||
plat_status_msg_busy_next(msg);
|
||||
}
|
||||
|
||||
void plat_update_volume(int has_changed, int is_up)
|
||||
{
|
||||
static int prev_frame = 0, wait_frames = 0;
|
||||
int vol = currentConfig.volume;
|
||||
|
||||
if (has_changed)
|
||||
{
|
||||
if (is_up) {
|
||||
if (vol < 99) vol++;
|
||||
} else {
|
||||
if (vol > 0) vol--;
|
||||
}
|
||||
wait_frames = 0;
|
||||
sndout_oss_setvol(vol, vol);
|
||||
currentConfig.volume = vol;
|
||||
emu_status_msg("VOL: %02i", vol);
|
||||
prev_frame = Pico.m.frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
static void make_bg(int no_scale)
|
||||
{
|
||||
unsigned short *s = (void *)fb_copy;
|
||||
int x, y;
|
||||
|
||||
memset32(g_menubg_src_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2 / 4);
|
||||
|
||||
if (!no_scale && g_menuscreen_w >= 640 && g_menuscreen_h >= 480) {
|
||||
unsigned int t, *d = g_menubg_src_ptr;
|
||||
d += (g_menuscreen_h / 2 - 480 / 2) * g_menuscreen_w / 2;
|
||||
d += (g_menuscreen_w / 2 - 640 / 2) / 2;
|
||||
for (y = 0; y < 240; y++, s += 320, d += g_menuscreen_w*2/2) {
|
||||
for (x = 0; x < 320; x++) {
|
||||
t = s[x];
|
||||
t |= t << 16;
|
||||
d[x] = d[x + g_menuscreen_w / 2] = t;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_menuscreen_w >= 320 && g_menuscreen_h >= 240) {
|
||||
unsigned short *d = g_menubg_src_ptr;
|
||||
d += (g_menuscreen_h / 2 - 240 / 2) * g_menuscreen_w;
|
||||
d += (g_menuscreen_w / 2 - 320 / 2);
|
||||
for (y = 0; y < 240; y++, s += 320, d += g_menuscreen_w)
|
||||
memcpy(d, s, 320*2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
doing_bg_frame = 1;
|
||||
emu_cmn_forced_frame(no_scale, do_emu);
|
||||
doing_bg_frame = 0;
|
||||
|
||||
// making a copy because enabling the layer clears it's mem
|
||||
memcpy32((void *)fb_copy, g_screen_ptr, sizeof(fb_copy) / 4);
|
||||
make_bg(no_scale);
|
||||
}
|
||||
|
||||
static void oss_write_nonblocking(int len)
|
||||
{
|
||||
// sndout_oss_can_write() is not reliable, only use with no_frmlimit
|
||||
if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && !sndout_oss_can_write(len))
|
||||
return;
|
||||
|
||||
sndout_oss_write_nb(PsndOut, len);
|
||||
}
|
||||
|
||||
void pemu_sound_start(void)
|
||||
{
|
||||
PsndOut = NULL;
|
||||
|
||||
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||
{
|
||||
int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;
|
||||
|
||||
PsndRerate(Pico.m.frame_count ? 1 : 0);
|
||||
|
||||
/*
|
||||
* for 44k stereo, we do 1470 samples/emu_frame
|
||||
* OMAP driver does power of 2 buffers, so we need at least 4K buffer.
|
||||
* The most we can lag is 1K samples, size of OMAP's McBSP FIFO,
|
||||
* with 2K sample buffer we might sometimes lag more than that,
|
||||
* thus causing underflows.
|
||||
*/
|
||||
printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
|
||||
PsndRate, PsndLen, is_stereo, Pico.m.pal);
|
||||
sndout_oss_start(PsndRate, is_stereo, 2);
|
||||
//sndout_oss_setvol(currentConfig.volume, currentConfig.volume);
|
||||
PicoWriteSound = oss_write_nonblocking;
|
||||
plat_update_volume(0, 0);
|
||||
memset(sndBuffer, 0, sizeof(sndBuffer));
|
||||
PsndOut = sndBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_sound_stop(void)
|
||||
{
|
||||
sndout_oss_stop();
|
||||
}
|
||||
|
||||
void pemu_sound_wait(void)
|
||||
{
|
||||
// don't need to do anything, writes will block by themselves
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str)
|
||||
{
|
||||
}
|
||||
|
||||
static int pnd_setup_layer_(int fd, int enabled, int x, int y, int w, int h)
|
||||
{
|
||||
struct omapfb_plane_info pi;
|
||||
struct omapfb_mem_info mi;
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
|
||||
if (ret != 0) {
|
||||
perror("QUERY_PLANE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
|
||||
if (ret != 0) {
|
||||
perror("QUERY_MEM");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* must disable when changing stuff */
|
||||
if (pi.enabled) {
|
||||
pi.enabled = 0;
|
||||
ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
|
||||
if (ret != 0)
|
||||
perror("SETUP_PLANE");
|
||||
}
|
||||
|
||||
mi.size = 320*240*2*4;
|
||||
ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
|
||||
if (ret != 0) {
|
||||
perror("SETUP_MEM");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pi.pos_x = x;
|
||||
pi.pos_y = y;
|
||||
pi.out_width = w;
|
||||
pi.out_height = h;
|
||||
pi.enabled = enabled;
|
||||
|
||||
ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
|
||||
if (ret != 0) {
|
||||
perror("SETUP_PLANE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pnd_setup_layer(int enabled, int x, int y, int w, int h)
|
||||
{
|
||||
return pnd_setup_layer_(vout_fbdev_get_fd(layer_fb), enabled, x, y, w, h);
|
||||
}
|
||||
|
||||
void pnd_restore_layer_data(void)
|
||||
{
|
||||
short *t = (short *)fb_copy + 320*240 / 2 + 160;
|
||||
|
||||
// right now this is used by menu, which wants to preview something
|
||||
// so try to get something on the layer.
|
||||
if ((t[0] | t[5] | t[13]) == 0)
|
||||
memset32((void *)fb_copy, 0x07000700, sizeof(fb_copy) / 4);
|
||||
|
||||
memcpy32(g_screen_ptr, (void *)fb_copy, 320*240*2 / 4);
|
||||
plat_video_flip();
|
||||
}
|
||||
|
||||
static void apply_filter(int which)
|
||||
{
|
||||
char buf[128];
|
||||
int i;
|
||||
|
||||
if (pnd_filter_list == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < which; i++)
|
||||
if (pnd_filter_list[i] == NULL)
|
||||
return;
|
||||
|
||||
if (pnd_filter_list[i] == NULL)
|
||||
return;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
|
||||
system(buf);
|
||||
}
|
||||
|
||||
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||
{
|
||||
int fb_w = 320, fb_h = 240, fb_left = 0, fb_right = 0, fb_top = 0, fb_bottom = 0;
|
||||
|
||||
if (doing_bg_frame)
|
||||
return;
|
||||
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
PicoDrawSetCallbacks(emuscan, NULL);
|
||||
|
||||
if (is_32cols) {
|
||||
fb_w = 256;
|
||||
fb_left = fb_right = 32;
|
||||
}
|
||||
|
||||
switch (currentConfig.scaling) {
|
||||
case SCALE_1x1:
|
||||
g_layer_w = fb_w;
|
||||
g_layer_h = fb_h;
|
||||
break;
|
||||
case SCALE_2x2_3x2:
|
||||
g_layer_w = fb_w * (is_32cols ? 3 : 2);
|
||||
g_layer_h = fb_h * 2;
|
||||
break;
|
||||
case SCALE_2x2_2x2:
|
||||
g_layer_w = fb_w * 2;
|
||||
g_layer_h = fb_h * 2;
|
||||
break;
|
||||
case SCALE_FULLSCREEN:
|
||||
g_layer_w = 800;
|
||||
g_layer_h = 480;
|
||||
break;
|
||||
case SCALE_CUSTOM:
|
||||
g_layer_x = g_layer_cx;
|
||||
g_layer_y = g_layer_cy;
|
||||
g_layer_w = g_layer_cw;
|
||||
g_layer_h = g_layer_ch;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentConfig.scaling != SCALE_CUSTOM) {
|
||||
// center the layer
|
||||
g_layer_x = 800 / 2 - g_layer_w / 2;
|
||||
g_layer_y = 480 / 2 - g_layer_h / 2;
|
||||
}
|
||||
|
||||
switch (currentConfig.scaling) {
|
||||
case SCALE_FULLSCREEN:
|
||||
case SCALE_CUSTOM:
|
||||
fb_top = start_line;
|
||||
fb_h = line_count;
|
||||
break;
|
||||
}
|
||||
g_osd_fps_x = is_32cols ? 232 : 264;
|
||||
g_osd_y = fb_top + fb_h - 8;
|
||||
|
||||
pnd_setup_layer(1, g_layer_x, g_layer_y, g_layer_w, g_layer_h);
|
||||
vout_fbdev_clear(layer_fb);
|
||||
vout_fbdev_resize(layer_fb, fb_w, fb_h, 16, fb_left, fb_right, fb_top, fb_bottom, 3);
|
||||
plat_video_flip();
|
||||
}
|
||||
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
static int pal_old = -1;
|
||||
static int filter_old = -1;
|
||||
char buf[128];
|
||||
|
||||
if (currentConfig.CPUclock != get_cpu_clock()) {
|
||||
snprintf(buf, sizeof(buf), "unset DISPLAY; echo y | %s/op_cpuspeed.sh %d",
|
||||
pnd_script_base, currentConfig.CPUclock);
|
||||
system(buf);
|
||||
}
|
||||
|
||||
if (Pico.m.pal != pal_old) {
|
||||
snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
|
||||
pnd_script_base, Pico.m.pal ? 50 : 60);
|
||||
system(buf);
|
||||
pal_old = Pico.m.pal;
|
||||
}
|
||||
|
||||
if (currentConfig.filter != filter_old) {
|
||||
apply_filter(currentConfig.filter);
|
||||
filter_old = currentConfig.filter;
|
||||
}
|
||||
|
||||
// make sure there is no junk left behind the layer
|
||||
memset32(g_menuscreen_ptr, 0, g_menuscreen_w * g_menuscreen_h * 2 / 4);
|
||||
g_menuscreen_ptr = vout_fbdev_flip(main_fb);
|
||||
|
||||
// emu_video_mode_change will call pnd_setup_layer()
|
||||
|
||||
// dirty buffers better go now than during gameplay
|
||||
sync();
|
||||
sleep(0);
|
||||
|
||||
pemu_sound_start();
|
||||
}
|
||||
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
|
||||
/* do one more frame for menu bg */
|
||||
pemu_forced_frame(0, 1);
|
||||
|
||||
pnd_setup_layer(0, g_layer_x, g_layer_y, g_layer_w, g_layer_h);
|
||||
}
|
||||
|
||||
void plat_wait_till_us(unsigned int us_to)
|
||||
{
|
||||
unsigned int now;
|
||||
signed int diff;
|
||||
|
||||
now = plat_get_ticks_us();
|
||||
|
||||
// XXX: need to check NOHZ
|
||||
diff = (signed int)(us_to - now);
|
||||
if (diff > 10000) {
|
||||
//printf("sleep %d\n", us_to - now);
|
||||
usleep(diff * 15 / 16);
|
||||
now = plat_get_ticks_us();
|
||||
//printf(" wake %d\n", (signed)(us_to - now));
|
||||
}
|
||||
/*
|
||||
while ((signed int)(us_to - now) > 512) {
|
||||
spend_cycles(1024);
|
||||
now = plat_get_ticks_us();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void plat_early_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
const char *main_fb_name, *layer_fb_name;
|
||||
int fd, ret, w, h;
|
||||
|
||||
main_fb_name = getenv("FBDEV_MAIN");
|
||||
if (main_fb_name == NULL)
|
||||
main_fb_name = "/dev/fb0";
|
||||
|
||||
layer_fb_name = getenv("FBDEV_LAYER");
|
||||
if (layer_fb_name == NULL)
|
||||
layer_fb_name = "/dev/fb1";
|
||||
|
||||
// must set the layer up first to be able to use it
|
||||
fd = open(layer_fb_name, O_RDWR);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "%s: ", layer_fb_name);
|
||||
perror("open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = pnd_setup_layer_(fd, 0, g_layer_x, g_layer_y, g_layer_w, g_layer_h);
|
||||
close(fd);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "failed to set up layer, exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
xenv_init();
|
||||
|
||||
w = h = 0;
|
||||
main_fb = vout_fbdev_init(main_fb_name, &w, &h, 16, 2);
|
||||
if (main_fb == NULL) {
|
||||
fprintf(stderr, "couldn't init fb: %s\n", main_fb_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_menuscreen_w = w;
|
||||
g_menuscreen_h = h;
|
||||
g_menuscreen_ptr = vout_fbdev_flip(main_fb);
|
||||
|
||||
w = 320; h = 240;
|
||||
layer_fb = vout_fbdev_init(layer_fb_name, &w, &h, 16, 3);
|
||||
if (layer_fb == NULL) {
|
||||
fprintf(stderr, "couldn't init fb: %s\n", layer_fb_name);
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
if (w != g_screen_width || h != g_screen_height) {
|
||||
fprintf(stderr, "%dx%d not supported on %s\n", w, h, layer_fb_name);
|
||||
goto fail1;
|
||||
}
|
||||
g_screen_ptr = vout_fbdev_flip(layer_fb);
|
||||
|
||||
temp_frame = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
|
||||
if (temp_frame == NULL) {
|
||||
fprintf(stderr, "OOM\n");
|
||||
goto fail1;
|
||||
}
|
||||
g_menubg_ptr = temp_frame;
|
||||
g_menubg_src_ptr = temp_frame;
|
||||
PicoDraw2FB = temp_frame;
|
||||
|
||||
sndout_oss_init();
|
||||
pnd_menu_init();
|
||||
|
||||
in_set_config(in_name_to_id("evdev:gpio-keys"), IN_CFG_KEY_NAMES,
|
||||
pandora_gpio_keys, sizeof(pandora_gpio_keys));
|
||||
return;
|
||||
|
||||
fail1:
|
||||
vout_fbdev_finish(layer_fb);
|
||||
fail0:
|
||||
vout_fbdev_finish(main_fb);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void plat_finish(void)
|
||||
{
|
||||
sndout_oss_exit();
|
||||
vout_fbdev_finish(main_fb);
|
||||
xenv_finish();
|
||||
|
||||
printf("all done\n");
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
extern char **pnd_filter_list;
|
||||
extern int g_layer_cx, g_layer_cy;
|
||||
extern int g_layer_cw, g_layer_ch;
|
||||
|
||||
void pnd_menu_init(void);
|
||||
int pnd_setup_layer(int enabled, int x, int y, int w, int h);
|
||||
void pnd_restore_layer_data(void);
|
||||
|
||||
enum {
|
||||
SCALE_1x1,
|
||||
SCALE_2x2_3x2,
|
||||
SCALE_2x2_2x2,
|
||||
SCALE_FULLSCREEN,
|
||||
SCALE_CUSTOM,
|
||||
};
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define CASE_SENSITIVE_FS 1 // CS filesystem
|
||||
#define DONT_OPEN_MANY_FILES 0
|
||||
#define REDUCE_IO_CALLS 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 1
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define MSCREEN_SIZE_FIXED 0
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
|
||||
// pico.c
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
#define SIMPLE_WRITE_SOUND 0
|
||||
|
||||
// logging emu events
|
||||
#define EL_LOGMASK (EL_STATUS|EL_IDLE) // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO|EL_INTS|EL_CDPOLL) // xffff
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "/"
|
||||
#define PATH_SEP_C '/'
|
||||
#define MENU_X2 1
|
||||
|
||||
#endif //PORT_CONFIG_H
|
|
@ -1,13 +0,0 @@
|
|||
@ vim:filetype=armasm
|
||||
|
||||
@ .equiv START_ROW, 1
|
||||
@ .equiv END_ROW, 27
|
||||
@ one row means 8 pixels. If above example was used, (27-1)*8=208 lines would be rendered.
|
||||
.equiv START_ROW, 0
|
||||
.equiv END_ROW, 28
|
||||
|
||||
.equiv UNALIGNED_DRAWLINEDEST, 0
|
||||
|
||||
@ this should be set to one only for GP2X port
|
||||
.equiv EXTERNAL_YM2612, 1
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#define VERSION "1.80"
|
||||
|
205
psp/Makefile
205
psp/Makefile
|
@ -1,205 +0,0 @@
|
|||
|
||||
# pspdev is expected to be in path
|
||||
PSPSDK = $(shell psp-config --pspsdk-path)
|
||||
|
||||
# settings
|
||||
#use_musashi = 1
|
||||
#use_mz80 = 1
|
||||
amalgamate = 0
|
||||
for_15fw = 1
|
||||
# :!touch platform/psp/psp.c
|
||||
|
||||
|
||||
CFLAGS += -I../.. -I. -DNO_SYNC -D_ASM_DRAW_C_AMIPS
|
||||
CFLAGS += -Wall -Winline -G0
|
||||
#CFLAGS += -DLPRINTF_STDIO
|
||||
#CFLAGS += -pg
|
||||
ifeq ($(DEBUG),)
|
||||
CFLAGS += -O2 -ftracer -fstrength-reduce -ffast-math
|
||||
else
|
||||
CFLAGS += -ggdb
|
||||
endif
|
||||
ifeq "$(for_15fw)" "1"
|
||||
CFLAGS += -DFW15
|
||||
endif
|
||||
|
||||
|
||||
# frontend and stuff
|
||||
OBJS += main.o emu.o mp3.o menu.o psp.o asm_utils.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/emu.o platform/common/menu.o platform/common/fonts.o platform/common/config.o platform/common/readpng.o
|
||||
|
||||
# Pico
|
||||
ifeq "$(amalgamate)" "1"
|
||||
OBJS += ../../picoAll.o
|
||||
else
|
||||
OBJS += pico/area.o pico/cart.o pico/memory.o pico/misc.o pico/pico.o pico/sek.o pico/videoport.o \
|
||||
pico/draw2.o pico/draw.o pico/z80if.o pico/patch.o pico/draw_amips.o pico/memory_amips.o \
|
||||
pico/misc_amips.o pico/debug.o
|
||||
# Pico - CD
|
||||
OBJS += pico/cd/pico.o pico/cd/memory.o pico/cd/sek.o pico/cd/LC89510.o \
|
||||
pico/cd/cd_sys.o pico/cd/cd_file.o pico/cd/cue.o pico/cd/gfx_cd.o \
|
||||
pico/cd/area.o pico/cd/misc.o pico/cd/pcm.o pico/cd/buffering.o
|
||||
# Pico - carthw
|
||||
OBJS += pico/carthw/carthw.o pico/carthw/svp/svp.o pico/carthw/svp/memory.o \
|
||||
pico/carthw/svp/ssp16.o
|
||||
# Pico - Pico
|
||||
OBJS += pico/pico/pico.o pico/pico/memory.o pico/pico/xpcm.o
|
||||
endif
|
||||
|
||||
# Pico - sound
|
||||
ifneq "$(amalgamate)" "1"
|
||||
OBJS += pico/sound/sound.o
|
||||
endif
|
||||
OBJS += pico/sound/mix.o
|
||||
OBJS += pico/sound/sn76496.o pico/sound/ym2612.o
|
||||
# zlib (hacked)
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o \
|
||||
zlib/uncompr.o
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
# CPU cores
|
||||
ifeq "$(use_musashi)" "1"
|
||||
CFLAGS += -DEMU_M68K
|
||||
OBJS += cpu/musashi/m68kops.o cpu/musashi/m68kcpu.o
|
||||
else
|
||||
CFLAGS += -DEMU_F68K
|
||||
OBJS += cpu/fame/famec.o
|
||||
endif
|
||||
# z80
|
||||
ifeq "$(use_mz80)" "1"
|
||||
CFLAGS += -D_USE_MZ80
|
||||
OBJS += cpu/mz80/mz80.o
|
||||
else
|
||||
CFLAGS += -D_USE_CZ80
|
||||
OBJS += cpu/cz80/cz80.o
|
||||
endif
|
||||
# bg images
|
||||
OBJS += data/bg32.o data/bg40.o
|
||||
|
||||
vpath %.c = ../..
|
||||
vpath %.s = ../..
|
||||
DIRS = platform platform/psp platform/common pico pico/cd pico/pico pico/sound pico/carthw/svp \
|
||||
zlib unzip cpu cpu/musashi cpu/fame cpu/mz80 cpu/cz80
|
||||
|
||||
|
||||
LIBS += -lpng -lm -lpspgu -lpsppower -lpspaudio -lpsprtc -lpspaudiocodec -lpspkubridge
|
||||
#LIBS += -lpspprof
|
||||
LDFLAGS += -Wl,-Map=PicoDrive.map
|
||||
|
||||
|
||||
# target
|
||||
TARGET = PicoDrive
|
||||
EXTRA_TARGETS = mkdirs EBOOT.PBP
|
||||
PSP_EBOOT_TITLE = PicoDrive
|
||||
PSP_EBOOT_ICON = data/icon.png
|
||||
#PSP_EBOOT_PIC1 = .png
|
||||
ifneq "$(for_15fw)" "1"
|
||||
BUILD_PRX = 1
|
||||
endif
|
||||
|
||||
CUSTOM_CLEAN = myclean
|
||||
|
||||
include $(PSPSDK)/lib/build.mak
|
||||
|
||||
# some additional rules
|
||||
mkdirs:
|
||||
mkdir -p $(DIRS)
|
||||
|
||||
.c.o:
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
AS := psp-as
|
||||
|
||||
.s.o:
|
||||
@echo ">>>" $<
|
||||
$(AS) -march=allegrex -mtune=allegrex $< -o $@
|
||||
|
||||
../../cpu/musashi/m68kops.c :
|
||||
make -C ../../cpu/musashi
|
||||
|
||||
cpu/fame/famec.o : ../../cpu/fame/famec.c
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -Wno-unused -c $< -o $@
|
||||
|
||||
pico/misc.o : ../../pico/misc.c
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -c $< -o $@ -D_ASM_MISC_C_AMIPS
|
||||
|
||||
pico/memory.o : ../../pico/memory.c
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -O2 -c $< -o $@ -D_ASM_MEMORY_C -D_ASM_MEMORY_C_AMIPS
|
||||
|
||||
pico/cd/memory.o : ../../pico/cd/memory.c
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -O2 -c $< -o $@
|
||||
|
||||
pico/cd/gfx_cd.o : ../../pico/cd/gfx_cd.c
|
||||
@echo ">>>" $<
|
||||
$(CC) $(CFLAGS) -O2 -c $< -o $@
|
||||
|
||||
readme.txt: ../../tools/textfilter ../base_readme.txt
|
||||
../../tools/textfilter ../base_readme.txt $@ PSP
|
||||
|
||||
../../tools/textfilter: ../../tools/textfilter.c
|
||||
make -C ../../tools/ textfilter
|
||||
|
||||
data/bg32.o: data/bg32.bin
|
||||
bin2o -i $< $@ bgdatac32
|
||||
|
||||
data/bg40.o: data/bg40.bin
|
||||
bin2o -i $< $@ bgdatac40
|
||||
|
||||
#
|
||||
ifndef UPDIR
|
||||
UPDIR = /media/disk/PSP/GAME/PicoDrive/
|
||||
endif
|
||||
up: EBOOT.PBP
|
||||
@cp -v $^ $(UPDIR)
|
||||
|
||||
|
||||
# cleanup
|
||||
|
||||
myclean:
|
||||
#rm -rf $(DIRS)
|
||||
$(RM) PicoDrive.map
|
||||
make -C ../../cpu/musashi clean
|
||||
|
||||
|
||||
clean_prof:
|
||||
find ../.. -name '*.gcno' -delete
|
||||
find ../.. -name '*.gcda' -delete
|
||||
|
||||
# ----------- release -----------
|
||||
ifneq ($(findstring rel,$(MAKECMDGOALS)),)
|
||||
ifeq ($(VER),)
|
||||
$(error need VER)
|
||||
endif
|
||||
endif
|
||||
|
||||
# ?
|
||||
rel: EBOOT.PBP readme.txt ../game_def.cfg
|
||||
mkdir -p PicoDrive/skin/
|
||||
cp $^ PicoDrive/
|
||||
cp skin/* PicoDrive/skin/
|
||||
zip -9 -r ../../PicoDrive_psp_$(VER).zip PicoDrive
|
||||
rm -rf PicoDrive
|
||||
mkdir bin_to_cso_mp3
|
||||
cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/
|
||||
zip -9 -r ../../PicoDrive_psp_$(VER).zip bin_to_cso_mp3
|
||||
rm -rf bin_to_cso_mp3
|
||||
|
||||
rel_kxploit: readme.txt ../game_def.cfg
|
||||
mkdir -p PicoDrive/skin/
|
||||
cp $^ PicoDrive/
|
||||
cp skin/* PicoDrive/skin/
|
||||
zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip PicoDrive
|
||||
zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip PicoDrive%
|
||||
mkdir bin_to_cso_mp3
|
||||
cp ../../tools/bin_to_cso_mp3/* bin_to_cso_mp3/
|
||||
zip -9 -r ../../PicoDrive_psp_$(VER)_kxploit.zip bin_to_cso_mp3
|
||||
rm -rf bin_to_cso_mp3
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
// pointers must be word aligned, gammaa_val = -4..16, black_lvl = {0,1,2}
|
||||
void do_pal_convert(unsigned short *dest, unsigned short *src, int gammaa_val, int black_lvl);
|
135
psp/asm_utils.s
135
psp/asm_utils.s
|
@ -1,135 +0,0 @@
|
|||
# vim:filetype=mips
|
||||
|
||||
# some asm utils
|
||||
# (c) Copyright 2007, Grazvydas "notaz" Ignotas
|
||||
# All Rights Reserved
|
||||
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
.data
|
||||
.align 4
|
||||
|
||||
.byte 0, 1, 6, 11, 16, 21, 26, 31 # -4
|
||||
.byte 0, 2, 7, 12, 16, 21, 26, 31 # -3
|
||||
.byte 0, 3, 7, 12, 17, 22, 26, 31 # -2
|
||||
.byte 0, 4, 8, 13, 17, 22, 26, 31 # -1
|
||||
pal_gmtab:
|
||||
.byte 0, 5, 10, 15, 16, 21, 26, 31 # 0
|
||||
.byte 0, 6, 10, 15, 19, 23, 27, 31
|
||||
.byte 0, 7, 11, 15, 19, 23, 27, 31
|
||||
.byte 0, 8, 12, 16, 19, 23, 27, 31
|
||||
.byte 0, 9, 12, 16, 20, 24, 27, 31
|
||||
.byte 0, 10, 13, 17, 20, 24, 27, 31
|
||||
.byte 0, 10, 14, 17, 21, 24, 28, 31
|
||||
.byte 0, 11, 15, 18, 21, 24, 28, 31
|
||||
.byte 0, 12, 15, 18, 22, 25, 28, 31
|
||||
.byte 0, 13, 16, 19, 22, 25, 28, 31
|
||||
.byte 0, 14, 17, 20, 22, 25, 28, 31 # 10
|
||||
.byte 0, 15, 17, 20, 23, 26, 28, 31
|
||||
.byte 0, 16, 18, 21, 23, 26, 28, 31
|
||||
.byte 0, 16, 19, 21, 24, 26, 29, 31
|
||||
.byte 0, 17, 20, 22, 24, 26, 29, 31
|
||||
.byte 0, 18, 20, 22, 25, 27, 29, 31
|
||||
.byte 0, 19, 21, 23, 25, 27, 29, 31 # 16
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
# bbbb bggg gggr rrrr
|
||||
|
||||
#.global pal_gmtab
|
||||
.global do_pal_convert # dest, src, gammaa_val, black_lvl
|
||||
|
||||
do_pal_convert:
|
||||
bnez $a2, dpc_gma
|
||||
li $t0, 64/2
|
||||
bnez $a3, dpc_gma
|
||||
lui $t2, 0x00e
|
||||
ori $t2, 0x00e
|
||||
lui $t3, 0x006
|
||||
ori $t3, 0x006
|
||||
lui $t4, 0x0e0
|
||||
ori $t4, 0x0e0
|
||||
lui $t6, 0xe00
|
||||
ori $t6, 0xe00
|
||||
lui $t7, 0x600
|
||||
ori $t7, 0x600
|
||||
|
||||
dpc_loop:
|
||||
lw $v0, 0($a1)
|
||||
addiu $a1, 4
|
||||
and $v1, $v0, $t2 # r
|
||||
sll $v1, 1
|
||||
and $t9, $v0, $t3
|
||||
srl $t9, 1
|
||||
or $v1, $t9 # r
|
||||
and $t9, $v0, $t4 # g
|
||||
sll $t8, $t9, 3
|
||||
or $v1, $t8
|
||||
or $v1, $t9 # g
|
||||
and $t9, $v0, $t6 # b
|
||||
sll $t9, 4
|
||||
or $v1, $t9
|
||||
and $t9, $v0, $t7
|
||||
sll $t9, 2
|
||||
or $v1, $t9 # b
|
||||
sw $v1, 0($a0)
|
||||
addiu $t0, -1
|
||||
bnez $t0, dpc_loop
|
||||
addiu $a0, 4
|
||||
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
# non-zero gamma
|
||||
dpc_gma:
|
||||
slt $t2, $a2, $0
|
||||
sll $a2, 3
|
||||
lui $t1, %hi(pal_gmtab)
|
||||
addiu $t1, %lo(pal_gmtab)
|
||||
addu $a2, $t1
|
||||
beqz $a3, dpc_gma_loop
|
||||
sb $0, 0($a2) # black level 0
|
||||
bnez $t2, dpc_gma_loop # gamma < 0, keep black at 0
|
||||
addiu $a3, -2
|
||||
slt $t2, $a3, $0 # t2 = a3_orig == 1 ? 1 : 0
|
||||
lb $t1, 1($a2)
|
||||
addiu $t1, -2
|
||||
srlv $t1, $t1, $t2
|
||||
sb $t1, 0($a2)
|
||||
|
||||
dpc_gma_loop:
|
||||
lw $v0, 0($a1)
|
||||
addiu $a1, 4
|
||||
ext $v1, $v0, 1, 3
|
||||
addu $v1, $a2
|
||||
lb $v1, 0($v1)
|
||||
ext $t1, $v0, 5, 3
|
||||
addu $t1, $a2
|
||||
lb $t1, 0($t1)
|
||||
ext $t2, $v0, 9, 3
|
||||
addu $t2, $a2
|
||||
lb $t2, 0($t2)
|
||||
ext $t3, $v0, 17, 3
|
||||
addu $t3, $a2
|
||||
lb $t3, 0($t3)
|
||||
ext $t4, $v0, 21, 3
|
||||
addu $t4, $a2
|
||||
lb $t4, 0($t4)
|
||||
ext $t5, $v0, 25, 3
|
||||
addu $t5, $a2
|
||||
lb $t5, 0($t5)
|
||||
ins $v1, $t1, 6, 5
|
||||
ins $v1, $t2, 11, 5
|
||||
ins $v1, $t3, 16, 5
|
||||
ins $v1, $t4, 22, 5
|
||||
ins $v1, $t5, 27, 5
|
||||
sw $v1, 0($a0)
|
||||
addiu $t0, -1
|
||||
bnez $t0, dpc_gma_loop
|
||||
addiu $a0, 4
|
||||
|
||||
jr $ra
|
||||
nop
|
||||
|
15
psp/emu.h
15
psp/emu.h
|
@ -1,15 +0,0 @@
|
|||
// (c) Copyright 2006-2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
|
||||
extern int engineStateSuspend;
|
||||
|
||||
void emu_HandleResume(void);
|
||||
|
||||
void emu_msg_cb(const char *msg);
|
||||
|
||||
// actually comes from Pico/Misc_amips.s
|
||||
void memset32_uncached(int *dest, int c, int count);
|
||||
|
121
psp/main.c
121
psp/main.c
|
@ -1,121 +0,0 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <string.h>
|
||||
#include "psp.h"
|
||||
#include "emu.h"
|
||||
#include "menu.h"
|
||||
#include "mp3.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/lprintf.h"
|
||||
|
||||
#ifdef GPROF
|
||||
#include <pspprof.h>
|
||||
#endif
|
||||
|
||||
#ifdef GCOV
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void dummy(void)
|
||||
{
|
||||
engineState = atoi(rom_fname_reload);
|
||||
setbuf(NULL, NULL);
|
||||
getenv(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pico_main(void)
|
||||
{
|
||||
psp_init();
|
||||
|
||||
emu_prepareDefaultConfig();
|
||||
emu_ReadConfig(0, 0);
|
||||
config_readlrom(PicoConfigFile);
|
||||
|
||||
emu_Init();
|
||||
menu_init();
|
||||
// moved to emu_Loop(), after CPU clock change..
|
||||
//mp3_init();
|
||||
|
||||
engineState = PGS_Menu;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
switch (engineState)
|
||||
{
|
||||
case PGS_Menu:
|
||||
#ifndef GPROF
|
||||
menu_loop();
|
||||
#else
|
||||
strcpy(rom_fname_reload, rom_fname_loaded);
|
||||
engineState = PGS_ReloadRom;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PGS_ReloadRom:
|
||||
if (emu_reload_rom(rom_fname_reload)) {
|
||||
engineState = PGS_Running;
|
||||
if (mp3_last_error != 0)
|
||||
engineState = PGS_Menu; // send to menu to display mp3 error
|
||||
} else {
|
||||
lprintf("PGS_ReloadRom == 0\n");
|
||||
engineState = PGS_Menu;
|
||||
}
|
||||
break;
|
||||
|
||||
case PGS_Suspending:
|
||||
while (engineState == PGS_Suspending)
|
||||
psp_wait_suspend();
|
||||
break;
|
||||
|
||||
case PGS_SuspendWake:
|
||||
psp_unhandled_suspend = 0;
|
||||
psp_resume_suspend();
|
||||
emu_HandleResume();
|
||||
engineState = engineStateSuspend;
|
||||
break;
|
||||
|
||||
case PGS_RestartRun:
|
||||
engineState = PGS_Running;
|
||||
|
||||
case PGS_Running:
|
||||
if (psp_unhandled_suspend) {
|
||||
psp_unhandled_suspend = 0;
|
||||
psp_resume_suspend();
|
||||
emu_HandleResume();
|
||||
break;
|
||||
}
|
||||
pemu_loop();
|
||||
#ifdef GPROF
|
||||
goto endloop;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PGS_Quit:
|
||||
goto endloop;
|
||||
|
||||
default:
|
||||
lprintf("engine got into unknown state (%i), exitting\n", engineState);
|
||||
goto endloop;
|
||||
}
|
||||
}
|
||||
|
||||
endloop:
|
||||
|
||||
mp3_deinit();
|
||||
emu_Deinit();
|
||||
#ifdef GPROF
|
||||
gprof_cleanup();
|
||||
#endif
|
||||
#ifndef GCOV
|
||||
psp_finish();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1786
psp/menu.c
1786
psp/menu.c
File diff suppressed because it is too large
Load diff
14
psp/menu.h
14
psp/menu.h
|
@ -1,14 +0,0 @@
|
|||
// (c) Copyright 2006,2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
void menu_loop(void);
|
||||
int menu_loop_tray(void);
|
||||
void menu_romload_prepare(const char *rom_name);
|
||||
void menu_romload_end(void);
|
||||
|
||||
|
||||
#define CONFIGURABLE_KEYS (PBTN_UP|PBTN_LEFT|PBTN_RIGHT|PBTN_DOWN|PBTN_L|PBTN_R|PBTN_TRIANGLE|PBTN_CIRCLE|PBTN_X|PBTN_SQUARE|PBTN_START| \
|
||||
PBTN_NUB_UP|PBTN_NUB_RIGHT|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NOTE)
|
||||
|
492
psp/mp3.c
492
psp/mp3.c
|
@ -1,492 +0,0 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspsdk.h>
|
||||
#include <pspaudiocodec.h>
|
||||
#include <kubridge.h>
|
||||
|
||||
#include "../../pico/pico_int.h"
|
||||
#include "../../pico/sound/mix.h"
|
||||
#include "../common/lprintf.h"
|
||||
|
||||
int mp3_last_error = 0;
|
||||
|
||||
static int initialized = 0;
|
||||
static SceUID thread_job_sem = -1;
|
||||
static SceUID thread_busy_sem = -1;
|
||||
static int thread_exit = 0;
|
||||
|
||||
// MPEG-1, layer 3
|
||||
static int bitrates[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 };
|
||||
//static int samplerates[] = { 44100, 48000, 32000, 0 };
|
||||
|
||||
#define MIN_INFRAME_SIZE 96
|
||||
#define IN_BUFFER_SIZE (2*1024)
|
||||
|
||||
static unsigned long mp3_codec_struct[65] __attribute__((aligned(64)));
|
||||
|
||||
static unsigned char mp3_src_buffer[2][IN_BUFFER_SIZE] __attribute__((aligned(64)));
|
||||
static short mp3_mix_buffer[2][1152*2] __attribute__((aligned(64)));
|
||||
static int working_buf = 0;
|
||||
|
||||
static const char *mp3_fname = NULL;
|
||||
static SceUID mp3_handle = -1;
|
||||
static int mp3_src_pos = 0, mp3_src_size = 0;
|
||||
|
||||
static int decode_thread(SceSize args, void *argp);
|
||||
|
||||
|
||||
static void psp_sem_lock(SceUID sem)
|
||||
{
|
||||
int ret = sceKernelWaitSema(sem, 1, 0);
|
||||
if (ret < 0) lprintf("sceKernelWaitSema(%08x) failed with %08x\n", sem, ret);
|
||||
}
|
||||
|
||||
static void psp_sem_unlock(SceUID sem)
|
||||
{
|
||||
int ret = sceKernelSignalSema(sem, 1);
|
||||
if (ret < 0) lprintf("sceKernelSignalSema(%08x) failed with %08x\n", sem, ret);
|
||||
}
|
||||
|
||||
// only accepts MPEG-1, layer3
|
||||
static int find_sync_word(unsigned char *data, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len-1; i++)
|
||||
{
|
||||
if ( data[i+0] != 0xff) continue;
|
||||
if ((data[i+1] & 0xfe) == 0xfa) return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int read_next_frame(int which_buffer)
|
||||
{
|
||||
int i, bytes_read, frame_offset;
|
||||
int bitrate, padding, frame_size = 0;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
bytes_read = sceIoRead(mp3_handle, mp3_src_buffer[which_buffer], sizeof(mp3_src_buffer[which_buffer]));
|
||||
mp3_src_pos += bytes_read;
|
||||
if (bytes_read < MIN_INFRAME_SIZE) {
|
||||
mp3_src_pos = mp3_src_size;
|
||||
return 0; // EOF/IO failure
|
||||
}
|
||||
frame_offset = find_sync_word(mp3_src_buffer[which_buffer], bytes_read);
|
||||
if (frame_offset < 0) {
|
||||
lprintf("missing syncword, foffs=%i\n", mp3_src_pos - bytes_read);
|
||||
mp3_src_pos--;
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
continue;
|
||||
}
|
||||
if (bytes_read - frame_offset < 4) {
|
||||
lprintf("syncword @ EOB, foffs=%i\n", mp3_src_pos - bytes_read);
|
||||
mp3_src_pos--;
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
continue;
|
||||
}
|
||||
|
||||
bitrate = mp3_src_buffer[which_buffer][frame_offset+2] >> 4;
|
||||
padding = (mp3_src_buffer[which_buffer][frame_offset+2] & 2) >> 1;
|
||||
|
||||
frame_size = 144000*bitrates[bitrate]/44100 + padding;
|
||||
if (frame_size <= 0) {
|
||||
lprintf("bad frame, foffs=%i\n", mp3_src_pos - bytes_read);
|
||||
continue; // bad frame
|
||||
}
|
||||
|
||||
if (bytes_read - frame_offset < frame_size)
|
||||
{
|
||||
lprintf("unfit, foffs=%i\n", mp3_src_pos - bytes_read);
|
||||
mp3_src_pos -= bytes_read - frame_offset;
|
||||
if (mp3_src_size - mp3_src_pos < frame_size) {
|
||||
mp3_src_pos = mp3_src_size;
|
||||
return 0; // EOF
|
||||
}
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
continue; // didn't fit, re-read..
|
||||
}
|
||||
|
||||
if (frame_offset) {
|
||||
//lprintf("unaligned, foffs=%i, offs=%i\n", mp3_src_pos - bytes_read, frame_offset);
|
||||
memmove(mp3_src_buffer[which_buffer], mp3_src_buffer[which_buffer] + frame_offset, frame_size);
|
||||
}
|
||||
|
||||
// align for next frame read
|
||||
mp3_src_pos -= bytes_read - (frame_offset + frame_size);
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return frame_size > 0 ? frame_size : -1;
|
||||
}
|
||||
|
||||
|
||||
static SceUID load_start_module(const char *prxname)
|
||||
{
|
||||
SceUID mod, mod1;
|
||||
int status, ret;
|
||||
|
||||
mod = pspSdkLoadStartModule(prxname, PSP_MEMORY_PARTITION_KERNEL);
|
||||
if (mod < 0) {
|
||||
lprintf("failed to load %s (%08x), trying kuKernelLoadModule\n", prxname, mod);
|
||||
mod1 = kuKernelLoadModule(prxname, 0, NULL);
|
||||
if (mod1 < 0) lprintf("kuKernelLoadModule failed with %08x\n", mod1);
|
||||
else {
|
||||
ret = sceKernelStartModule(mod1, 0, NULL, &status, 0);
|
||||
if (ret < 0) lprintf("sceKernelStartModule failed with %08x\n", ret);
|
||||
else mod = mod1;
|
||||
}
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
||||
int mp3_init(void)
|
||||
{
|
||||
SceUID thid, mod;
|
||||
int ret;
|
||||
|
||||
/* load modules */
|
||||
/* <= 1.5 (and probably some other, not sure which) fw need this to for audiocodec to work,
|
||||
* so if it fails, assume we are just on new enough firmware and continue.. */
|
||||
load_start_module("flash0:/kd/me_for_vsh.prx");
|
||||
|
||||
if (sceKernelDevkitVersion() < 0x02070010)
|
||||
mod = load_start_module("flash0:/kd/audiocodec.prx");
|
||||
else mod = load_start_module("flash0:/kd/avcodec.prx");
|
||||
if (mod < 0) {
|
||||
ret = mod;
|
||||
mod = load_start_module("flash0:/kd/audiocodec_260.prx"); // last chance..
|
||||
if (mod < 0) goto fail;
|
||||
}
|
||||
|
||||
/* audiocodec init */
|
||||
memset(mp3_codec_struct, 0, sizeof(mp3_codec_struct));
|
||||
ret = sceAudiocodecCheckNeedMem(mp3_codec_struct, 0x1002);
|
||||
if (ret < 0) {
|
||||
lprintf("sceAudiocodecCheckNeedMem failed with %08x\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = sceAudiocodecGetEDRAM(mp3_codec_struct, 0x1002);
|
||||
if (ret < 0) {
|
||||
lprintf("sceAudiocodecGetEDRAM failed with %08x\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = sceAudiocodecInit(mp3_codec_struct, 0x1002);
|
||||
if (ret < 0) {
|
||||
lprintf("sceAudiocodecInit failed with %08x\n", ret);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* thread and stuff */
|
||||
thread_job_sem = sceKernelCreateSema("p_mp3job_sem", 0, 0, 1, NULL);
|
||||
if (thread_job_sem < 0) {
|
||||
lprintf("sceKernelCreateSema() failed: %08x\n", thread_job_sem);
|
||||
ret = thread_job_sem;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
thread_busy_sem = sceKernelCreateSema("p_mp3busy_sem", 0, 1, 1, NULL);
|
||||
if (thread_busy_sem < 0) {
|
||||
lprintf("sceKernelCreateSema() failed: %08x\n", thread_busy_sem);
|
||||
ret = thread_busy_sem;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
/* use slightly higher prio then main */
|
||||
thread_exit = 0;
|
||||
thid = sceKernelCreateThread("mp3decode_thread", decode_thread, 30, 0x2000, 0, NULL);
|
||||
if (thid < 0) {
|
||||
lprintf("failed to create decode thread: %08x\n", thid);
|
||||
ret = thid;
|
||||
goto fail3;
|
||||
}
|
||||
ret = sceKernelStartThread(thid, 0, 0);
|
||||
if (ret < 0) {
|
||||
lprintf("failed to start decode thread: %08x\n", ret);
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
mp3_last_error = 0;
|
||||
initialized = 1;
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
sceKernelDeleteSema(thread_busy_sem);
|
||||
thread_busy_sem = -1;
|
||||
fail2:
|
||||
sceKernelDeleteSema(thread_job_sem);
|
||||
thread_job_sem = -1;
|
||||
fail1:
|
||||
sceAudiocodecReleaseEDRAM(mp3_codec_struct);
|
||||
fail:
|
||||
mp3_last_error = ret;
|
||||
initialized = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mp3_deinit(void)
|
||||
{
|
||||
lprintf("mp3_deinit, initialized=%i\n", initialized);
|
||||
|
||||
if (!initialized) return;
|
||||
thread_exit = 1;
|
||||
psp_sem_lock(thread_busy_sem);
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
|
||||
sceKernelSignalSema(thread_job_sem, 1);
|
||||
sceKernelDelayThread(100*1000);
|
||||
|
||||
if (mp3_handle >= 0) sceIoClose(mp3_handle);
|
||||
mp3_handle = -1;
|
||||
mp3_fname = NULL;
|
||||
|
||||
sceKernelDeleteSema(thread_busy_sem);
|
||||
thread_busy_sem = -1;
|
||||
sceKernelDeleteSema(thread_job_sem);
|
||||
thread_job_sem = -1;
|
||||
sceAudiocodecReleaseEDRAM(mp3_codec_struct);
|
||||
initialized = 0;
|
||||
}
|
||||
|
||||
// may overflow stack?
|
||||
static int decode_thread(SceSize args, void *argp)
|
||||
{
|
||||
int ret, frame_size;
|
||||
|
||||
lprintf("decode_thread started with id %08x, priority %i\n",
|
||||
sceKernelGetThreadId(), sceKernelGetThreadCurrentPriority());
|
||||
|
||||
while (!thread_exit)
|
||||
{
|
||||
psp_sem_lock(thread_job_sem);
|
||||
if (thread_exit) break;
|
||||
|
||||
psp_sem_lock(thread_busy_sem);
|
||||
//lprintf("{ job\n");
|
||||
|
||||
frame_size = read_next_frame(working_buf);
|
||||
if (frame_size > 0)
|
||||
{
|
||||
mp3_codec_struct[6] = (unsigned long)mp3_src_buffer[working_buf];
|
||||
mp3_codec_struct[8] = (unsigned long)mp3_mix_buffer[working_buf];
|
||||
mp3_codec_struct[7] = mp3_codec_struct[10] = frame_size;
|
||||
mp3_codec_struct[9] = 1152 * 4;
|
||||
|
||||
ret = sceAudiocodecDecode(mp3_codec_struct, 0x1002);
|
||||
if (ret < 0) lprintf("sceAudiocodecDecode failed with %08x\n", ret);
|
||||
}
|
||||
|
||||
//lprintf("} job\n");
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
}
|
||||
|
||||
lprintf("leaving decode thread\n");
|
||||
sceKernelExitDeleteThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// might be called before initialization
|
||||
int mp3_get_bitrate(void *f, int size)
|
||||
{
|
||||
int ret, retval = -1, sample_rate, bitrate;
|
||||
// filenames are stored instead handles in PSP, due to stupid max open file limit
|
||||
char *fname = f;
|
||||
|
||||
/* make sure thread is not busy.. */
|
||||
if (thread_busy_sem >= 0)
|
||||
psp_sem_lock(thread_busy_sem);
|
||||
|
||||
if (mp3_handle >= 0) sceIoClose(mp3_handle);
|
||||
mp3_handle = sceIoOpen(fname, PSP_O_RDONLY, 0777);
|
||||
if (mp3_handle < 0) {
|
||||
lprintf("sceIoOpen(%s) failed\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
mp3_src_pos = 0;
|
||||
ret = read_next_frame(0);
|
||||
if (ret <= 0) {
|
||||
lprintf("read_next_frame() failed (%s)\n", fname);
|
||||
goto end;
|
||||
}
|
||||
sample_rate = (mp3_src_buffer[0][2] & 0x0c) >> 2;
|
||||
bitrate = mp3_src_buffer[0][2] >> 4;
|
||||
|
||||
if (sample_rate != 0) {
|
||||
lprintf("unsupported samplerate (%s)\n", fname);
|
||||
goto end; // only 44kHz supported..
|
||||
}
|
||||
bitrate = bitrates[bitrate];
|
||||
if (bitrate == 0) {
|
||||
lprintf("unsupported bitrate (%s)\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* looking good.. */
|
||||
retval = bitrate;
|
||||
end:
|
||||
if (mp3_handle >= 0) sceIoClose(mp3_handle);
|
||||
mp3_handle = -1;
|
||||
mp3_fname = NULL;
|
||||
if (thread_busy_sem >= 0)
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
if (retval < 0) mp3_last_error = -1; // remember we had a problem..
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int mp3_job_started = 0, mp3_samples_ready = 0, mp3_buffer_offs = 0, mp3_play_bufsel = 0;
|
||||
|
||||
void mp3_start_play(void *f, int pos)
|
||||
{
|
||||
char *fname = f;
|
||||
|
||||
if (!initialized) return;
|
||||
|
||||
lprintf("mp3_start_play(%s) @ %i\n", fname, pos);
|
||||
psp_sem_lock(thread_busy_sem);
|
||||
|
||||
if (mp3_fname != fname || mp3_handle < 0)
|
||||
{
|
||||
if (mp3_handle >= 0) sceIoClose(mp3_handle);
|
||||
mp3_handle = sceIoOpen(fname, PSP_O_RDONLY, 0777);
|
||||
if (mp3_handle < 0) {
|
||||
lprintf("sceIoOpen(%s) failed\n", fname);
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
return;
|
||||
}
|
||||
mp3_src_size = sceIoLseek32(mp3_handle, 0, PSP_SEEK_END);
|
||||
mp3_fname = fname;
|
||||
}
|
||||
|
||||
// clear decoder state
|
||||
sceAudiocodecInit(mp3_codec_struct, 0x1002);
|
||||
|
||||
// seek..
|
||||
mp3_src_pos = (int) (((float)pos / 1023.0f) * (float)mp3_src_size);
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
lprintf("seek %i: %i/%i\n", pos, mp3_src_pos, mp3_src_size);
|
||||
|
||||
mp3_job_started = 1;
|
||||
mp3_samples_ready = mp3_buffer_offs = mp3_play_bufsel = 0;
|
||||
working_buf = 0;
|
||||
|
||||
/* send a request to decode first frame */
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
psp_sem_unlock(thread_job_sem);
|
||||
sceKernelDelayThread(1); // reschedule
|
||||
}
|
||||
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
int length_mp3;
|
||||
|
||||
// playback was started, track not ended
|
||||
if (mp3_handle < 0 || mp3_src_pos >= mp3_src_size) return;
|
||||
|
||||
length_mp3 = length;
|
||||
if (PsndRate == 22050) length_mp3 <<= 1; // mp3s are locked to 44100Hz stereo
|
||||
else if (PsndRate == 11025) length_mp3 <<= 2; // so make length 44100ish
|
||||
|
||||
/* do we have to wait? */
|
||||
if (mp3_job_started && mp3_samples_ready < length_mp3)
|
||||
{
|
||||
psp_sem_lock(thread_busy_sem);
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
mp3_job_started = 0;
|
||||
mp3_samples_ready += 1152;
|
||||
}
|
||||
|
||||
/* mix mp3 data, only stereo */
|
||||
if (mp3_samples_ready >= length_mp3)
|
||||
{
|
||||
int shr = 0;
|
||||
void (*mix_samples)(int *dest_buf, short *mp3_buf, int count) = mix_16h_to_32;
|
||||
if (PsndRate == 22050) { mix_samples = mix_16h_to_32_s1; shr = 1; }
|
||||
else if (PsndRate == 11025) { mix_samples = mix_16h_to_32_s2; shr = 2; }
|
||||
|
||||
if (1152 - mp3_buffer_offs >= length_mp3) {
|
||||
mix_samples(buffer, mp3_mix_buffer[mp3_play_bufsel] + mp3_buffer_offs*2, length<<1);
|
||||
|
||||
mp3_buffer_offs += length_mp3;
|
||||
} else {
|
||||
// collect samples from both buffers..
|
||||
int left = 1152 - mp3_buffer_offs;
|
||||
if (mp3_play_bufsel == 0)
|
||||
{
|
||||
mix_samples(buffer, mp3_mix_buffer[0] + mp3_buffer_offs*2, length<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mp3_play_bufsel = 1;
|
||||
} else {
|
||||
mix_samples(buffer, mp3_mix_buffer[1] + mp3_buffer_offs*2, (left>>shr)<<1);
|
||||
mp3_buffer_offs = length_mp3 - left;
|
||||
mix_samples(buffer + ((left>>shr)<<1),
|
||||
mp3_mix_buffer[0], (mp3_buffer_offs>>shr)<<1);
|
||||
mp3_play_bufsel = 0;
|
||||
}
|
||||
}
|
||||
mp3_samples_ready -= length_mp3;
|
||||
}
|
||||
|
||||
// ask to decode more if we already can
|
||||
if (!mp3_job_started)
|
||||
{
|
||||
mp3_job_started = 1;
|
||||
working_buf ^= 1;
|
||||
|
||||
/* next job.. */
|
||||
psp_sem_lock(thread_busy_sem); // just in case
|
||||
psp_sem_unlock(thread_busy_sem);
|
||||
psp_sem_unlock(thread_job_sem);
|
||||
sceKernelDelayThread(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mp3_get_offset(void) // 0-1023
|
||||
{
|
||||
unsigned int offs1024 = 0;
|
||||
int cdda_on;
|
||||
|
||||
cdda_on = (PicoAHW & PAHW_MCD) && (PicoOpt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&
|
||||
(Pico_mcd->scd.Status_CDC & 1) && mp3_handle >= 0;
|
||||
|
||||
if (cdda_on) {
|
||||
offs1024 = mp3_src_pos << 7;
|
||||
offs1024 /= mp3_src_size >> 3;
|
||||
}
|
||||
lprintf("offs1024=%u (%i/%i)\n", offs1024, mp3_src_pos, mp3_src_size);
|
||||
|
||||
return offs1024;
|
||||
}
|
||||
|
||||
|
||||
void mp3_reopen_file(void)
|
||||
{
|
||||
if (mp3_fname == NULL) return;
|
||||
lprintf("mp3_reopen_file(%s)\n", mp3_fname);
|
||||
|
||||
// try closing, just in case
|
||||
if (mp3_handle >= 0) sceIoClose(mp3_handle);
|
||||
|
||||
mp3_handle = sceIoOpen(mp3_fname, PSP_O_RDONLY, 0777);
|
||||
if (mp3_handle >= 0)
|
||||
sceIoLseek32(mp3_handle, mp3_src_pos, PSP_SEEK_SET);
|
||||
lprintf("mp3_reopen_file %s\n", mp3_handle >= 0 ? "ok" : "failed");
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
// additional stuff for PSP mp3 decoder implementation
|
||||
extern int mp3_last_error;
|
||||
|
||||
int mp3_init(void);
|
||||
void mp3_deinit(void);
|
||||
void mp3_reopen_file(void);
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define CASE_SENSITIVE_FS 0
|
||||
#define DONT_OPEN_MANY_FILES 1 // work around the stupid PSP ~10 open file limit
|
||||
#define REDUCE_IO_CALLS 1 // another workaround
|
||||
#define SIMPLE_WRITE_SOUND 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 1
|
||||
#define SCREEN_WIDTH 512
|
||||
#define SCREEN_HEIGHT 272
|
||||
#define MSCREEN_SIZE_FIXED 1
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw.c
|
||||
#define USE_BGR555 1
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
#define DRAW2_OVERRIDE_LINE_WIDTH 512
|
||||
|
||||
// pico.c
|
||||
extern void blit1(void);
|
||||
#define DRAW_FINISH_FUNC blit1
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
// logging emu events
|
||||
#define EL_LOGMASK (EL_STATUS|EL_IDLE) // (EL_STATUS|EL_ANOMALY|EL_UIO|EL_SRAMIO) // xffff
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "/"
|
||||
#define PATH_SEP_C '/'
|
||||
#define MENU_X2 0
|
||||
|
||||
#endif //PORT_CONFIG_H
|
372
psp/psp.c
372
psp/psp.c
|
@ -1,372 +0,0 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspiofilemgr.h>
|
||||
#include <pspdisplay.h>
|
||||
#include <psppower.h>
|
||||
#include <psprtc.h>
|
||||
#include <pspgu.h>
|
||||
#include <pspsdk.h>
|
||||
|
||||
#include "psp.h"
|
||||
#include "emu.h"
|
||||
#include "../common/lprintf.h"
|
||||
#include "version.h"
|
||||
|
||||
extern int pico_main(void);
|
||||
|
||||
#ifndef FW15
|
||||
|
||||
PSP_MODULE_INFO("PicoDrive", 0, 1, 51);
|
||||
PSP_HEAP_SIZE_MAX();
|
||||
|
||||
int main() { return pico_main(); } /* just a wrapper */
|
||||
|
||||
#else
|
||||
|
||||
PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 51);
|
||||
PSP_MAIN_THREAD_ATTR(0);
|
||||
|
||||
int main()
|
||||
{
|
||||
SceUID thid;
|
||||
|
||||
/* this is the thing we need the kernel mode for */
|
||||
pspSdkInstallNoDeviceCheckPatch();
|
||||
|
||||
thid = sceKernelCreateThread("pico_main", (SceKernelThreadEntry) pico_main, 32, 0x2000, PSP_THREAD_ATTR_USER, NULL);
|
||||
if (thid >= 0)
|
||||
sceKernelStartThread(thid, 0, 0);
|
||||
#ifndef GCOV
|
||||
sceKernelExitDeleteThread(0);
|
||||
#else
|
||||
while (engineState != PGS_Quit)
|
||||
sceKernelDelayThread(1024 * 1024);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int psp_unhandled_suspend = 0;
|
||||
|
||||
unsigned int __attribute__((aligned(16))) guCmdList[GU_CMDLIST_SIZE];
|
||||
|
||||
void *psp_screen = VRAM_FB0;
|
||||
|
||||
static int current_screen = 0; /* front bufer */
|
||||
|
||||
static SceUID main_thread_id = -1;
|
||||
|
||||
#define ANALOG_DEADZONE 80
|
||||
|
||||
/* Exit callback */
|
||||
static int exit_callback(int arg1, int arg2, void *common)
|
||||
{
|
||||
sceKernelExitGame();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Power Callback */
|
||||
static int power_callback(int unknown, int pwrflags, void *common)
|
||||
{
|
||||
lprintf("power_callback: flags: 0x%08X\n", pwrflags);
|
||||
|
||||
/* check for power switch and suspending as one is manual and the other automatic */
|
||||
if (pwrflags & PSP_POWER_CB_POWER_SWITCH || pwrflags & PSP_POWER_CB_SUSPENDING || pwrflags & PSP_POWER_CB_STANDBY)
|
||||
{
|
||||
psp_unhandled_suspend = 1;
|
||||
if (engineState != PGS_Suspending)
|
||||
engineStateSuspend = engineState;
|
||||
sceKernelDelayThread(100000); // ??
|
||||
}
|
||||
else if (pwrflags & PSP_POWER_CB_RESUME_COMPLETE)
|
||||
{
|
||||
engineState = PGS_SuspendWake;
|
||||
}
|
||||
|
||||
//sceDisplayWaitVblankStart();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback thread */
|
||||
static int callback_thread(SceSize args, void *argp)
|
||||
{
|
||||
int cbid;
|
||||
|
||||
lprintf("callback_thread started with id %08x, priority %i\n",
|
||||
sceKernelGetThreadId(), sceKernelGetThreadCurrentPriority());
|
||||
|
||||
cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
|
||||
sceKernelRegisterExitCallback(cbid);
|
||||
cbid = sceKernelCreateCallback("Power Callback", power_callback, NULL);
|
||||
scePowerRegisterCallback(0, cbid);
|
||||
|
||||
sceKernelSleepThreadCB();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void psp_init(void)
|
||||
{
|
||||
SceUID thid;
|
||||
char buff[128], *r;
|
||||
|
||||
/* fw 1.5 sometimes returns 8002032c, although getcwd works */
|
||||
r = getcwd(buff, sizeof(buff));
|
||||
if (r) sceIoChdir(buff);
|
||||
|
||||
main_thread_id = sceKernelGetThreadId();
|
||||
|
||||
lprintf("\n%s\n", "PicoDrive v" VERSION " " __DATE__ " " __TIME__);
|
||||
lprintf("running on %08x kernel\n", sceKernelDevkitVersion()),
|
||||
lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id,
|
||||
sceKernelGetThreadCurrentPriority());
|
||||
|
||||
thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, NULL);
|
||||
if (thid >= 0)
|
||||
{
|
||||
sceKernelStartThread(thid, 0, 0);
|
||||
}
|
||||
|
||||
/* video */
|
||||
sceDisplaySetMode(0, 480, 272);
|
||||
sceDisplaySetFrameBuf(VRAM_FB1, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
|
||||
current_screen = 1;
|
||||
psp_screen = VRAM_FB0;
|
||||
|
||||
/* gu */
|
||||
sceGuInit();
|
||||
|
||||
sceGuStart(GU_DIRECT, guCmdList);
|
||||
sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
|
||||
sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
|
||||
sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
|
||||
sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
|
||||
sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2));
|
||||
sceGuViewport(2048, 2048, 480, 272);
|
||||
sceGuDepthRange(0xc350, 0x2710);
|
||||
sceGuScissor(0, 0, 480, 272);
|
||||
sceGuEnable(GU_SCISSOR_TEST);
|
||||
|
||||
sceGuDepthMask(0xffff);
|
||||
sceGuDisable(GU_DEPTH_TEST);
|
||||
|
||||
sceGuFrontFace(GU_CW);
|
||||
sceGuEnable(GU_TEXTURE_2D);
|
||||
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
|
||||
sceGuAmbientColor(0xffffffff);
|
||||
sceGuColor(0xffffffff);
|
||||
sceGuFinish();
|
||||
sceGuSync(0, 0);
|
||||
|
||||
sceDisplayWaitVblankStart();
|
||||
sceGuDisplay(GU_TRUE);
|
||||
|
||||
|
||||
/* input */
|
||||
sceCtrlSetSamplingCycle(0);
|
||||
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
|
||||
}
|
||||
|
||||
void psp_finish(void)
|
||||
{
|
||||
lprintf("psp_finish..\n");
|
||||
sceGuTerm();
|
||||
|
||||
//sceKernelSleepThread();
|
||||
sceKernelExitGame();
|
||||
}
|
||||
|
||||
void psp_video_flip(int wait_vsync)
|
||||
{
|
||||
if (wait_vsync) sceDisplayWaitVblankStart();
|
||||
sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565,
|
||||
wait_vsync ? PSP_DISPLAY_SETBUF_IMMEDIATE : PSP_DISPLAY_SETBUF_NEXTFRAME);
|
||||
current_screen ^= 1;
|
||||
psp_screen = current_screen ? VRAM_FB0 : VRAM_FB1;
|
||||
}
|
||||
|
||||
void *psp_video_get_active_fb(void)
|
||||
{
|
||||
return current_screen ? VRAM_FB1 : VRAM_FB0;
|
||||
}
|
||||
|
||||
void psp_video_switch_to_single(void)
|
||||
{
|
||||
psp_screen = VRAM_FB0;
|
||||
sceDisplaySetFrameBuf(psp_screen, 512, PSP_DISPLAY_PIXEL_FORMAT_565, PSP_DISPLAY_SETBUF_NEXTFRAME);
|
||||
current_screen = 0;
|
||||
}
|
||||
|
||||
void psp_msleep(int ms)
|
||||
{
|
||||
sceKernelDelayThread(ms * 1000);
|
||||
}
|
||||
|
||||
unsigned int psp_pad_read(int blocking)
|
||||
{
|
||||
unsigned int buttons;
|
||||
SceCtrlData pad;
|
||||
if (blocking)
|
||||
sceCtrlReadBufferPositive(&pad, 1);
|
||||
else sceCtrlPeekBufferPositive(&pad, 1);
|
||||
buttons = pad.Buttons;
|
||||
|
||||
// analog..
|
||||
buttons &= ~(PBTN_NUB_UP|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NUB_RIGHT);
|
||||
if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_LEFT;
|
||||
if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_RIGHT;
|
||||
if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_UP;
|
||||
if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_DOWN;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
int psp_get_cpu_clock(void)
|
||||
{
|
||||
return scePowerGetCpuClockFrequencyInt();
|
||||
}
|
||||
|
||||
int psp_set_cpu_clock(int clock)
|
||||
{
|
||||
int ret = scePowerSetClockFrequency(clock, clock, clock/2);
|
||||
if (ret != 0) lprintf("failed to set clock: %i\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *psp_get_status_line(void)
|
||||
{
|
||||
static char buff[64];
|
||||
int ret, bat_percent, bat_time;
|
||||
pspTime time;
|
||||
|
||||
ret = sceRtcGetCurrentClockLocalTime(&time);
|
||||
bat_percent = scePowerGetBatteryLifePercent();
|
||||
bat_time = scePowerGetBatteryLifeTime();
|
||||
if (ret < 0 || bat_percent < 0 || bat_time < 0) return NULL;
|
||||
|
||||
snprintf(buff, sizeof(buff), "%02i:%02i bat: %3i%%", time.hour, time.minutes, bat_percent);
|
||||
if (!scePowerIsPowerOnline())
|
||||
snprintf(buff+strlen(buff), sizeof(buff)-strlen(buff), " (%i:%02i)", bat_time/60, bat_time%60);
|
||||
return buff;
|
||||
}
|
||||
|
||||
void psp_wait_suspend(void)
|
||||
{
|
||||
// probably should do something smarter here?
|
||||
sceDisplayWaitVblankStart();
|
||||
}
|
||||
|
||||
void psp_resume_suspend(void)
|
||||
{
|
||||
// for some reason file IO doesn't seem to work
|
||||
// after resume for some period of time, at least on 1.5
|
||||
SceUID fd;
|
||||
int i;
|
||||
for (i = 0; i < 30; i++) {
|
||||
fd = sceIoOpen("EBOOT.PBP", PSP_O_RDONLY, 0777);
|
||||
if (fd >= 0) break;
|
||||
sceKernelDelayThread(100 * 1024);
|
||||
}
|
||||
if (fd >= 0) sceIoClose(fd);
|
||||
sceDisplayWaitVblankStart();
|
||||
if (i < 30)
|
||||
lprintf("io resumed after %i tries\n", i);
|
||||
else {
|
||||
lprintf("io resume failed with %08x\n", fd);
|
||||
sceKernelDelayThread(500 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
/* alt logging */
|
||||
#define LOG_FILE "log.txt"
|
||||
|
||||
#ifndef LPRINTF_STDIO
|
||||
typedef struct _log_entry
|
||||
{
|
||||
char buff[256];
|
||||
struct _log_entry *next;
|
||||
} log_entry;
|
||||
|
||||
static log_entry *le_root = NULL;
|
||||
#endif
|
||||
|
||||
/* strange: if this function leaks memory (before psp_init() call?),
|
||||
* resume after suspend breaks on 3.90 */
|
||||
void lprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
#ifdef LPRINTF_STDIO
|
||||
va_start(vl, fmt);
|
||||
vprintf(fmt, vl);
|
||||
va_end(vl);
|
||||
#else
|
||||
static SceUID logfd = -1;
|
||||
static int msg_count = 0;
|
||||
char buff[256];
|
||||
log_entry *le, *le1;
|
||||
|
||||
if (logfd == -2) return; // disabled
|
||||
|
||||
va_start(vl, fmt);
|
||||
vsnprintf(buff, sizeof(buff), fmt, vl);
|
||||
va_end(vl);
|
||||
|
||||
// note: this is still unsafe code
|
||||
if (main_thread_id != sceKernelGetThreadId())
|
||||
{
|
||||
le = malloc(sizeof(*le));
|
||||
if (le == NULL) return;
|
||||
le->next = NULL;
|
||||
strcpy(le->buff, buff);
|
||||
if (le_root == NULL) le_root = le;
|
||||
else {
|
||||
for (le1 = le_root; le1->next != NULL; le1 = le1->next);
|
||||
le1->next = le;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
logfd = sceIoOpen(LOG_FILE, PSP_O_WRONLY|PSP_O_APPEND, 0777);
|
||||
if (logfd < 0) {
|
||||
if (msg_count == 0) logfd = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (le_root != NULL)
|
||||
{
|
||||
le1 = le_root;
|
||||
le_root = NULL;
|
||||
sceKernelDelayThread(1000);
|
||||
while (le1 != NULL) {
|
||||
le = le1;
|
||||
le1 = le->next;
|
||||
sceIoWrite(logfd, le->buff, strlen(le->buff));
|
||||
free(le);
|
||||
msg_count++;
|
||||
}
|
||||
}
|
||||
|
||||
sceIoWrite(logfd, buff, strlen(buff));
|
||||
msg_count++;
|
||||
|
||||
// make sure it gets flushed
|
||||
sceIoClose(logfd);
|
||||
logfd = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
70
psp/psp.h
70
psp/psp.h
|
@ -1,70 +0,0 @@
|
|||
// (c) Copyright 2007 notaz, All rights reserved.
|
||||
// Free for non-commercial use.
|
||||
|
||||
// For commercial use, separate licencing terms must be obtained.
|
||||
|
||||
#include <pspctrl.h>
|
||||
|
||||
void psp_init(void);
|
||||
void psp_finish(void);
|
||||
|
||||
void psp_msleep(int ms);
|
||||
|
||||
// vram usage map:
|
||||
// 000000-044000 fb0
|
||||
// 044000-088000 fb1
|
||||
// 088000-0cc000 depth (?)
|
||||
// 0cc000-126000 emu draw buffers: 512*240 + 512*240*2
|
||||
|
||||
#define VRAMOFFS_FB0 0x00000000
|
||||
#define VRAMOFFS_FB1 0x00044000
|
||||
#define VRAMOFFS_DEPTH 0x00088000
|
||||
#define VRAMOFFS_STUFF 0x000cc000
|
||||
|
||||
#define VRAM_FB0 ((void *) (0x44000000+VRAMOFFS_FB0))
|
||||
#define VRAM_FB1 ((void *) (0x44000000+VRAMOFFS_FB1))
|
||||
#define VRAM_STUFF ((void *) (0x44000000+VRAMOFFS_STUFF))
|
||||
|
||||
#define VRAM_CACHED_STUFF ((void *) (0x04000000+VRAMOFFS_STUFF))
|
||||
|
||||
#define GU_CMDLIST_SIZE (16*1024)
|
||||
|
||||
extern unsigned int guCmdList[GU_CMDLIST_SIZE];
|
||||
extern int psp_unhandled_suspend;
|
||||
|
||||
void *psp_video_get_active_fb(void);
|
||||
void psp_video_switch_to_single(void);
|
||||
void psp_video_flip(int wait_vsync);
|
||||
extern void *psp_screen;
|
||||
|
||||
unsigned int psp_pad_read(int blocking);
|
||||
|
||||
int psp_get_cpu_clock(void);
|
||||
int psp_set_cpu_clock(int clock);
|
||||
|
||||
char *psp_get_status_line(void);
|
||||
|
||||
void psp_wait_suspend(void);
|
||||
void psp_resume_suspend(void);
|
||||
|
||||
/* shorter btn names */
|
||||
#define PBTN_UP PSP_CTRL_UP
|
||||
#define PBTN_LEFT PSP_CTRL_LEFT
|
||||
#define PBTN_RIGHT PSP_CTRL_RIGHT
|
||||
#define PBTN_DOWN PSP_CTRL_DOWN
|
||||
#define PBTN_L PSP_CTRL_LTRIGGER
|
||||
#define PBTN_R PSP_CTRL_RTRIGGER
|
||||
#define PBTN_TRIANGLE PSP_CTRL_TRIANGLE
|
||||
#define PBTN_CIRCLE PSP_CTRL_CIRCLE
|
||||
#define PBTN_X PSP_CTRL_CROSS
|
||||
#define PBTN_SQUARE PSP_CTRL_SQUARE
|
||||
#define PBTN_SELECT PSP_CTRL_SELECT
|
||||
#define PBTN_START PSP_CTRL_START
|
||||
#define PBTN_NOTE PSP_CTRL_NOTE // doesn't seem to work?
|
||||
|
||||
/* fake 'nub' btns */
|
||||
#define PBTN_NUB_UP (1 << 28)
|
||||
#define PBTN_NUB_RIGHT (1 << 29)
|
||||
#define PBTN_NUB_DOWN (1 << 30)
|
||||
#define PBTN_NUB_LEFT (1 << 31)
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#define VERSION "1.51b"
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
# settings
|
||||
CROSS=i586-mingw32msvc-
|
||||
|
||||
#use_musashi = 1
|
||||
use_fame = 1
|
||||
use_cz80 = 1
|
||||
use_sh2drc = 1
|
||||
#use_sh2mame = 1
|
||||
|
||||
-include Makefile.local
|
||||
|
||||
ARCH ?= x86
|
||||
CC = $(CROSS)gcc
|
||||
CXX = $(CROSS)g++
|
||||
LD = $(CROSS)ld
|
||||
STRIP = $(CROSS)strip
|
||||
|
||||
DEFINES = _UNZIP_SUPPORT IN_VK
|
||||
CFLAGS += -O2 -Wall -falign-functions=2 -ffast-math
|
||||
CFLAGS += -I../.. -I. -I../../zlib/ -Idirectx/include/
|
||||
LDFLAGS += -mwindows -L. -Ldirectx/lib/ -lgdi32 -lcomdlg32 -lddraw -ldsound -ldxguid
|
||||
|
||||
# frontend
|
||||
OBJS += main.o plat.o direct.o dsnd.o in_vk.o
|
||||
|
||||
# common
|
||||
OBJS += platform/common/emu.o platform/common/menu.o \
|
||||
platform/common/config.o platform/common/fonts.o platform/common/readpng.o \
|
||||
platform/common/input.o
|
||||
|
||||
OBJS += pico/carthw/svp/compiler.o
|
||||
OBJS += pico/sound/mix.o
|
||||
# zlib
|
||||
OBJS += zlib/gzio.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o \
|
||||
zlib/deflate.o zlib/crc32.o zlib/adler32.o zlib/zutil.o zlib/compress.o zlib/uncompr.o
|
||||
# unzip
|
||||
OBJS += unzip/unzip.o unzip/unzip_stream.o
|
||||
|
||||
CFLAGS += $(addprefix -D,$(DEFINES))
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
||||
vpath %.c = ../..
|
||||
|
||||
DIRS += zlib unzip
|
||||
|
||||
TARGET = PicoDrive.exe
|
||||
all: mkdirs $(TARGET)
|
||||
|
||||
include ../common/common.mak
|
||||
include ../common/revision.mak
|
||||
|
||||
clean: tidy
|
||||
@$(RM) $(TARGET)
|
||||
tidy:
|
||||
$(RM) $(OBJS) $(TARGET).map
|
||||
rm -rf $(DIRS)
|
||||
|
||||
$(TARGET) : $(OBJS)
|
||||
@echo ">>>" $@
|
||||
$(CC) $(CFLAGS) $^ $(LDFLAGS) -lm -lpng -Wl,-Map=$(TARGET).map -o $@
|
||||
$(STRIP) $@
|
||||
|
||||
# ----------- release -----------
|
||||
ifneq ($(findstring rel,$(MAKECMDGOALS)),)
|
||||
ifeq ($(VER),)
|
||||
$(error need VER)
|
||||
endif
|
||||
endif
|
||||
|
||||
rel: $(TARGET) readme.txt carthw.cfg
|
||||
zip -9 -j ../../PicoDrive_win32_$(VER).zip $^
|
||||
|
635
win32/main.c
635
win32/main.c
|
@ -1,635 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../pico/pico.h"
|
||||
#include "../common/readpng.h"
|
||||
#include "../common/config.h"
|
||||
#include "../common/lprintf.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../common/menu.h"
|
||||
#include "../common/input.h"
|
||||
#include "../common/plat.h"
|
||||
#include "version.h"
|
||||
#include "direct.h"
|
||||
#include "in_vk.h"
|
||||
|
||||
char *romname=NULL;
|
||||
HWND FrameWnd=NULL;
|
||||
RECT FrameRectMy;
|
||||
RECT EmuScreenRect = { 0, 0, 320, 224 };
|
||||
int lock_to_1_1 = 1;
|
||||
static HWND PicoSwWnd=NULL, PicoPadWnd=NULL;
|
||||
|
||||
static HMENU mmain = 0, mdisplay = 0, mpicohw = 0;
|
||||
static HBITMAP ppad_bmp = 0;
|
||||
static HBITMAP ppage_bmps[7] = { 0, };
|
||||
static char rom_name[0x20*3+1];
|
||||
static int main_wnd_as_pad = 0;
|
||||
|
||||
static HANDLE loop_enter_event, loop_end_event;
|
||||
|
||||
void error(char *text)
|
||||
{
|
||||
MessageBox(FrameWnd, text, "Error", 0);
|
||||
}
|
||||
|
||||
static void UpdateRect(void)
|
||||
{
|
||||
WINDOWINFO wi;
|
||||
memset(&wi, 0, sizeof(wi));
|
||||
wi.cbSize = sizeof(wi);
|
||||
GetWindowInfo(FrameWnd, &wi);
|
||||
FrameRectMy = wi.rcClient;
|
||||
}
|
||||
|
||||
static int extract_rom_name(char *dest, const unsigned char *src, int len)
|
||||
{
|
||||
char *p = dest, s_old = 0x20;
|
||||
int i;
|
||||
|
||||
for (i = len - 1; i >= 0; i--)
|
||||
{
|
||||
if (src[i^1] != ' ') break;
|
||||
}
|
||||
len = i + 1;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
unsigned char s = src[i^1];
|
||||
if (s == 0x20 && s_old == 0x20) continue;
|
||||
else if (s >= 0x20 && s < 0x7f && s != '%')
|
||||
{
|
||||
*p++ = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(p, "%%%02x", s);
|
||||
p += 3;
|
||||
}
|
||||
s_old = s;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
static void check_name_alias(const char *afname)
|
||||
{
|
||||
char buff[256], *var, *val;
|
||||
FILE *f;
|
||||
int ret;
|
||||
|
||||
f = fopen(afname, "r");
|
||||
if (f == NULL) return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = config_get_var_val(f, buff, sizeof(buff), &var, &val);
|
||||
if (ret == 0) break;
|
||||
if (ret == -1) continue;
|
||||
|
||||
if (strcmp(rom_name, var) == 0) {
|
||||
lprintf("rom aliased: \"%s\" -> \"%s\"\n", rom_name, val);
|
||||
strncpy(rom_name, val, sizeof(rom_name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static HBITMAP png2hb(const char *fname, int is_480)
|
||||
{
|
||||
BITMAPINFOHEADER bih;
|
||||
HBITMAP bmp;
|
||||
void *bmem;
|
||||
int ret;
|
||||
|
||||
bmem = calloc(1, is_480 ? 480*240*3 : 320*240*3);
|
||||
if (bmem == NULL) return NULL;
|
||||
ret = readpng(bmem, fname, READPNG_24, is_480 ? 480 : 320, 240);
|
||||
if (ret != 0) {
|
||||
free(bmem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&bih, 0, sizeof(bih));
|
||||
bih.biSize = sizeof(bih);
|
||||
bih.biWidth = is_480 ? 480 : 320;
|
||||
bih.biHeight = -240;
|
||||
bih.biPlanes = 1;
|
||||
bih.biBitCount = 24;
|
||||
bih.biCompression = BI_RGB;
|
||||
bmp = CreateDIBitmap(GetDC(FrameWnd), &bih, CBM_INIT, bmem, (BITMAPINFO *)&bih, 0);
|
||||
if (bmp == NULL)
|
||||
lprintf("CreateDIBitmap failed with %i", GetLastError());
|
||||
|
||||
free(bmem);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
static void PrepareForROM(void)
|
||||
{
|
||||
unsigned char *rom_data = NULL;
|
||||
int i, ret, show = PicoAHW & PAHW_PICO;
|
||||
|
||||
PicoGetInternal(PI_ROM, (pint_ret_t *) &rom_data);
|
||||
EnableMenuItem(mmain, 2, MF_BYPOSITION|(show ? MF_ENABLED : MF_GRAYED));
|
||||
ShowWindow(PicoPadWnd, show ? SW_SHOWNA : SW_HIDE);
|
||||
ShowWindow(PicoSwWnd, show ? SW_SHOWNA : SW_HIDE);
|
||||
CheckMenuItem(mpicohw, 1210, show ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(mpicohw, 1211, show ? MF_CHECKED : MF_UNCHECKED);
|
||||
PostMessage(FrameWnd, WM_COMMAND, 1220 + PicoPicohw.page, 0);
|
||||
DrawMenuBar(FrameWnd);
|
||||
InvalidateRect(PicoSwWnd, NULL, 1);
|
||||
|
||||
PicoPicohw.pen_pos[0] =
|
||||
PicoPicohw.pen_pos[1] = 0x8000;
|
||||
in_vk_add_pl12 = 0;
|
||||
|
||||
ret = extract_rom_name(rom_name, rom_data + 0x150, 0x20);
|
||||
if (ret == 0)
|
||||
extract_rom_name(rom_name, rom_data + 0x130, 0x20);
|
||||
|
||||
if (show)
|
||||
{
|
||||
char path[MAX_PATH], *p;
|
||||
GetModuleFileName(NULL, path, sizeof(path) - 32);
|
||||
p = strrchr(path, '\\');
|
||||
if (p == NULL) p = path;
|
||||
else p++;
|
||||
if (ppad_bmp == NULL) {
|
||||
strcpy(p, "pico\\pad.png");
|
||||
ppad_bmp = png2hb(path, 0);
|
||||
}
|
||||
|
||||
strcpy(p, "pico\\alias.txt");
|
||||
check_name_alias(path);
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (ppage_bmps[i] != NULL) DeleteObject(ppage_bmps[i]);
|
||||
sprintf(p, "pico\\%s_%i.png", rom_name, i);
|
||||
ppage_bmps[i] = png2hb(path, 1);
|
||||
}
|
||||
// games usually don't have page 6, so just duplicate page 5.
|
||||
if (ppage_bmps[6] == NULL && ppage_bmps[5] != NULL) {
|
||||
sprintf(p, "pico\\%s_5.png", rom_name);
|
||||
ppage_bmps[6] = png2hb(path, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadROM(const char *cmdpath)
|
||||
{
|
||||
char rompath[MAX_PATH];
|
||||
int ret;
|
||||
|
||||
if (cmdpath != NULL && strlen(cmdpath)) {
|
||||
strcpy(rompath, cmdpath + (cmdpath[0] == '\"' ? 1 : 0));
|
||||
if (rompath[strlen(rompath)-1] == '\"')
|
||||
rompath[strlen(rompath)-1] = 0;
|
||||
}
|
||||
else {
|
||||
OPENFILENAME of; ZeroMemory(&of, sizeof(of));
|
||||
rompath[sizeof(rompath) - 1] = 0;
|
||||
strncpy(rompath, rom_fname_loaded, sizeof(rompath) - 1);
|
||||
of.lStructSize = sizeof(of);
|
||||
of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue\0"
|
||||
"whatever\0*.*\0";
|
||||
of.lpstrFile = rompath;
|
||||
of.nMaxFile = MAX_PATH;
|
||||
of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
||||
of.hwndOwner = FrameWnd;
|
||||
if (!GetOpenFileName(&of))
|
||||
return;
|
||||
}
|
||||
|
||||
if (engineState == PGS_Running) {
|
||||
engineState = PGS_Paused;
|
||||
WaitForSingleObject(loop_end_event, 5000);
|
||||
}
|
||||
|
||||
ret = emu_reload_rom(rompath);
|
||||
if (ret == 0) {
|
||||
extern char menu_error_msg[]; // HACK..
|
||||
error(menu_error_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareForROM();
|
||||
engineState = PGS_Running;
|
||||
SetEvent(loop_enter_event);
|
||||
}
|
||||
|
||||
static const int rect_widths[4] = { 320, 256, 640, 512 };
|
||||
static const int rect_heights[4] = { 224, 224, 448, 448 };
|
||||
|
||||
// Window proc for the frame window:
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||
{
|
||||
POINT pt;
|
||||
RECT rc;
|
||||
int i;
|
||||
switch (msg)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_DESTROY:
|
||||
FrameWnd = NULL; // Blank the handle
|
||||
break;
|
||||
case WM_SIZE:
|
||||
case WM_MOVE:
|
||||
case WM_SIZING:
|
||||
UpdateRect();
|
||||
if (lock_to_1_1 && FrameRectMy.right - FrameRectMy.left != 0 &&
|
||||
(FrameRectMy.right - FrameRectMy.left != EmuScreenRect.right - EmuScreenRect.left ||
|
||||
FrameRectMy.bottom - FrameRectMy.top != EmuScreenRect.bottom - EmuScreenRect.top)) {
|
||||
lock_to_1_1 = 0;
|
||||
CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wparam))
|
||||
{
|
||||
case 1000:
|
||||
LoadROM(NULL);
|
||||
break;
|
||||
case 1001:
|
||||
emu_reset_game();
|
||||
return 0;
|
||||
case 1002:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case 1100:
|
||||
case 1101:
|
||||
case 1102:
|
||||
case 1103:
|
||||
// LoopWait=1; // another sync hack
|
||||
// for (i = 0; !LoopWaiting && i < 10; i++) Sleep(10);
|
||||
FrameRectMy.right = FrameRectMy.left + rect_widths[wparam&3];
|
||||
FrameRectMy.bottom = FrameRectMy.top + rect_heights[wparam&3];
|
||||
AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
|
||||
MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
|
||||
FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
|
||||
UpdateRect();
|
||||
lock_to_1_1 = 0;
|
||||
CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
|
||||
// if (rom_loaded) LoopWait=0;
|
||||
return 0;
|
||||
case 1104:
|
||||
lock_to_1_1 = !lock_to_1_1;
|
||||
CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
|
||||
/* FALLTHROUGH */
|
||||
case 2000: // EmuScreenRect/FrameRectMy sync request
|
||||
if (!lock_to_1_1)
|
||||
return 0;
|
||||
FrameRectMy.right = FrameRectMy.left + (EmuScreenRect.right - EmuScreenRect.left);
|
||||
FrameRectMy.bottom = FrameRectMy.top + (EmuScreenRect.bottom - EmuScreenRect.top);
|
||||
AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
|
||||
MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
|
||||
FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
|
||||
UpdateRect();
|
||||
return 0;
|
||||
case 1210:
|
||||
case 1211:
|
||||
i = IsWindowVisible((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd);
|
||||
i = !i;
|
||||
ShowWindow((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd, i ? SW_SHOWNA : SW_HIDE);
|
||||
CheckMenuItem(mpicohw, LOWORD(wparam), i ? MF_CHECKED : MF_UNCHECKED);
|
||||
return 0;
|
||||
case 1212:
|
||||
main_wnd_as_pad = !main_wnd_as_pad;
|
||||
CheckMenuItem(mpicohw, 1212, main_wnd_as_pad ? MF_CHECKED : MF_UNCHECKED);
|
||||
return 0;
|
||||
case 1220:
|
||||
case 1221:
|
||||
case 1222:
|
||||
case 1223:
|
||||
case 1224:
|
||||
case 1225:
|
||||
case 1226:
|
||||
PicoPicohw.page = LOWORD(wparam) % 10;
|
||||
for (i = 0; i < 7; i++)
|
||||
CheckMenuItem(mpicohw, 1220 + i, MF_UNCHECKED);
|
||||
CheckMenuItem(mpicohw, 1220 + PicoPicohw.page, MF_CHECKED);
|
||||
InvalidateRect(PicoSwWnd, NULL, 1);
|
||||
return 0;
|
||||
case 1300:
|
||||
MessageBox(FrameWnd, plat_get_credits(), "About", 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
GetCursorPos(&pt);
|
||||
GetWindowRect(PicoSwWnd, &rc);
|
||||
if (PtInRect(&rc, pt)) break;
|
||||
GetWindowRect(PicoPadWnd, &rc);
|
||||
if (PtInRect(&rc, pt)) break;
|
||||
PicoPicohw.pen_pos[0] |= 0x8000;
|
||||
PicoPicohw.pen_pos[1] |= 0x8000;
|
||||
in_vk_add_pl12 = 0;
|
||||
break;
|
||||
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||
case WM_MOUSEMOVE:
|
||||
if (!main_wnd_as_pad) break;
|
||||
PicoPicohw.pen_pos[0] = 0x03c + (320 * LOWORD(lparam) / (FrameRectMy.right - FrameRectMy.left));
|
||||
PicoPicohw.pen_pos[1] = 0x1fc + (232 * HIWORD(lparam) / (FrameRectMy.bottom - FrameRectMy.top));
|
||||
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
if (wparam == VK_TAB) {
|
||||
emu_reset_game();
|
||||
break;
|
||||
}
|
||||
if (wparam == VK_ESCAPE) {
|
||||
LoadROM(NULL);
|
||||
break;
|
||||
}
|
||||
in_vk_keydown(wparam);
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
in_vk_keyup(wparam);
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK PicoSwWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc, hdc2;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DESTROY: PicoSwWnd=NULL; break;
|
||||
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||
case WM_MOUSEMOVE:
|
||||
if (HIWORD(lparam) < 0x20) break;
|
||||
PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam) * 2/3;
|
||||
PicoPicohw.pen_pos[1] = 0x2f8 + HIWORD(lparam) - 0x20;
|
||||
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||
break;
|
||||
case WM_KEYDOWN: in_vk_keydown(wparam); break;
|
||||
case WM_KEYUP: in_vk_keyup(wparam); break;
|
||||
case WM_PAINT:
|
||||
hdc = BeginPaint(hwnd, &ps);
|
||||
if (ppage_bmps[PicoPicohw.page] == NULL)
|
||||
{
|
||||
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
|
||||
SetTextColor(hdc, RGB(255, 255, 255));
|
||||
SetBkColor(hdc, RGB(0, 0, 0));
|
||||
TextOut(hdc, 2, 2, "missing PNGs for", 16);
|
||||
TextOut(hdc, 2, 18, rom_name, strlen(rom_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
|
||||
SelectObject(hdc2, ppage_bmps[PicoPicohw.page]);
|
||||
BitBlt(hdc, 0, 0, 480, 240, hdc2, 0, 0, SRCCOPY);
|
||||
DeleteDC(hdc2);
|
||||
}
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
case WM_CLOSE:
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
CheckMenuItem(mpicohw, 1210, MF_UNCHECKED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK PicoPadWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc, hdc2;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DESTROY: PicoPadWnd=NULL; break;
|
||||
case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
|
||||
case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
|
||||
case WM_MOUSEMOVE:
|
||||
PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam);
|
||||
PicoPicohw.pen_pos[1] = 0x1fc + HIWORD(lparam);
|
||||
SetTimer(FrameWnd, 100, 1000, NULL);
|
||||
break;
|
||||
case WM_KEYDOWN: in_vk_keydown(wparam); break;
|
||||
case WM_KEYUP: in_vk_keyup(wparam); break;
|
||||
case WM_PAINT:
|
||||
if (ppad_bmp == NULL) break;
|
||||
hdc = BeginPaint(hwnd, &ps);
|
||||
hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
|
||||
SelectObject(hdc2, ppad_bmp);
|
||||
BitBlt(hdc, 0, 0, 320, 240, hdc2, 0, 0, SRCCOPY);
|
||||
EndPaint(hwnd, &ps);
|
||||
DeleteDC(hdc2);
|
||||
return 0;
|
||||
case WM_CLOSE:
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
CheckMenuItem(mpicohw, 1211, MF_UNCHECKED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,msg,wparam,lparam);
|
||||
}
|
||||
|
||||
|
||||
static int FrameInit()
|
||||
{
|
||||
WNDCLASS wc;
|
||||
RECT rect={0,0,0,0};
|
||||
HMENU mfile;
|
||||
int style=0;
|
||||
int left=0,top=0,width=0,height=0;
|
||||
|
||||
memset(&wc,0,sizeof(wc));
|
||||
|
||||
// Register the window class:
|
||||
wc.lpfnWndProc=WndProc;
|
||||
wc.hInstance=GetModuleHandle(NULL);
|
||||
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
|
||||
wc.hbrBackground=CreateSolidBrush(0);
|
||||
wc.lpszClassName="PicoMainFrame";
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.lpszClassName="PicoSwWnd";
|
||||
wc.lpfnWndProc=PicoSwWndProc;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.lpszClassName="PicoPadWnd";
|
||||
wc.lpfnWndProc=PicoPadWndProc;
|
||||
RegisterClass(&wc);
|
||||
|
||||
rect.right =320;
|
||||
rect.bottom=224;
|
||||
|
||||
// Adjust size of windows based on borders:
|
||||
style=WS_OVERLAPPEDWINDOW;
|
||||
AdjustWindowRect(&rect,style,1);
|
||||
width =rect.right-rect.left;
|
||||
height=rect.bottom-rect.top;
|
||||
|
||||
// Place window in the centre of the screen:
|
||||
SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
|
||||
left=rect.left+rect.right;
|
||||
top=rect.top+rect.bottom;
|
||||
|
||||
left-=width; left>>=1;
|
||||
top-=height; top>>=1;
|
||||
|
||||
// Create menu:
|
||||
mfile = CreateMenu();
|
||||
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1000, "&Load ROM");
|
||||
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1001, "&Reset");
|
||||
InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1002, "E&xit");
|
||||
mdisplay = CreateMenu();
|
||||
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1100, "320x224");
|
||||
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1101, "256x224");
|
||||
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1102, "640x448");
|
||||
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1103, "512x448");
|
||||
InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1104, "Lock to 1:1");
|
||||
mpicohw = CreateMenu();
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1210, "Show &Storyware");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1211, "Show &Drawing pad");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1212, "&Main window as pad");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1220, "Title page (&0)");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1221, "Page &1");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1222, "Page &2");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1223, "Page &3");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1224, "Page &4");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1225, "Page &5");
|
||||
InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1226, "Page &6");
|
||||
mmain = CreateMenu();
|
||||
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mfile, "&File");
|
||||
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mdisplay, "&Display");
|
||||
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mpicohw, "&Pico");
|
||||
EnableMenuItem(mmain, 2, MF_BYPOSITION|MF_GRAYED);
|
||||
// InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, 1200, "&Config");
|
||||
InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING, 1300, "&About");
|
||||
|
||||
// Create the window:
|
||||
FrameWnd=CreateWindow("PicoMainFrame","PicoDrive " VERSION,style|WS_VISIBLE,
|
||||
left,top,width,height,NULL,mmain,NULL,NULL);
|
||||
|
||||
CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
|
||||
ShowWindow(FrameWnd, SW_NORMAL);
|
||||
UpdateWindow(FrameWnd);
|
||||
UpdateRect();
|
||||
|
||||
// create Pico windows
|
||||
style = WS_OVERLAPPED|WS_CAPTION|WS_BORDER|WS_SYSMENU;
|
||||
rect.left=rect.top=0;
|
||||
rect.right =320;
|
||||
rect.bottom=224;
|
||||
|
||||
AdjustWindowRect(&rect,style,1);
|
||||
width =rect.right-rect.left;
|
||||
height=rect.bottom-rect.top;
|
||||
|
||||
left += 326;
|
||||
PicoSwWnd=CreateWindow("PicoSwWnd","Storyware",style,
|
||||
left,top,width+160,height,FrameWnd,NULL,NULL,NULL);
|
||||
|
||||
top += 266;
|
||||
PicoPadWnd=CreateWindow("PicoPadWnd","Drawing Pad",style,
|
||||
left,top,width,height,FrameWnd,NULL,NULL,NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --------------------
|
||||
|
||||
static DWORD WINAPI work_thread(void *x)
|
||||
{
|
||||
while (engineState != PGS_Quit) {
|
||||
WaitForSingleObject(loop_enter_event, INFINITE);
|
||||
if (engineState != PGS_Running)
|
||||
continue;
|
||||
|
||||
printf("loop..\n");
|
||||
emu_loop();
|
||||
SetEvent(loop_end_event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// XXX: use main.c
|
||||
void xxinit(void)
|
||||
{
|
||||
/* in_init() must go before config, config accesses in_ fwk */
|
||||
in_init();
|
||||
emu_prep_defconfig();
|
||||
emu_read_config(NULL, 0);
|
||||
config_readlrom(PicoConfigFile);
|
||||
|
||||
plat_init();
|
||||
in_probe();
|
||||
|
||||
emu_init();
|
||||
menu_init();
|
||||
}
|
||||
|
||||
|
||||
int WINAPI WinMain(HINSTANCE p1, HINSTANCE p2, LPSTR cmdline, int p4)
|
||||
{
|
||||
MSG msg;
|
||||
DWORD tid = 0;
|
||||
HANDLE thread;
|
||||
int ret;
|
||||
|
||||
xxinit();
|
||||
FrameInit();
|
||||
ret = DirectInit();
|
||||
if (ret)
|
||||
goto end0;
|
||||
|
||||
loop_enter_event = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (loop_enter_event == NULL)
|
||||
goto end0;
|
||||
|
||||
loop_end_event = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (loop_end_event == NULL)
|
||||
goto end0;
|
||||
|
||||
thread = CreateThread(NULL, 0, work_thread, NULL, 0, &tid);
|
||||
if (thread == NULL)
|
||||
goto end0;
|
||||
|
||||
LoadROM(cmdline);
|
||||
|
||||
// Main window loop:
|
||||
for (;;)
|
||||
{
|
||||
GetMessage(&msg,NULL,0,0);
|
||||
if (msg.message==WM_QUIT) break;
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
// Signal thread to quit and wait for it to exit:
|
||||
if (engineState == PGS_Running) {
|
||||
engineState = PGS_Quit;
|
||||
WaitForSingleObject(loop_end_event, 5000);
|
||||
}
|
||||
CloseHandle(thread); thread=NULL;
|
||||
|
||||
emu_write_config(0);
|
||||
emu_finish();
|
||||
//plat_finish();
|
||||
|
||||
end0:
|
||||
DirectExit();
|
||||
DestroyWindow(FrameWnd);
|
||||
|
||||
// _CrtDumpMemoryLeaks();
|
||||
return 0;
|
||||
}
|
||||
|
11
win32/main.h
11
win32/main.h
|
@ -1,11 +0,0 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern HWND FrameWnd;
|
||||
extern RECT FrameRectMy;
|
||||
extern RECT EmuScreenRect;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
249
win32/plat.c
249
win32/plat.c
|
@ -1,249 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../common/lprintf.h"
|
||||
#include "../common/plat.h"
|
||||
#include "../common/emu.h"
|
||||
#include "../../pico/pico.h"
|
||||
#include "version.h"
|
||||
#include "direct.h"
|
||||
#include "dsnd.h"
|
||||
#include "main.h"
|
||||
|
||||
static unsigned short screen_buff[320 * 240];
|
||||
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
|
||||
unsigned char *PicoDraw2FB = PicoDraw2FB_;
|
||||
const char *renderer_names[] = { NULL };
|
||||
const char *renderer_names32x[] = { NULL };
|
||||
|
||||
void plat_init(void)
|
||||
{
|
||||
g_screen_ptr = (void *)screen_buff;
|
||||
}
|
||||
|
||||
int plat_is_dir(const char *path)
|
||||
{
|
||||
return (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int plat_get_ticks_ms(void)
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
unsigned int plat_get_ticks_us(void)
|
||||
{
|
||||
// XXX: maybe performance counters?
|
||||
return GetTickCount() * 1000;
|
||||
}
|
||||
|
||||
void plat_wait_till_us(unsigned int us)
|
||||
{
|
||||
int msdiff = (int)(us - plat_get_ticks_us()) / 1000;
|
||||
if (msdiff > 6)
|
||||
Sleep(msdiff - 6);
|
||||
while (plat_get_ticks_us() < us)
|
||||
;
|
||||
}
|
||||
|
||||
void plat_sleep_ms(int ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
int plat_wait_event(int *fds_hnds, int count, int timeout_ms)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pemu_prep_defconfig(void)
|
||||
{
|
||||
memset(&defaultConfig, 0, sizeof(defaultConfig));
|
||||
defaultConfig.s_PicoOpt|= POPT_6BTN_PAD; // for xmen proto
|
||||
defaultConfig.s_PicoCDBuffers = 0;
|
||||
defaultConfig.Frameskip = 0;
|
||||
}
|
||||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
}
|
||||
|
||||
void pemu_loop_prep(void)
|
||||
{
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
PicoDrawSetOutBuf(g_screen_ptr, g_screen_width * 2);
|
||||
pemu_sound_start();
|
||||
}
|
||||
|
||||
void pemu_loop_end(void)
|
||||
{
|
||||
pemu_sound_stop();
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
}
|
||||
|
||||
void pemu_finalize_frame(const char *fps, const char *notice_msg)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_flip(void)
|
||||
{
|
||||
DirectScreen(g_screen_ptr);
|
||||
DirectPresent();
|
||||
}
|
||||
|
||||
void plat_video_wait_vsync(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_toggle_renderer(int change, int is_menu)
|
||||
{
|
||||
// this will auto-select SMS/32X renderers
|
||||
PicoDrawSetOutFormat(PDF_RGB555, 1);
|
||||
}
|
||||
|
||||
void emu_video_mode_change(int start_line, int line_count, int is_32cols)
|
||||
{
|
||||
EmuScreenRect.left = is_32cols ? 32 : 0;
|
||||
EmuScreenRect.right = is_32cols ? 256+32 : 320;
|
||||
EmuScreenRect.top = start_line;
|
||||
EmuScreenRect.bottom = start_line + line_count;
|
||||
|
||||
PostMessage(FrameWnd, WM_COMMAND, 0x20000 | 2000, 0);
|
||||
}
|
||||
|
||||
static int sndbuff[2*44100/50/2 + 4];
|
||||
|
||||
static void update_sound(int len)
|
||||
{
|
||||
/* avoid writing audio when lagging behind to prevent audio lag */
|
||||
if (PicoSkipFrame != 2)
|
||||
DSoundUpdate(sndbuff, (currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) ? 0 : 1);
|
||||
}
|
||||
|
||||
void pemu_sound_start(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
PsndOut = NULL;
|
||||
currentConfig.EmuOpt &= ~EOPT_EXT_FRMLIMIT;
|
||||
|
||||
// prepare sound stuff
|
||||
if (currentConfig.EmuOpt & EOPT_EN_SOUND)
|
||||
{
|
||||
PsndRerate(0);
|
||||
|
||||
ret = DSoundInit(FrameWnd, PsndRate, (PicoOpt & POPT_EN_STEREO) ? 1 : 0, PsndLen);
|
||||
if (ret != 0) {
|
||||
lprintf("dsound init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PsndOut = (void *)sndbuff;
|
||||
PicoWriteSound = update_sound;
|
||||
currentConfig.EmuOpt |= EOPT_EXT_FRMLIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
void pemu_sound_stop(void)
|
||||
{
|
||||
DSoundExit();
|
||||
}
|
||||
|
||||
void pemu_sound_wait(void)
|
||||
{
|
||||
}
|
||||
|
||||
int plat_get_root_dir(char *dst, int len)
|
||||
{
|
||||
int ml;
|
||||
|
||||
ml = GetModuleFileName(NULL, dst, len);
|
||||
while (ml > 0 && dst[ml] != '\\')
|
||||
ml--;
|
||||
if (ml != 0)
|
||||
ml++;
|
||||
|
||||
dst[ml] = 0;
|
||||
return ml;
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_first(const char *msg)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_status_msg_busy_next(const char *msg)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_status_msg_clear(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_enter(int is_rom_loaded)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_begin(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_video_menu_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_update_volume(int has_changed, int is_up)
|
||||
{
|
||||
}
|
||||
|
||||
const char *plat_get_credits(void)
|
||||
{
|
||||
return "PicoDrive v" VERSION " minibeta (c) notaz, 2006-2009\n\n"
|
||||
"Credits:\n"
|
||||
"fDave: base code of PicoDrive\n"
|
||||
"Chui: Fame/C\n"
|
||||
"NJ: CZ80\n"
|
||||
"MAME devs: YM2612, SN76496 and SH2 cores\n"
|
||||
"Stéphane Dallongeville: base of Fame/C (C68K), CZ80\n\n"
|
||||
"Special thanks (ideas, valuable information and stuff):\n"
|
||||
"Charles MacDonald, Eke, Exophase, Haze, Lordus, Nemesis,\n"
|
||||
"Pierpaolo Prazzoli, Rokas, Steve Snake, Tasco Deluxe.\n";
|
||||
}
|
||||
|
||||
void plat_debug_cat(char *str)
|
||||
{
|
||||
}
|
||||
|
||||
// required by pico
|
||||
int mp3_get_bitrate(void *f, int size)
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
void mp3_start_play(void *f, int pos)
|
||||
{
|
||||
}
|
||||
|
||||
void mp3_update(int *buffer, int length, int stereo)
|
||||
{
|
||||
}
|
||||
|
||||
// other
|
||||
void lprintf(const char *fmt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list val;
|
||||
|
||||
va_start(val, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, val);
|
||||
va_end(val);
|
||||
OutputDebugString(buf);
|
||||
printf("%s", buf);
|
||||
}
|
||||
|
||||
// fake
|
||||
int alphasort() { return 0; }
|
||||
int scandir() { return 0; }
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// port specific settings
|
||||
|
||||
#ifndef PORT_CONFIG_H
|
||||
#define PORT_CONFIG_H
|
||||
|
||||
#define NO_SYNC
|
||||
|
||||
#define CASE_SENSITIVE_FS 0 // CS filesystem
|
||||
#define DONT_OPEN_MANY_FILES 0
|
||||
#define REDUCE_IO_CALLS 0
|
||||
|
||||
#define SCREEN_SIZE_FIXED 0
|
||||
#define SCREEN_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define MSCREEN_SIZE_FIXED 0
|
||||
#define MSCREEN_WIDTH SCREEN_WIDTH
|
||||
#define MSCREEN_HEIGHT SCREEN_HEIGHT
|
||||
|
||||
// draw2.c
|
||||
#define START_ROW 0 // which row of tiles to start rendering at?
|
||||
#define END_ROW 28 // ..end
|
||||
|
||||
// pico.c
|
||||
#define CAN_HANDLE_240_LINES 1
|
||||
|
||||
#define SIMPLE_WRITE_SOUND 1
|
||||
#define mix_32_to_16l_stereo_lvl mix_32_to_16l_stereo
|
||||
|
||||
#define EL_LOGMASK (EL_STATUS)
|
||||
|
||||
//#define dprintf(f,...) printf("%05i:%03i: " f "\n",Pico.m.frame_count,Pico.m.scanline,##__VA_ARGS__)
|
||||
#define dprintf(x...)
|
||||
|
||||
// platform
|
||||
#define PATH_SEP "\\"
|
||||
#define PATH_SEP_C '\\'
|
||||
#define MENU_X2 0
|
||||
|
||||
#endif //PORT_CONFIG_H
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
|
||||
About
|
||||
-----
|
||||
|
||||
This is a quick windows port of PicoDrive, a Megadrive / Genesis emulator for
|
||||
handheld devices. It was originally coded having ARM CPU based devices in mind
|
||||
(most work was done on GP2X version), but there is also a PSP port.
|
||||
|
||||
The reason I'm sometimes doing windows versions is to show certain emulation
|
||||
possibilities, first release was to demonstrate SVP emulation (Virtua Racing),
|
||||
later Pico toy and X-Men 32X prototype. It is not to compete with other
|
||||
emulators like Kega Fusion and the likes.
|
||||
|
||||
For more info, visit http://notaz.gp2x.de/svp.php
|
||||
|
||||
|
||||
Releases
|
||||
--------
|
||||
|
||||
1.70 - preliminary 32X emulation, runs X-Men proto.
|
||||
1.45a - Few bugfixes and additions.
|
||||
1.45 - Added preliminary Sega Pico emulation.
|
||||
1.40b - Perspective fix thanks to Pierpaolo Prazzoli's info.
|
||||
1.40a - Tasco Deluxe's dithering fix.
|
||||
1.40 - first release.
|
||||
|
||||
|
||||
Controls
|
||||
--------
|
||||
|
||||
These are currently hardcoded, keyboard only:
|
||||
|
||||
PC Gen/MD Sega Pico
|
||||
-------+-----------+---------
|
||||
Enter: Start
|
||||
A: A
|
||||
S: B red button
|
||||
D: C pen push
|
||||
Q,W,E: X,Y,Z
|
||||
TAB: (reset)
|
||||
Esc: (load ROM)
|
||||
Arrows: D-pad
|
||||
|
||||
It is possible to change some things in config.cfg (it is created on exit),
|
||||
but possibilities are limited.
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
Vast majority of code written by notaz (notasasatgmailcom).
|
||||
|
||||
A lot of work on making SVP emulation happen was done by Tasco Deluxe, my
|
||||
stuff is a continuation of his. Pierpaolo Prazzoli's information and his
|
||||
SSP1610 disassembler in MAME code helped a lot too.
|
||||
|
||||
The original PicoDrive was written by fDave from finalburn.com
|
||||
|
||||
This PicoDrive version uses bits and pieces of from other projects:
|
||||
|
||||
68k: FAME/C core, by Chui and Stéphane Dallongeville (as C68K).
|
||||
z80: CZ80 by Stéphane Dallongeville and modified by NJ.
|
||||
YM2612, SN76496 and SH2 cores: MAME devs.
|
||||
|
||||
Special thanks (ideas, valuable information and stuff):
|
||||
Charles MacDonald, Eke, Exophase, Haze, Lordus, Nemesis,
|
||||
Pierpaolo Prazzoli, Rokas, Steve Snake, Tasco Deluxe.
|
||||
|
||||
Greets to all the sceners and emu authors out there!
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#define VERSION "1.70"
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue