diff --git a/.gitignore b/.gitignore index e0292b1..d3399f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o *.a +*.so diff --git a/Makefile.common b/Makefile.common index f493168..9ee013b 100644 --- a/Makefile.common +++ b/Makefile.common @@ -3,11 +3,7 @@ INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(LIBRETRO_COMM_DIR)/include - COREDEFINES = -D__LIBRETRO__ -DSOUND_QUALITY=0 -DPATH_MAX=1024 -DFCEU_VERSION_NUMERIC=9813 -DFRONTEND_SUPPORTS_RGB565 INCLUDE_STDINT = 0 -ifneq (,$(findstring msvc2003,$(platform))) -INCLUDE_STDINT = 1 -endif - -ifneq (,$(findstring msvc2005,$(platform))) +ifneq (,$(findstring msvc200,$(platform))) INCLUDE_STDINT = 1 endif @@ -17,8 +13,6 @@ endif ifneq (,$(findstring msvc,$(platform))) COREDEFINES += -DINLINE=_inline -else -COREDEFINES += -DINLINE=inline endif ifeq ($(PSS_STYLE),2) diff --git a/Makefile.libretro b/Makefile.libretro index c37b154..140b874 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -4,6 +4,7 @@ EXTERNAL_ZLIB=0 HAVE_GRIFFIN=1 STATIC_LINKING=0 ENDIANNESS_DEFINES= +SIGNED_CHAR=0 SPACE := SPACE := $(SPACE) $(SPACE) @@ -13,6 +14,7 @@ filter_out1 = $(filter-out $(firstword $1),$1) filter_out2 = $(call filter_out1,$(call filter_out1,$1)) unixpath = $(subst \,/,$1) unixcygpath = /$(subst :,,$(call unixpath,$1)) +RETROARCH_OBJECTS := ifeq ($(platform),) platform = unix @@ -154,6 +156,21 @@ else ifeq ($(platform), sncps3) STATIC_LINKING=1 EXTERNAL_ZLIB=1 +# PS2 +else ifeq ($(platform), ps2) + TARGET := $(TARGET_NAME)_libretro_$(platform).a + CC = ee-gcc$(EXE_EXT) + AR = ee-ar$(EXE_EXT) + FCEU_DEFINES := -DPATH_MAX=1024 -DINLINE=inline -DPSS_STYLE=1 -DFCEU_VERSION_NUMERIC=9813 -DHAVE_ASPRINTF + ENDIANNESS_DEFINES := -DLSB_FIRST -DLOCAL_LE=1 + PLATFORM_DEFINES := -DPS2 -G0 -DFRONTEND_SUPPORTS_ABGR1555 -DRENDER_GSKIT_PS2 + PLATFORM_DEFINES += -Dmemcpy=mips_memcpy -Dmemset=mips_memset + PLATFORM_DEFINES += -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include -Ips2/ -I$(PS2DEV)/gsKit/include + STATIC_LINKING=1 + EXTERNAL_ZLIB=1 + + RETROARCH_OBJECTS += ps2/SMS_Utils.o + # PSP else ifeq ($(platform), psp1) TARGET := $(TARGET_NAME)_libretro_$(platform).a @@ -255,6 +272,7 @@ else ifeq ($(platform), wii) ENDIANNESS_DEFINES += -DMSB_FIRST STATIC_LINKING=1 EXTERNAL_ZLIB=1 + SIGNED_CHAR=1 # Nintendo WiiU else ifeq ($(platform), wiiu) @@ -266,6 +284,7 @@ else ifeq ($(platform), wiiu) ENDIANNESS_DEFINES += -DMSB_FIRST STATIC_LINKING=1 EXTERNAL_ZLIB=1 + SIGNED_CHAR=1 # Nintendo Switch (libtransistor) else ifeq ($(platform), switch) @@ -366,9 +385,21 @@ else ifeq ($(platform), gcw0) SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float EXTERNAL_ZLIB = 1 - + +# Genode +else ifeq ($(platform), genode) + TARGET := $(TARGET_NAME)_libretro.lib.so + CC := $(shell pkg-config genode-base --variable=cc) + LD := $(shell pkg-config genode-base --variable=ld) + CFLAGS += $(shell pkg-config --cflags genode-libc) + LDFLAGS += -shared --version-script=src/drivers/libretro/link.T + LDFLAGS += $(shell pkg-config --libs genode-lib genode-libc) + LIBM = + # Windows MSVC 2017 all architectures else ifneq (,$(findstring windows_msvc2017,$(platform))) + CC = cl.exe + CXX = cl.exe PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) ifneq (,$(findstring desktop,$(PlatformSuffix))) @@ -388,8 +419,6 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) - CC = cl.exe - CXX = cl.exe LD = link.exe reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul))) @@ -530,6 +559,26 @@ CXXFLAGS += -D_XBOX -D_XBOX360 ENDIANNESS_DEFINES += -DMSB_FIRST STATIC_LINKING=1 +# Windows MSVC 2008 x86 +else ifeq ($(platform), windows_msvc2008_x86) + CC = cl.exe + CXX = cl.exe + +PATH := $(shell IFS=$$'\n'; cygpath "$(VS90COMNTOOLS)../../VC/bin"):$(PATH) +PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS90COMNTOOLS)../IDE") +INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS90COMNTOOLS)../../VC/include") +LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS90COMNTOOLS)../../VC/lib") +BIN := $(shell IFS=$$'\n'; cygpath "$(VS90COMNTOOLS)../../VC/bin") + +WindowsSdkDir := $(INETSDK) + +export INCLUDE := $(INCLUDE);$(INETSDK)/Include +export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib +TARGET := $(TARGET_NAME)_libretro.dll +PSS_STYLE :=2 +LDFLAGS += -DLL +CFLAGS += -D_CRT_SECURE_NO_DEPRECATE + # Windows MSVC 2005 x86 else ifeq ($(platform), windows_msvc2005_x86) CC = cl.exe @@ -543,7 +592,7 @@ BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin") WindowsSdkDir := $(INETSDK) -export INCLUDE := $(INCLUDE);$(INETSDK)/Include;src/drivers/libretro/msvc/msvc-2005 +export INCLUDE := $(INCLUDE);$(INETSDK)/Include export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib TARGET := $(TARGET_NAME)_libretro.dll PSS_STYLE :=2 @@ -563,7 +612,7 @@ BIN := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin") WindowsSdkDir := $(INETSDK) -export INCLUDE := $(INCLUDE);$(INETSDK)/Include;src/drivers/libretro/msvc/msvc-2005 +export INCLUDE := $(INCLUDE);$(INETSDK)/Include export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib TARGET := $(TARGET_NAME)_libretro.dll PSS_STYLE :=2 @@ -616,6 +665,10 @@ ifeq ($(EXTERNAL_ZLIB), 1) CFLAGS += -DHAVE_EXTERNAL_ZLIB endif +ifeq ($(SIGNED_CHAR), 1) + CFLAGS += -fsigned-char +endif + CORE_DIR := src include Makefile.common @@ -623,6 +676,7 @@ include Makefile.common CFLAGS += -DWANT_GRIFFIN OBJECTS := $(SOURCES_C:.c=.o) +OBJECTS += $(RETROARCH_OBJECTS) DEFINES := $(COREDEFINES) $(PLATFORM_DEFINES) @@ -660,6 +714,9 @@ else ifeq ($(platform), switch) OBJOUT = -o LINKOUT = -o # libtransistor.mk sets LD for us +else ifeq ($(platform), genode) + OBJOUT = -o + LINKOUT = -o else OBJOUT = -o LINKOUT = -o @@ -674,7 +731,6 @@ include $(THEOS_MAKE_PATH)/library.mk else all: $(TARGET) $(TARGET): $(OBJECTS) - @echo "** BUILDING $(TARGET) FOR PLATFORM $(platform) **" ifeq ($(STATIC_LINKING),1) ifneq (,$(findstring msvc,$(platform))) $(LD) $(LINKOUT)$@ $(OBJECTS) @@ -684,11 +740,15 @@ endif else $(LD) $(LINKOUT)$@ $(SHARED) $(OBJECTS) $(LDFLAGS) $(LIBS) endif - @echo "** BUILD SUCCESSFUL! GG NO RE **" %.o: %.c $(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(INCFLAGS) +ifeq ($(platform), ps2) +%.o: %.s + ee-as -G0 $< -o $@ +endif + clean-objs: rm -f $(OBJECTS) diff --git a/ps2/SMS_Utils.s b/ps2/SMS_Utils.s new file mode 100644 index 0000000..e437356 --- /dev/null +++ b/ps2/SMS_Utils.s @@ -0,0 +1,202 @@ +/* +# ___ _ _ ___ +# | | | | | +# ___| | | ___| PS2DEV Open Source Project. +#---------------------------------------------------------- +# MUL64 is pulled from some binary library (I don't remember which one). +# mips_memcpy routine is pulled from 'sde' library from MIPS. +# +*/ +.set noat +.set noreorder +.set nomacro + +.globl MUL64 +.globl mips_memcpy +.globl mips_memset + +.text + +MUL64: + pmultuw $v0, $a0, $a1 + dsra32 $a2, $a0, 0 + dsra32 $v1, $a1, 0 + mult $v1, $a0, $v1 + mult1 $a2, $a2, $a1 + addu $v1, $v1, $a2 + dsll32 $v1, $v1, 0 + jr $ra + daddu $v0, $v0, $v1 + +mips_memcpy: + addu $v0, $a0, $zero + beqz $a2, 1f + sltiu $t2, $a2, 12 + bnez $t2, 2f + xor $v1, $a1, $a0 + andi $v1, $v1, 7 + negu $a3, $a0 + beqz $v1, 3f + andi $a3, $a3, 7 + beqz $a3, 4f + subu $a2, $a2, $a3 + ldr $v1, 0($a1) + ldl $v1, 7($a1) + addu $a1, $a1, $a3 + sdr $v1, 0($a0) + addu $a0, $a0, $a3 +4: + andi $v1, $a2, 31 + subu $a3, $a2, $v1 + beqz $a3, 5f + addu $a2, $v1, $zero + addu $a3, $a3, $a1 +6: + ldr $v1, 0($a1) + ldl $v1, 7($a1) + ldr $t0, 8($a1) + ldl $t0, 15($a1) + ldr $t1, 16($a1) + ldl $t1, 23($a1) + ldr $t2, 24($a1) + ldl $t2, 31($a1) + sd $v1, 0($a0) + sd $t0, 8($a0) + sd $t1, 16($a0) + addiu $a1, $a1, 32 + addiu $a0, $a0, 32 + bne $a1, $a3, 6b + sd $t2, -8($a0) +5: + andi $v1, $a2, 7 + subu $a3, $a2, $v1 + beqz $a3, 2f + addu $a2, $v1, $zero + addu $a3, $a3, $a1 +7: + ldr $v1, 0($a1) + ldl $v1, 7($a1) + addiu $a1, $a1, 8 + addiu $a0, $a0, 8 + nop + bne $a1, $a3, 7b + sd $v1, -8($a0) + beq $zero, $zero, 2f + nop +3: + beqz $a3, 8f + subu $a2, $a2, $a3 + ldr $v1, 0($a1) + addu $a1, $a1, $a3 + sdr $v1, 0($a0) + addu $a0, $a0, $a3 +8: + andi $v1, $a2, 31 + subu $a3, $a2, $v1 + beqz $a3, 9f + addu $a2, $v1, $zero + addu $a3, $a3, $a1 +10: + ld $v1, 0($a1) + ld $t0, 8($a1) + ld $t1, 16($a1) + ld $t2, 24($a1) + sd $v1, 0($a0) + sd $t0, 8($a0) + sd $t1, 16($a0) + addiu $a1, $a1, 32 + addiu $a0, $a0, 32 + bne $a1, $a3, 10b + sd $t2, -8($a0) +9: + andi $v1, $a2, 7 + subu $a3, $a2, $v1 + beqz $a3, 2f + addu $a2, $v1, $zero + addu $a3, $a3, $a1 +11: + ld $v1, 0($a1) + addiu $a1, $a1, 8 + addiu $a0, $a0, 8 + nop + nop + bne $a1, $a3, 11b + sd $v1, -8($a0) +2: + beqz $a2, 1f + addu $a3, $a2, $a1 +12: + lbu $v1, 0($a1) + addiu $a1, $a1, 1 + addiu $a0, $a0, 1 + nop + nop + bne $a1, $a3, 12b + sb $v1, -1($a0) +1: + jr $ra + nop + +mips_memset: + beqz $a2, 1f + sltiu $at, $a2, 16 + bnez $at, 2f + andi $a1, $a1, 0xFF + dsll $at, $a1, 0x8 + or $a1, $a1, $at + dsll $at, $a1, 0x10 + or $a1, $a1, $at + dsll32 $at, $a1, 0x0 + or $a1, $a1, $at + andi $v1, $a0, 0x7 + beqz $v1, 3f + li $a3, 8 + subu $a3, $a3, $v1 + subu $a2, $a2, $a3 + sdr $a1, 0($a0) + addu $a0, $a0, $a3 +3: + andi $v1, $a2, 0x1f + subu $a3, $a2, $v1 + beqz $a3, 4f + move $a2, $v1 + addu $a3, $a3, $a0 +5: + sd $a1, 0($a0) + sd $a1, 8($a0) + sd $a1, 16($a0) + addiu $a0, $a0, 32 + sd $a1, -8($a0) + bne $a0, $a3, 5b +4: + andi $v1, $a2, 0x7 + subu $a3, $a2, $v1 + beqz $a3, 2f + move $a2, $v1 + addu $a3, $a3, $a0 +6: + addiu $a0, $a0, 8 + beq $a0, $a3, 2f + sd $a1, -8($a0) + addiu $a0, $a0, 8 + beq $a0, $a3, 2f + sd $a1, -8($a0) + addiu $a0, $a0, 8 + bne $a0, $a3, 6b + sd $a1, -8($a0) +2: + beqz $a2, 1f + addu $a3, $a2, $a0 +7: + addiu $a0, $a0, 1 + beq $a0, $a3, 1f + sb $a1, -1($a0) + addiu $a0, $a0, 1 + beq $a0, $a3, 1f + sb $a1, -1($a0) + addiu $a0, $a0, 1 + bne $a0, $a3, 7b + sb $a1, -1($a0) +1: + jr $ra + nop diff --git a/ps2/inttypes.h b/ps2/inttypes.h new file mode 100644 index 0000000..3049fbd --- /dev/null +++ b/ps2/inttypes.h @@ -0,0 +1,8 @@ +#ifndef INTTYPES_H +#define INTTYPES_H + +#define PRId64 "ld" +#define PRIu64 "lu" +#define PRIuPTR "lu" + +#endif //INTTYPES_H diff --git a/ps2/stdint.h b/ps2/stdint.h new file mode 100644 index 0000000..ae9a75b --- /dev/null +++ b/ps2/stdint.h @@ -0,0 +1,33 @@ +#ifndef STDINT_H +#define STDINT_H + +typedef unsigned long uintptr_t; +typedef signed long intptr_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long uint64_t; + +typedef unsigned long uint_least32_t; +typedef unsigned short uint_least16_t; + +#define STDIN_FILENO 0 /* standard input file descriptor */ +#define STDOUT_FILENO 1 /* standard output file descriptor */ +#define STDERR_FILENO 2 /* standard error file descriptor */ + +#define INT8_C(val) val##c +#define INT16_C(val) val##h +#define INT32_C(val) val##i +#define INT64_C(val) val##l + +#define UINT8_C(val) val##uc +#define UINT16_C(val) val##uh +#define UINT32_C(val) val##ui +#define UINT64_C(val) val##ul + +#endif //STDINT_H diff --git a/src/boards/69.c b/src/boards/69.c index 3907b57..2a7093b 100644 --- a/src/boards/69.c +++ b/src/boards/69.c @@ -27,6 +27,8 @@ static int32 IRQCount; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +static void(*sfun[3]) (void); + static SFORMAT StateRegs[] = { { &cmdreg, 1, "CMDR" }, @@ -41,7 +43,7 @@ static SFORMAT StateRegs[] = static void Sync(void) { uint8 i; if ((preg[3] & 0xC0) == 0xC0) - setprg8r(0x10, 0x6000, 0); + setprg8r(0x10, 0x6000, preg[3] & 0x3F); else setprg8(0x6000, preg[3] & 0x3F); setprg8(0x8000, preg[0]); @@ -89,9 +91,6 @@ static DECLFW(M69Write1) { case 0xA: preg[1] = V; Sync(); break; case 0xB: preg[2] = V; Sync(); break; case 0xC: mirr = V & 3; Sync();break; - /* 17/10/17- reg $0D should awknowledge IRQ and no other - * http://forums.nesdev.com/viewtopic.php?f=2&t=12436&start=15 - */ case 0xD: IRQa = V; X6502_IRQEnd(FCEU_IQEXT); break; case 0xE: IRQCount &= 0xFF00; IRQCount |= V; break; case 0xF: IRQCount &= 0x00FF; IRQCount |= V << 8; break; @@ -114,6 +113,20 @@ static SFORMAT SStateRegs[] = { { &sndcmd, 1, "SCMD" }, { sreg, 14, "SREG" }, + +/* Ignoring these sound state files for Wii since it causes states unable to load */ +#ifndef GEKKO + { &dcount[0], 4 | FCEUSTATE_RLSB, "DCT0" }, + { &dcount[1], 4 | FCEUSTATE_RLSB, "DCT1" }, + { &dcount[2], 4 | FCEUSTATE_RLSB, "DCT2" }, + { &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" }, + { &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" }, + { &vcount[2], 4 | FCEUSTATE_RLSB, "VCT2" }, + { &CAYBC[0], 4 | FCEUSTATE_RLSB, "BC00" }, + { &CAYBC[1], 4 | FCEUSTATE_RLSB, "BC01" }, + { &CAYBC[2], 4 | FCEUSTATE_RLSB, "BC02" }, +#endif + { 0 } }; @@ -125,22 +138,21 @@ static DECLFW(M69SWrite1) { int x; GameExpSound.Fill = AYSound; GameExpSound.HiFill = AYSoundHQ; - if (FSettings.SndRate) - switch (sndcmd) { - case 0: - case 1: - case 8: if (FSettings.soundq >= 1) DoAYSQHQ(0); else DoAYSQ(0); break; - case 2: - case 3: - case 9: if (FSettings.soundq >= 1) DoAYSQHQ(1); else DoAYSQ(1); break; - case 4: - case 5: - case 10: if (FSettings.soundq >= 1) DoAYSQHQ(2); else DoAYSQ(2); break; - case 7: - for (x = 0; x < 2; x++) - if (FSettings.soundq >= 1) DoAYSQHQ(x); else DoAYSQ(x); - break; - } + switch (sndcmd) { + case 0: + case 1: + case 8: if (sfun[0]) sfun[0](); break; + case 2: + case 3: + case 9: if (sfun[1]) sfun[1](); break; + case 4: + case 5: + case 10: if (sfun[2]) sfun[2](); break; + case 7: + if (sfun[0]) sfun[0](); + if (sfun[1]) sfun[1](); + break; + } sreg[sndcmd] = V; } @@ -190,19 +202,43 @@ static void DoAYSQHQ(int x) { CAYBC[x] = SOUNDTS; } +static void DoAYSQ1(void) { + DoAYSQ(0); +} + +static void DoAYSQ2(void) { + DoAYSQ(1); +} + +static void DoAYSQ3(void) { + DoAYSQ(2); +} + +static void DoAYSQ1HQ(void) { + DoAYSQHQ(0); +} + +static void DoAYSQ2HQ(void) { + DoAYSQHQ(1); +} + +static void DoAYSQ3HQ(void) { + DoAYSQHQ(2); +} + static void AYSound(int Count) { int x; - DoAYSQ(0); - DoAYSQ(1); - DoAYSQ(2); + DoAYSQ1(); + DoAYSQ2(); + DoAYSQ3(); for (x = 0; x < 3; x++) CAYBC[x] = Count; } static void AYSoundHQ(void) { - DoAYSQHQ(0); - DoAYSQHQ(1); - DoAYSQHQ(2); + DoAYSQ1HQ(); + DoAYSQ2HQ(); + DoAYSQ3HQ(); } static void AYHiSync(int32 ts) { @@ -218,6 +254,18 @@ void Mapper69_ESI(void) { memset(dcount, 0, sizeof(dcount)); memset(vcount, 0, sizeof(vcount)); memset(CAYBC, 0, sizeof(CAYBC)); + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) { + sfun[0] = DoAYSQ1HQ; + sfun[1] = DoAYSQ2HQ; + sfun[2] = DoAYSQ3HQ; + } else { + sfun[0] = DoAYSQ1; + sfun[1] = DoAYSQ2; + sfun[2] = DoAYSQ3; + } + } else + memset(sfun, 0, sizeof(sfun)); } /* SUNSOFT-5/FME-7 Sound */ @@ -270,8 +318,8 @@ void Mapper69_Init(CartInfo *info) { } GameStateRestore = StateRestore; Mapper69_ESI(); - AddExState(&SStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); + AddExState(&SStateRegs, ~0, 0, 0); } void NSFAY_Init(void) { diff --git a/src/boards/bandai.c b/src/boards/bandai.c index 9d3ca99..375d2b0 100644 --- a/src/boards/bandai.c +++ b/src/boards/bandai.c @@ -31,12 +31,29 @@ static int16 IRQCount, IRQLatch; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +/* TODO: Clean this up. State variables are expanded for + * big-endian compatibility when saving and loading states */ static SFORMAT StateRegs[] = { - { reg, 16, "REGS" }, + { ®[0], 1, "REG0" }, + { ®[1], 1, "REG1" }, + { ®[2], 1, "REG2" }, + { ®[3], 1, "REG3" }, + { ®[4], 1, "REG4" }, + { ®[5], 1, "REG5" }, + { ®[6], 1, "REG6" }, + { ®[7], 1, "REG7" }, + { ®[8], 1, "REG8" }, + { ®[9], 1, "REG9" }, + { ®[10], 1, "REGA" }, + { ®[11], 1, "REGB" }, + { ®[12], 1, "REGC" }, + { ®[13], 1, "REGD" }, + { ®[14], 1, "REGE" }, + { ®[15], 1, "REGF" }, { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, /* need for Famicom Jump II - Saikyou no 7 Nin (J) [!] */ + { &IRQCount, 2 | FCEUSTATE_RLSB, "IRQC" }, + { &IRQLatch, 2 | FCEUSTATE_RLSB, "IRQL" }, /* need for Famicom Jump II - Saikyou no 7 Nin (J) [!] */ { 0 } }; diff --git a/src/boards/emu2413.h b/src/boards/emu2413.h index 06eccd8..a0c173c 100644 --- a/src/boards/emu2413.h +++ b/src/boards/emu2413.h @@ -7,20 +7,6 @@ #include #include "../fceu-types.h" -#ifndef INLINE - -#if defined(_MSC_VER) -#define INLINE __forceinline -#elif defined(__GNUC__) -#define INLINE __inline__ -#elif defined(_MWERKS_) -#define INLINE inline -#else -#define INLINE -#endif -#endif - - #ifdef __cplusplus extern "C" { #endif diff --git a/src/boards/famicombox.c b/src/boards/famicombox.c index 67d9be1..8be1a60 100644 --- a/src/boards/famicombox.c +++ b/src/boards/famicombox.c @@ -75,7 +75,6 @@ static void SSSNROMPower(void) { regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0; regs[7] = 0xff; Sync(); - memset(WRAM, 0x00, WRAMSIZE); /* SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite); */ SetReadHandler(0x0800, 0x1FFF, CartBR); SetWriteHandler(0x0800, 0x1FFF, CartBW); diff --git a/src/boards/mmc5.c b/src/boards/mmc5.c index 27952c6..0ef1681 100644 --- a/src/boards/mmc5.c +++ b/src/boards/mmc5.c @@ -751,12 +751,31 @@ static void GenMMC5Reset(void) { FCEU_CheatAddRAM(1, 0x5c00, ExRAM); } +/* TODO: Clean this up. State variables are expanded for + * big-endian compatibility when saving and loading states */ static SFORMAT MMC5_StateRegs[] = { - { PRGBanks, 4, "PRGB" }, - { CHRBanksA, 16, "CHRA" }, - { CHRBanksB, 8, "CHRB" }, + { &PRGBanks[0], 1, "PRG1" }, + { &PRGBanks[1], 1, "PRG2" }, + { &PRGBanks[2], 1, "PRG3" }, + { &PRGBanks[3], 1, "PRG4" }, + + { &CHRBanksA[0], 2 | FCEUSTATE_RLSB, "CRA1" }, + { &CHRBanksA[1], 2 | FCEUSTATE_RLSB, "CRA2" }, + { &CHRBanksA[2], 2 | FCEUSTATE_RLSB, "CRA3" }, + { &CHRBanksA[3], 2 | FCEUSTATE_RLSB, "CRA4" }, + { &CHRBanksA[4], 2 | FCEUSTATE_RLSB, "CRA5" }, + { &CHRBanksA[5], 2 | FCEUSTATE_RLSB, "CRA6" }, + { &CHRBanksA[6], 2 | FCEUSTATE_RLSB, "CRA7" }, + { &CHRBanksA[7], 2 | FCEUSTATE_RLSB, "CRA8" }, + + { &CHRBanksB[0], 2 | FCEUSTATE_RLSB, "CRB1" }, + { &CHRBanksB[1], 2 | FCEUSTATE_RLSB, "CRB2" }, + { &CHRBanksB[2], 2 | FCEUSTATE_RLSB, "CRB3" }, + { &CHRBanksB[3], 2 | FCEUSTATE_RLSB, "CRB4" }, + { &WRAMPage, 1, "WRMP" }, - { WRAMMaskEnable, 2, "WRME" }, + { &WRAMMaskEnable[0], 1, "WRM1" }, + { &WRAMMaskEnable[1], 1, "WRM2" }, { &mmc5ABMode, 1, "ABMD" }, { &IRQScanline, 1, "IRQS" }, { &IRQEnable, 1, "IRQE" }, @@ -770,13 +789,25 @@ static SFORMAT MMC5_StateRegs[] = { { &MMC5LineCounter, 1, "LCTR" }, { &mmc5psize, 1, "PSIZ" }, { &mmc5vsize, 1, "VSIZ" }, - { mul, 2, "MUL2" }, - { MMC5ROMWrProtect, 4, "WRPR" }, - { MMC5MemIn, 5, "MEMI" }, + + { &mul[0], 1, "MUL1" }, + { &mul[1], 1, "MUL2" }, + + { &MMC5ROMWrProtect[0], 1, "WRP1" }, + { &MMC5ROMWrProtect[1], 1, "WRP2" }, + { &MMC5ROMWrProtect[2], 1, "WRP3" }, + { &MMC5ROMWrProtect[3], 1, "WRP4" }, + + { &MMC5MemIn[0], 1, "MMI1" }, + { &MMC5MemIn[1], 1, "MMI2" }, + { &MMC5MemIn[2], 1, "MMI3" }, + { &MMC5MemIn[3], 1, "MMI4" }, + { &MMC5MemIn[4], 1, "MMI5" }, { &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" }, { &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" }, - { MMC5Sound.env, 2, "SDEV" }, + { &MMC5Sound.env[0], 1, "SEV1" }, + { &MMC5Sound.env[1], 1, "SEV2" }, { &MMC5Sound.enable, 1, "SDEN" }, { &MMC5Sound.running, 1, "SDRU" }, { &MMC5Sound.raw, 1, "SDRW" }, @@ -790,6 +821,7 @@ static SFORMAT MMC5_StateRegs[] = { { &MMC5Sound.BC[2], 4 | FCEUSTATE_RLSB, "BC02" }, { &MMC5Sound.vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" }, { &MMC5Sound.vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" }, + { 0 } }; diff --git a/src/boards/n106.c b/src/boards/n106.c index f786a57..b1d6618 100644 --- a/src/boards/n106.c +++ b/src/boards/n106.c @@ -53,10 +53,34 @@ static int is210; /* Lesser mapper. */ static uint8 PRG[3]; static uint8 CHR[8]; +/* TODO: Clean this up. State variables are expanded for + * big-endian compatibility when saving and loading states */ static SFORMAT N106_StateRegs[] = { - { PRG, 3, "PRG" }, - { CHR, 8, "CHR" }, - { NTAPage, 4, "NTA" }, + { &PRG[0], 1, "PRG1" }, + { &PRG[1], 1, "PRG2" }, + { &PRG[2], 1, "PRG3" }, + + { &CHR[0], 1, "CHR1" }, + { &CHR[1], 1, "CHR2" }, + { &CHR[2], 1, "CHR3" }, + { &CHR[3], 1, "CHR4" }, + { &CHR[4], 1, "CHR5" }, + { &CHR[5], 1, "CHR6" }, + { &CHR[6], 1, "CHR7" }, + { &CHR[7], 1, "CHR8" }, + + { &NTAPage[0], 1, "NTA1" }, + { &NTAPage[1], 1, "NTA2" }, + { &NTAPage[2], 1, "NTA3" }, + { &NTAPage[3], 1, "NTA4" }, + + { &IRQCount, 2 | FCEUSTATE_RLSB, "IRQC" }, + { &IRQa, 1, "IRQA" }, + + { &dopol, 1, "GORF" }, + { &gorfus, 1, "DOPO" }, + { &gorko, 1, "GORK" }, + { 0 } }; @@ -224,6 +248,28 @@ static int32 CVBC; #define TOINDEX (16 + 1) +static SFORMAT N106_SStateRegs[] = +{ + { &PlayIndex[0], 4 | FCEUSTATE_RLSB, "IDX0" }, + { &PlayIndex[1], 4 | FCEUSTATE_RLSB, "IDX1" }, + { &PlayIndex[2], 4 | FCEUSTATE_RLSB, "IDX2" }, + { &PlayIndex[3], 4 | FCEUSTATE_RLSB, "IDX3" }, + { &PlayIndex[4], 4 | FCEUSTATE_RLSB, "IDX4" }, + { &PlayIndex[5], 4 | FCEUSTATE_RLSB, "IDX5" }, + { &PlayIndex[6], 4 | FCEUSTATE_RLSB, "IDX6" }, + { &PlayIndex[7], 4 | FCEUSTATE_RLSB, "IDX7" }, + { &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" }, + { &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" }, + { &vcount[2], 4 | FCEUSTATE_RLSB, "VCT2" }, + { &vcount[3], 4 | FCEUSTATE_RLSB, "VCT3" }, + { &vcount[4], 4 | FCEUSTATE_RLSB, "VCT4" }, + { &vcount[5], 4 | FCEUSTATE_RLSB, "VCT5" }, + { &vcount[6], 4 | FCEUSTATE_RLSB, "VCT6" }, + { &vcount[7], 4 | FCEUSTATE_RLSB, "VCT7" }, + { &CVBC, 4 | FCEUSTATE_RLSB, "BC00" }, + { 0 } +}; + /* 16:15 */ static void SyncHQ(int32 ts) { CVBC = ts; @@ -404,6 +450,7 @@ void Mapper19_Init(CartInfo *info) { AddExState(WRAM, 8192, 0, "WRAM"); AddExState(IRAM, 128, 0, "IRAM"); AddExState(N106_StateRegs, ~0, 0, 0); + AddExState(N106_SStateRegs, ~0, 0, 0); if (info->battery) { info->SaveGame[0] = WRAM; diff --git a/src/boards/unrom512.c b/src/boards/unrom512.c index 9bc4736..59ac51d 100644 --- a/src/boards/unrom512.c +++ b/src/boards/unrom512.c @@ -226,16 +226,16 @@ void UNROM512_Init(CartInfo *info) { mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2); switch (mirror) { - case 0: // hard horizontal, internal + case 0: /* hard horizontal, internal */ SetupCartMirroring(MI_H, 1, NULL); break; - case 1: // hard vertical, internal + case 1: /* hard vertical, internal */ SetupCartMirroring(MI_V, 1, NULL); break; - case 2: // switchable 1-screen, internal (flags: 4-screen + horizontal) + case 2: /* switchable 1-screen, internal (flags: 4-screen + horizontal) */ SetupCartMirroring(MI_0, 0, NULL); break; - case 3: // hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) + case 3: /* hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) */ SetupCartMirroring(4, 1, VROM + (info->vram_size - 8192)); break; } diff --git a/src/boards/vrc6.c b/src/boards/vrc6.c index c8772c7..0574cef 100644 --- a/src/boards/vrc6.c +++ b/src/boards/vrc6.c @@ -44,16 +44,33 @@ static SFORMAT StateRegs[] = }; static void(*sfun[3]) (void); + static uint8 vpsg1[8]; static uint8 vpsg2[4]; static int32 cvbc[3]; static int32 vcount[3]; -static int32 dcount[2]; +static int32 dcount[3]; +static int32 phaseacc; static SFORMAT SStateRegs[] = { { vpsg1, 8, "PSG1" }, { vpsg2, 4, "PSG2" }, + +/* Ignoring these sound state files for Wii since it causes states unable to load */ +#ifndef GEKKO + /* rw - 2018-11-28 Added */ + { &cvbc[0], 4 | FCEUSTATE_RLSB, "BC01" }, + { &cvbc[1], 4 | FCEUSTATE_RLSB, "BC02" }, + { &cvbc[2], 4 | FCEUSTATE_RLSB, "BC03" }, + { &dcount[0], 4 | FCEUSTATE_RLSB, "DCT0" }, + { &dcount[1], 4 | FCEUSTATE_RLSB, "DCT1" }, + { &dcount[2], 4 | FCEUSTATE_RLSB, "DCT2" }, + { &vcount[0], 4 | FCEUSTATE_RLSB, "VCT0" }, + { &vcount[1], 4 | FCEUSTATE_RLSB, "VCT1" }, + { &vcount[2], 4 | FCEUSTATE_RLSB, "VCT2" }, + { &phaseacc, 4 | FCEUSTATE_RLSB, "ACCU" }, +#endif { 0 } }; @@ -177,15 +194,20 @@ static INLINE void DoSQV(int x) { } else { int32 thresh = (vpsg1[x << 2] >> 4) & 7; int32 freq = ((vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1) << 17; + int32 dc = dcount[x]; + int32 vc = vcount[x]; + for (V = start; V < end; V++) { - if (dcount[x] > thresh) + if (dc > thresh) Wave[V >> 4] += amp; - vcount[x] -= nesincsize; - while (vcount[x] <= 0) { - vcount[x] += freq; - dcount[x] = (dcount[x] + 1) & 15; + vc -= nesincsize; + while (vc <= 0) { + vc += freq; + dc = (dc + 1) & 15; } } + vcount[x] = vc; + dcount[x] = dc; } } } @@ -208,29 +230,26 @@ static void DoSawV(void) { cvbc[2] = end; if (vpsg2[2] & 0x80) { - static int32 saw1phaseacc = 0; uint32 freq3; - static uint8 b3 = 0; - static int32 phaseacc = 0; static uint32 duff = 0; freq3 = (vpsg2[1] + ((vpsg2[2] & 15) << 8) + 1); for (V = start; V < end; V++) { - saw1phaseacc -= nesincsize; - if (saw1phaseacc <= 0) { + vcount[2] -= nesincsize; + if (vcount[2] <= 0) { int32 t; rea: t = freq3; t <<= 18; - saw1phaseacc += t; + vcount[2] += t; phaseacc += vpsg2[0] & 0x3f; - b3++; - if (b3 == 7) { - b3 = 0; + dcount[2]++; + if (dcount[2] == 7) { + dcount[2] = 0; phaseacc = 0; } - if (saw1phaseacc <= 0) + if (vcount[2] <= 0) goto rea; duff = (((phaseacc >> 3) & 0x1f) << 4) * 6 / 8; } @@ -249,15 +268,20 @@ static INLINE void DoSQVHQ(int x) { WaveHi[V] += amp; } else { int32 thresh = (vpsg1[x << 2] >> 4) & 7; + int32 dc = dcount[x]; + int32 vc = vcount[x]; + for (V = cvbc[x]; V < (int)SOUNDTS; V++) { - if (dcount[x] > thresh) + if (dc > thresh) WaveHi[V] += amp; - vcount[x]--; - if (vcount[x] <= 0) { - vcount[x] = (vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1; - dcount[x] = (dcount[x] + 1) & 15; + vc--; + if (vc <= 0) { + vc = (vpsg1[(x << 2) | 0x1] | ((vpsg1[(x << 2) | 0x2] & 15) << 8)) + 1; + dc = (dc + 1) & 15; } } + dcount[x] = dc; + vcount[x] = vc; } } cvbc[x] = SOUNDTS; @@ -272,8 +296,6 @@ static void DoSQV2HQ(void) { } static void DoSawVHQ(void) { - static uint8 b3 = 0; - static int32 phaseacc = 0; int32 V; if (vpsg2[2] & 0x80) { @@ -283,9 +305,9 @@ static void DoSawVHQ(void) { if (vcount[2] <= 0) { vcount[2] = (vpsg2[1] + ((vpsg2[2] & 15) << 8) + 1) << 1; phaseacc += vpsg2[0] & 0x3f; - b3++; - if (b3 == 7) { - b3 = 0; + dcount[2]++; + if (dcount[2] == 7) { + dcount[2] = 0; phaseacc = 0; } } @@ -294,7 +316,6 @@ static void DoSawVHQ(void) { cvbc[2] = SOUNDTS; } - void VRC6Sound(int Count) { int x; @@ -322,6 +343,7 @@ static void VRC6_ESI(void) { GameExpSound.HiFill = VRC6SoundHQ; GameExpSound.HiSync = VRC6SyncHQ; + phaseacc = 0; memset(cvbc, 0, sizeof(cvbc)); memset(vcount, 0, sizeof(vcount)); memset(dcount, 0, sizeof(dcount)); @@ -347,8 +369,8 @@ void Mapper24_Init(CartInfo *info) { MapIRQHook = VRC6IRQHook; VRC6_ESI(); GameStateRestore = StateRestore; - AddExState(&SStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); + AddExState(&SStateRegs, ~0, 0, 0); } void Mapper26_Init(CartInfo *info) { @@ -367,8 +389,8 @@ void Mapper26_Init(CartInfo *info) { info->SaveGame[0] = WRAM; info->SaveGameLen[0] = WRAMSIZE; } - AddExState(&SStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); + AddExState(&SStateRegs, ~0, 0, 0); } void NSFVRC6_Init(void) { diff --git a/src/boards/vrc7.c b/src/boards/vrc7.c index 7166f8c..2d77fa2 100644 --- a/src/boards/vrc7.c +++ b/src/boards/vrc7.c @@ -174,6 +174,10 @@ static void VRC7IRQHook(int a) { static void StateRestore(int version) { Sync(); + +#ifndef GEKKO + OPLL_forceRefresh(VRC7Sound); +#endif } void Mapper85_Init(CartInfo *info) { @@ -191,6 +195,31 @@ void Mapper85_Init(CartInfo *info) { GameStateRestore = StateRestore; VRC7_ESI(); AddExState(&StateRegs, ~0, 0, 0); + +/* Ignoring these sound state files for Wii since it causes states unable to load */ +#ifndef GEKKO + /* Sound states */ + AddExState(&VRC7Sound->adr, sizeof(VRC7Sound->adr), 0, "ADDR"); + AddExState(&VRC7Sound->out, sizeof(VRC7Sound->out), 0, "OUT0"); + AddExState(&VRC7Sound->realstep, sizeof(VRC7Sound->realstep), 0, "RTIM"); + AddExState(&VRC7Sound->oplltime, sizeof(VRC7Sound->oplltime), 0, "TIME"); + AddExState(&VRC7Sound->opllstep, sizeof(VRC7Sound->opllstep), 0, "STEP"); + AddExState(&VRC7Sound->prev, sizeof(VRC7Sound->prev), 0, "PREV"); + AddExState(&VRC7Sound->next, sizeof(VRC7Sound->next), 0, "NEXT"); + AddExState(&VRC7Sound->LowFreq, sizeof(VRC7Sound->LowFreq), 0, "LFQ0"); + AddExState(&VRC7Sound->HiFreq, sizeof(VRC7Sound->HiFreq), 0, "HFQ0"); + AddExState(&VRC7Sound->InstVol, sizeof(VRC7Sound->InstVol), 0, "VOLI"); + AddExState(&VRC7Sound->CustInst, sizeof(VRC7Sound->CustInst), 0, "CUSI"); + AddExState(&VRC7Sound->slot_on_flag, sizeof(VRC7Sound->slot_on_flag), 0, "FLAG"); + AddExState(&VRC7Sound->pm_phase, sizeof(VRC7Sound->pm_phase), 0, "PMPH"); + AddExState(&VRC7Sound->lfo_pm, sizeof(VRC7Sound->lfo_pm), 0, "PLFO"); + AddExState(&VRC7Sound->am_phase, sizeof(VRC7Sound->am_phase), 0, "AMPH"); + AddExState(&VRC7Sound->lfo_am, sizeof(VRC7Sound->lfo_am), 0, "ALFO"); + AddExState(&VRC7Sound->patch_number, sizeof(VRC7Sound->patch_number), 0, "PNUM"); + AddExState(&VRC7Sound->key_status, sizeof(VRC7Sound->key_status), 0, "KET"); + AddExState(&VRC7Sound->mask, sizeof(VRC7Sound->mask), 0, "MASK"); + AddExState((uint8 *)VRC7Sound->slot, sizeof(VRC7Sound->slot), 0, "SLOT"); +#endif } void NSFVRC7_Init(void) { diff --git a/src/drivers/libretro/libretro-common/include/libretro.h b/src/drivers/libretro/libretro-common/include/libretro.h index 7d01185..4e1a978 100644 --- a/src/drivers/libretro/libretro-common/include/libretro.h +++ b/src/drivers/libretro/libretro-common/include/libretro.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this libretro API header (libretro.h). @@ -128,7 +128,8 @@ extern "C" { /* LIGHTGUN device is similar to Guncon-2 for PlayStation 2. * It reports X/Y coordinates in screen space (similar to the pointer) - * in the range [-0x8000, 0x7fff] in both axes, with zero being center. + * in the range [-0x8000, 0x7fff] in both axes, with zero being center and + * -0x8000 being out of bounds. * As well as reporting on/off screen state. It features a trigger, * start/select buttons, auxiliary action buttons and a * directional pad. A forced off-screen shot can be requested for @@ -139,7 +140,8 @@ extern "C" { /* The ANALOG device is an extension to JOYPAD (RetroPad). * Similar to DualShock2 it adds two analog sticks and all buttons can * be analog. This is treated as a separate device type as it returns - * axis values in the full analog range of [-0x8000, 0x7fff]. + * axis values in the full analog range of [-0x7fff, 0x7fff], + * although some devices may return -0x8000. * Positive X axis is right. Positive Y axis is down. * Buttons are returned in the range [0, 0x7fff]. * Only use ANALOG type when polling for analog values. @@ -271,6 +273,7 @@ enum retro_language RETRO_LANGUAGE_POLISH = 14, RETRO_LANGUAGE_VIETNAMESE = 15, RETRO_LANGUAGE_ARABIC = 16, + RETRO_LANGUAGE_GREEK = 17, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -450,6 +453,7 @@ enum retro_key RETROK_POWER = 320, RETROK_EURO = 321, RETROK_UNDO = 322, + RETROK_OEM_102 = 323, RETROK_LAST, @@ -599,9 +603,12 @@ enum retro_mod * GET_VARIABLE. * This allows the frontend to present these variables to * a user dynamically. - * This should be called as early as possible (ideally in - * retro_set_environment). - * + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterward it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * * 'data' points to an array of retro_variable structs * terminated by a { NULL, NULL } element. * retro_variable::key should be namespaced to not collide @@ -654,6 +661,15 @@ enum retro_mod /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. * It was not used by any known core at the time, * and was removed from the API. */ +#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 + /* const struct retro_frame_time_callback * -- + * Lets the core know how much time has passed since last + * invocation of retro_run(). + * The frontend can tamper with the timing to fake fast-forward, + * slow-motion, frame stepping, etc. + * In this case the delta time will use the reference value + * in frame_time_callback.. + */ #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22 /* const struct retro_audio_callback * -- * Sets an interface which is used to notify a libretro core about audio @@ -680,15 +696,6 @@ enum retro_mod * A libretro core using SET_AUDIO_CALLBACK should also make use of * SET_FRAME_TIME_CALLBACK. */ -#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21 - /* const struct retro_frame_time_callback * -- - * Lets the core know how much time has passed since last - * invocation of retro_run(). - * The frontend can tamper with the timing to fake fast-forward, - * slow-motion, frame stepping, etc. - * In this case the delta time will use the reference value - * in frame_time_callback.. - */ #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23 /* struct retro_rumble_interface * -- * Gets an interface which is used by a libretro core to set @@ -775,17 +782,18 @@ enum retro_mod */ #define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31 /* const char ** -- - * Returns the "save" directory of the frontend. - * This directory can be used to store SRAM, memory cards, - * high scores, etc, if the libretro core + * Returns the "save" directory of the frontend, unless there is no + * save directory available. The save directory should be used to + * store SRAM, memory cards, high scores, etc, if the libretro core * cannot use the regular memory interface (retro_get_memory_data()). * - * NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for - * similar things before. - * They should still check GET_SYSTEM_DIRECTORY if they want to - * be backwards compatible. - * The path here can be NULL. It should only be non-NULL if the - * frontend user has set a specific save path. + * If the frontend cannot designate a save directory, it will return + * NULL to indicate that the core should attempt to operate without a + * save directory set. + * + * NOTE: early libretro cores used the system directory for save + * files. Cores that need to be backwards-compatible can still check + * GET_SYSTEM_DIRECTORY. */ #define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 /* const struct retro_system_av_info * -- @@ -853,26 +861,39 @@ enum retro_mod #define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35 /* const struct retro_controller_info * -- * This environment call lets a libretro core tell the frontend - * which controller types are recognized in calls to + * which controller subclasses are recognized in calls to * retro_set_controller_port_device(). * - * Some emulators such as Super Nintendo - * support multiple lightgun types which must be specifically - * selected from. - * It is therefore sometimes necessary for a frontend to be able - * to tell the core about a special kind of input device which is - * not covered by the libretro input API. + * Some emulators such as Super Nintendo support multiple lightgun + * types which must be specifically selected from. It is therefore + * sometimes necessary for a frontend to be able to tell the core + * about a special kind of input device which is not specifcally + * provided by the Libretro API. * - * In order for a frontend to understand the workings of an input device, - * it must be a specialized type - * of the generic device types already defined in the libretro API. + * In order for a frontend to understand the workings of those devices, + * they must be defined as a specialized subclass of the generic device + * types already defined in the libretro API. * - * Which devices are supported can vary per input port. * The core must pass an array of const struct retro_controller_info which - * is terminated with a blanked out struct. Each element of the struct - * corresponds to an ascending port index to - * retro_set_controller_port_device(). - * Even if special device types are set in the libretro core, + * is terminated with a blanked out struct. Each element of the + * retro_controller_info struct corresponds to the ascending port index + * that is passed to retro_set_controller_port_device() when that function + * is called to indicate to the core that the frontend has changed the + * active device subclass. SEE ALSO: retro_set_controller_port_device() + * + * The ascending input port indexes provided by the core in the struct + * are generally presented by frontends as ascending User # or Player #, + * such as Player 1, Player 2, Player 3, etc. Which device subclasses are + * supported can vary per input port. + * + * The first inner element of each entry in the retro_controller_info array + * is a retro_controller_description struct that specifies the names and + * codes of all device subclasses that are available for the corresponding + * User or Player, beginning with the generic Libretro device that the + * subclasses are derived from. The second inner element of each entry is the + * total number of subclasses that are listed in the retro_controller_description. + * + * NOTE: Even if special device types are set in the libretro core, * libretro should only poll input based on the base input device types. */ #define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) @@ -951,7 +972,37 @@ enum retro_mod * A frontend must make sure that the pointer obtained from this function is * writeable (and readable). */ - +#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_interface ** -- + * Returns an API specific rendering interface for accessing API specific data. + * Not all HW rendering APIs support or need this. + * The contents of the returned pointer is specific to the rendering API + * being used. See the various headers like libretro_vulkan.h, etc. + * + * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. + * Similarly, after context_destroyed callback returns, + * the contents of the HW_RENDER_INTERFACE are invalidated. + */ +#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const bool * -- + * If true, the libretro implementation supports achievements + * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS + * or via retro_get_memory_data/retro_get_memory_size. + * + * This must be called before the first call to retro_run. + */ +#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* const struct retro_hw_render_context_negotiation_interface * -- + * Sets an interface which lets the libretro core negotiate with frontend how a context is created. + * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. + * This interface will be used when the frontend is trying to create a HW rendering context, + * so it will be used after SET_HW_RENDER, but before the context_reset callback. + */ +#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 + /* uint64_t * -- + * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't + * recognize or support. Should be set in either retro_init or retro_load_game, but not both. + */ #define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* N/A (null) * -- * The frontend will try to use a 'shared' hardware context (mostly applicable @@ -963,14 +1014,70 @@ enum retro_mod * This will do nothing on its own until SET_HW_RENDER env callbacks are * being used. */ - #define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL) /* struct retro_vfs_interface_info * -- * Gets access to the VFS interface. * VFS presence needs to be queried prior to load_game or any * get_system/save/other_directory being called to let front end know * core supports VFS before it starts handing out paths. - * It is recomended to do so in retro_set_environment */ + * It is recomended to do so in retro_set_environment + */ +#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_led_interface * -- + * Gets an interface which is used by a libretro core to set + * state of LEDs. + */ +#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* int * -- + * Tells the core if the frontend wants audio or video. + * If disabled, the frontend will discard the audio or video, + * so the core may decide to skip generating a frame or generating audio. + * This is mainly used for increasing performance. + * Bit 0 (value 1): Enable Video + * Bit 1 (value 2): Enable Audio + * Bit 2 (value 4): Use Fast Savestates. + * Bit 3 (value 8): Hard Disable Audio + * Other bits are reserved for future use and will default to zero. + * If video is disabled: + * * The frontend wants the core to not generate any video, + * including presenting frames via hardware acceleration. + * * The frontend's video frame callback will do nothing. + * * After running the frame, the video output of the next frame should be + * no different than if video was enabled, and saving and loading state + * should have no issues. + * If audio is disabled: + * * The frontend wants the core to not generate any audio. + * * The frontend's audio callbacks will do nothing. + * * After running the frame, the audio output of the next frame should be + * no different than if audio was enabled, and saving and loading state + * should have no issues. + * Fast Savestates: + * * Guaranteed to be created by the same binary that will load them. + * * Will not be written to or read from the disk. + * * Suggest that the core assumes loading state will succeed. + * * Suggest that the core updates its memory buffers in-place if possible. + * * Suggest that the core skips clearing memory. + * * Suggest that the core skips resetting the system. + * * Suggest that the core may skip validation steps. + * Hard Disable Audio: + * * Used for a secondary core when running ahead. + * * Indicates that the frontend will never need audio from the core. + * * Suggests that the core may stop synthesizing audio, but this should not + * compromise emulation accuracy. + * * Audio output for the next frame does not matter, and the frontend will + * never need an accurate audio state in the future. + * * State will never be saved when using Hard Disable Audio. + */ +#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_midi_interface ** -- + * Returns a MIDI interface that can be used for raw data I/O. + */ + +#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend is in + * fastforwarding mode. + */ /* VFS functionality */ @@ -1030,6 +1137,10 @@ typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *st * Introduced in VFS API v1 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream); +/* Truncate file to specified size. Returns 0 on success or -1 on error + * Introduced in VFS API v2 */ +typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length); + /* Get the current read / write position for the file. Returns - 1 for error. * Introduced in VFS API v1 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream); @@ -1060,6 +1171,7 @@ typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const cha struct retro_vfs_interface { + /* VFS API v1 */ retro_vfs_get_path_t get_path; retro_vfs_open_t open; retro_vfs_close_t close; @@ -1071,6 +1183,8 @@ struct retro_vfs_interface retro_vfs_flush_t flush; retro_vfs_remove_t remove; retro_vfs_rename_t rename; + /* VFS API v2 */ + retro_vfs_truncate_t truncate; }; struct retro_vfs_interface_info @@ -1104,81 +1218,41 @@ struct retro_hw_render_interface unsigned interface_version; }; - -#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_led_interface * -- - * Gets an interface which is used by a libretro core to set - * state of LEDs. - */ - typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state); struct retro_led_interface { retro_set_led_state_t set_led_state; }; -#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* int * -- - * Tells the core if the frontend wants audio or video. - * If disabled, the frontend will discard the audio or video, - * so the core may decide to skip generating a frame or generating audio. - * This is mainly used for increasing performance. - * Bit 0 (value 1): Enable Video - * Bit 1 (value 2): Enable Audio - * Bit 2 (value 4): Use Fast Savestates. - * Bit 3 (value 8): Hard Disable Audio - * Other bits are reserved for future use and will default to zero. - * If video is disabled: - * * The frontend wants the core to not generate any video, - * including presenting frames via hardware acceleration. - * * The frontend's video frame callback will do nothing. - * * After running the frame, the video output of the next frame should be - * no different than if video was enabled, and saving and loading state - * should have no issues. - * If audio is disabled: - * * The frontend wants the core to not generate any audio. - * * The frontend's audio callbacks will do nothing. - * * After running the frame, the audio output of the next frame should be - * no different than if audio was enabled, and saving and loading state - * should have no issues. - * Fast Savestates: - * * Guaranteed to be created by the same binary that will load them. - * * Will not be written to or read from the disk. - * * Suggest that the core assumes loading state will succeed. - * * Suggest that the core updates its memory buffers in-place if possible. - * * Suggest that the core skips clearing memory. - * * Suggest that the core skips resetting the system. - * * Suggest that the core may skip validation steps. - * Hard Disable Audio: - * * Used for a secondary core when running ahead. - * * Indicates that the frontend will never need audio from the core. - * * Suggests that the core may stop synthesizing audio, but this should not - * compromise emulation accuracy. - * * Audio output for the next frame does not matter, and the frontend will - * never need an accurate audio state in the future. - * * State will never be saved when using Hard Disable Audio. - */ +/* Retrieves the current state of the MIDI input. + * Returns true if it's enabled, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void); -#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_interface ** -- - * Returns an API specific rendering interface for accessing API specific data. - * Not all HW rendering APIs support or need this. - * The contents of the returned pointer is specific to the rendering API - * being used. See the various headers like libretro_vulkan.h, etc. - * - * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called. - * Similarly, after context_destroyed callback returns, - * the contents of the HW_RENDER_INTERFACE are invalidated. - */ +/* Retrieves the current state of the MIDI output. + * Returns true if it's enabled, false otherwise */ +typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void); -#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const bool * -- - * If true, the libretro implementation supports achievements - * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS - * or via retro_get_memory_data/retro_get_memory_size. - * - * This must be called before the first call to retro_run. - */ +/* Reads next byte from the input stream. + * Returns true if byte is read, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte); + +/* Writes byte to the output stream. + * 'delta_time' is in microseconds and represent time elapsed since previous write. + * Returns true if byte is written, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time); + +/* Flushes previously written data. + * Returns true if successful, false otherwise. */ +typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void); + +struct retro_midi_interface +{ + retro_midi_input_enabled_t input_enabled; + retro_midi_output_enabled_t output_enabled; + retro_midi_read_t read; + retro_midi_write_t write; + retro_midi_flush_t flush; +}; enum retro_hw_render_context_negotiation_interface_type { @@ -1193,13 +1267,6 @@ struct retro_hw_render_context_negotiation_interface enum retro_hw_render_context_negotiation_interface_type interface_type; unsigned interface_version; }; -#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_hw_render_context_negotiation_interface * -- - * Sets an interface which lets the libretro core negotiate with frontend how a context is created. - * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier. - * This interface will be used when the frontend is trying to create a HW rendering context, - * so it will be used after SET_HW_RENDER, but before the context_reset callback. - */ /* Serialized state is incomplete in some way. Set if serialization is * usable in typical end-user cases but should not be relied upon to @@ -1225,20 +1292,17 @@ struct retro_hw_render_context_negotiation_interface * dependence */ #define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6) -#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44 - /* uint64_t * -- - * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't - * recognize or support. Should be set in either retro_init or retro_load_game, but not both. - */ - -#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ -#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ -#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ -#define RETRO_MEMDESC_ALIGN_4 (2 << 16) -#define RETRO_MEMDESC_ALIGN_8 (3 << 16) -#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ -#define RETRO_MEMDESC_MINSIZE_4 (2 << 24) -#define RETRO_MEMDESC_MINSIZE_8 (3 << 24) +#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */ +#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */ +#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2) /* The memory area is system RAM. This is main RAM of the gaming system. */ +#define RETRO_MEMDESC_SAVE_RAM (1 << 3) /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */ +#define RETRO_MEMDESC_VIDEO_RAM (1 << 4) /* The memory area is video RAM (VRAM) */ +#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */ +#define RETRO_MEMDESC_ALIGN_4 (2 << 16) +#define RETRO_MEMDESC_ALIGN_8 (3 << 16) +#define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */ +#define RETRO_MEMDESC_MINSIZE_4 (2 << 24) +#define RETRO_MEMDESC_MINSIZE_8 (3 << 24) struct retro_memory_descriptor { uint64_t flags; @@ -2138,17 +2202,26 @@ struct retro_system_info * Typically used for a GUI to filter * out extensions. */ - /* If true, retro_load_game() is guaranteed to provide a valid pathname - * in retro_game_info::path. - * ::data and ::size are both invalid. + /* Libretro cores that need to have direct access to their content + * files, including cores which use the path of the content files to + * determine the paths of other files, should set need_fullpath to true. * - * If false, ::data and ::size are guaranteed to be valid, but ::path - * might not be valid. + * Cores should strive for setting need_fullpath to false, + * as it allows the frontend to perform patching, etc. * - * This is typically set to true for libretro implementations that must - * load from file. - * Implementations should strive for setting this to false, as it allows - * the frontend to perform patching, etc. */ + * If need_fullpath is true and retro_load_game() is called: + * - retro_game_info::path is guaranteed to have a valid path + * - retro_game_info::data and retro_game_info::size are invalid + * + * If need_fullpath is false and retro_load_game() is called: + * - retro_game_info::path may be NULL + * - retro_game_info::data and retro_game_info::size are guaranteed + * to be valid + * + * See also: + * - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY + * - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY + */ bool need_fullpath; /* If true, the frontend is not allowed to extract any archives before @@ -2333,7 +2406,13 @@ RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info); * will only poll input based on that particular device type. It is only a * hint to the libretro core when a core cannot automatically detect the * appropriate input device type on its own. It is also relevant when a - * core can change its behavior depending on device type. */ + * core can change its behavior depending on device type. + * + * As part of the core's implementation of retro_set_controller_port_device, + * the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the + * frontend if the descriptions for any controls have changed as a + * result of changing the device type. + */ RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device); /* Resets the current game. */ @@ -2365,7 +2444,9 @@ RETRO_API bool retro_unserialize(const void *data, size_t size); RETRO_API void retro_cheat_reset(void); RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code); -/* Loads a game. */ +/* Loads a game. + * Return true to indicate successful loading and false to indicate load failure. + */ RETRO_API bool retro_load_game(const struct retro_game_info *game); /* Loads a "special" kind of game. Should not be used, @@ -2375,7 +2456,7 @@ RETRO_API bool retro_load_game_special( const struct retro_game_info *info, size_t num_info ); -/* Unloads a currently loaded game. */ +/* Unloads the currently loaded game. Called before retro_deinit(void). */ RETRO_API void retro_unload_game(void); /* Gets region of game. */ diff --git a/src/drivers/libretro/libretro-common/include/libretro_gskit_ps2.h b/src/drivers/libretro/libretro-common/include/libretro_gskit_ps2.h new file mode 100644 index 0000000..f7b61dc --- /dev/null +++ b/src/drivers/libretro/libretro-common/include/libretro_gskit_ps2.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro_d3d.h) + * --------------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the + * "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBRETRO_GSKIT_PS2_H_ +#define LIBRETRO_GSKIT_PS2_H_ + +#include "libretro.h" + +#if defined(PS2) + +#include + +#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 1 + +struct retro_hw_ps2_insets +{ + float top; + float left; + float bottom; + float right; +}; + +#define empty_ps2_insets (struct retro_hw_ps2_insets){0.f, 0.f, 0.f, 0.f} + +struct retro_hw_render_interface_gskit_ps2 +{ + /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */ + enum retro_hw_render_interface_type interface_type; + /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */ + unsigned interface_version; + + /* Opaque handle to the GSKit_PS2 backend in the frontend + * which must be passed along to all function pointers + * in this interface. + */ + GSTEXTURE *coreTexture; + bool clearTexture; + bool updatedPalette; + struct retro_hw_ps2_insets padding; +}; +typedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2; + +#endif + +#endif /* LIBRETRO_GSKIT_PS2_H_ */ diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index 95e72de..28e1796 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -24,19 +24,29 @@ #include "../../vsuni.h" #include "../../video.h" +#if defined(RENDER_GSKIT_PS2) +#include "libretro-common/include/libretro_gskit_ps2.h" +#endif + #include "libretro-common/include/streams/memory_stream.h" #define MAX_PLAYERS 4 /* max supported players */ #define MAX_PORTS 2 /* max controller ports, * port 0 for player 1/3, port 1 for player 2/4 */ -#define RETRO_DEVICE_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) +#define RETRO_DEVICE_AUTO RETRO_DEVICE_JOYPAD +#define RETRO_DEVICE_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1) #define RETRO_DEVICE_ZAPPER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 0) #define RETRO_DEVICE_ARKANOID RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 1) + #define RETRO_DEVICE_FC_ARKANOID RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 2) #define RETRO_DEVICE_FC_OEKAKIDS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 3) #define RETRO_DEVICE_FC_SHADOW RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 4) +#define RETRO_DEVICE_FC_4PLAYERS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2) +#define RETRO_DEVICE_FC_AUTO RETRO_DEVICE_JOYPAD +#define NES_WIDTH 256 +#define NES_HEIGHT 240 #define NES_8_7_PAR ((width * (8.0 / 7.0)) / height) #define NES_4_3 ((width / (height * (256.0 / 240.0))) * 4.0 / 3.0) @@ -45,6 +55,10 @@ void* linearMemAlign(size_t size, size_t alignment); void linearFree(void* mem); #endif +#if defined(RENDER_GSKIT_PS2) +RETRO_HW_RENDER_INTEFACE_GSKIT_PS2 *ps2 = NULL; +#endif + static retro_video_refresh_t video_cb = NULL; static retro_input_poll_t poll_cb = NULL; static retro_input_state_t input_cb = NULL; @@ -89,20 +103,27 @@ static __attribute__((aligned(16))) uint16_t retro_palette[256]; #else static uint16_t retro_palette[256]; #endif +#if defined(RENDER_GSKIT_PS2) +static uint8_t* fceu_video_out; +#else static uint16_t* fceu_video_out; +#endif /* Some timing-related variables. */ -unsigned sndsamplerate = 48000; -unsigned sndquality = 0; -unsigned sndvolume = 150; -unsigned swapDuty = 0; +static unsigned sndsamplerate; +static unsigned sndquality; +static unsigned sndvolume; +unsigned swapDuty; static int32_t *sound = 0; static uint32_t JSReturn = 0; +static uint32_t Dummy = 0; static uint32_t MouseData[MAX_PORTS][3] = { {0} }; static uint32_t fc_MouseData[3] = {0}; static uint32_t current_palette = 0; +static unsigned serialize_size; + int PPUViewScanline=0; int PPUViewer=0; @@ -136,6 +157,16 @@ int FCEUD_SendData(void *data, uint32 len) #define RED_EXPAND 3 #define GREEN_EXPAND 2 #define BLUE_EXPAND 3 +#elif defined (FRONTEND_SUPPORTS_ABGR1555) +#define RED_SHIFT 0 +#define GREEN_SHIFT 5 +#define BLUE_SHIFT 10 +#define RED_EXPAND 3 +#define GREEN_EXPAND 3 +#define BLUE_EXPAND 3 +#define RED_MASK 0x1F +#define GREEN_MASK 0x3E0 +#define BLUE_MASK 0x7C00 #elif defined (FRONTEND_SUPPORTS_RGB565) #define RED_SHIFT 11 #define GREEN_SHIFT 5 @@ -155,12 +186,23 @@ int FCEUD_SendData(void *data, uint32 len) #define BLUE_EXPAND 3 #endif -void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b) +void FCEUD_SetPalette(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { + unsigned char index_to_write = index; +#if defined(RENDER_GSKIT_PS2) + /* Index correction for PS2 GS */ + int modi = index & 63; + if ((modi >= 8 && modi < 16) || (modi >= 40 && modi < 48)) { + index_to_write += 8; + } else if ((modi >= 16 && modi < 24) || (modi >= 48 && modi < 56)) { + index_to_write -= 8; + } +#endif + #ifdef FRONTEND_SUPPORTS_RGB565 - retro_palette[index] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); + retro_palette[index_to_write] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); #else - retro_palette[index] = + retro_palette[index_to_write] = ((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT); #endif } @@ -214,10 +256,11 @@ FILE *FCEUD_UTF8fopen(const char *n, const char *m) return NULL; } -#define MAX_PATH 1024 - /*palette for FCEU*/ -#define MAXPAL 17 /* raw palette # */ +#define PAL_TOTAL 16 /* total no. of palettes in palettes[] */ +#define PAL_DEFAULT (PAL_TOTAL + 1) +#define PAL_RAW (PAL_TOTAL + 2) +#define PAL_CUSTOM (PAL_TOTAL + 3) static int external_palette_exist = 0; extern int ipalette; @@ -546,31 +589,150 @@ void retro_set_input_state(retro_input_state_t cb) input_cb = cb; } -void set_input_nes_controller(unsigned port, int x); -void set_input_famicom_controller(int x); +static void update_nes_controllers(unsigned port, unsigned device) +{ + input_type[port] = device; + + if (port < 4) + { + switch (device) + { + case RETRO_DEVICE_NONE: + FCEUI_SetInput(port, SI_NONE, &Dummy, 0); + FCEU_printf(" Player %u: None Connected\n", port + 1); + break; + case RETRO_DEVICE_ZAPPER: + FCEUI_SetInput(port, SI_ZAPPER, MouseData[port], 1); + FCEU_printf(" Player %u: Zapper\n", port + 1); + break; + case RETRO_DEVICE_ARKANOID: + FCEUI_SetInput(port, SI_ARKANOID, MouseData[port], 0); + FCEU_printf(" Player %u: Arkanoid\n", port + 1); + break; + case RETRO_DEVICE_GAMEPAD: + default: + input_type[port] = RETRO_DEVICE_GAMEPAD; + FCEUI_SetInput(port, SI_GAMEPAD, &JSReturn, 0); + FCEU_printf(" Player %u: Gamepad\n", port + 1); + break; + } + } + + if (port == 4) + { + switch (device) + { + case RETRO_DEVICE_FC_ARKANOID: + FCEUI_SetInputFC(SIFC_ARKANOID, fc_MouseData, 0); + FCEU_printf(" Famicom Expansion: Arkanoid\n"); + break; + case RETRO_DEVICE_FC_SHADOW: + FCEUI_SetInputFC(SIFC_SHADOW, fc_MouseData, 1); + FCEU_printf(" Famicom Expansion: (Bandai) Hyper Shot\n"); + break; + case RETRO_DEVICE_FC_OEKAKIDS: + FCEUI_SetInputFC(SIFC_OEKAKIDS, fc_MouseData, 1); + FCEU_printf(" Famicom Expansion: Oeka Kids Tablet\n"); + break; + case RETRO_DEVICE_FC_4PLAYERS: + FCEUI_SetInputFC(SIFC_4PLAYER, &JSReturn, 0); + FCEU_printf(" Famicom Expansion: Famicom 4-Player Adapter\n"); + break; + case RETRO_DEVICE_NONE: + default: + FCEUI_SetInputFC(SIFC_NONE, &Dummy, 0); + FCEU_printf(" Famicom Expansion: None Connected\n"); + break; + } + } +} + +static unsigned nes_to_libretro(int d) +{ + switch(d) + { + case SI_UNSET: + case SI_GAMEPAD: + return RETRO_DEVICE_GAMEPAD; + case SI_NONE: + return RETRO_DEVICE_NONE; + case SI_ZAPPER: + return RETRO_DEVICE_ZAPPER; + case SI_ARKANOID: + return RETRO_DEVICE_ARKANOID; + } + + return (RETRO_DEVICE_GAMEPAD); +} + +static unsigned fc_to_libretro(int d) +{ + switch(d) + { + case SIFC_UNSET: + case SIFC_NONE: + return RETRO_DEVICE_NONE; + case SIFC_ARKANOID: + return RETRO_DEVICE_FC_ARKANOID; + case SIFC_SHADOW: + return RETRO_DEVICE_FC_SHADOW; + case SIFC_OEKAKIDS: + return RETRO_DEVICE_FC_OEKAKIDS; + case SIFC_4PLAYER: + return RETRO_DEVICE_FC_4PLAYERS; + } + + return (RETRO_DEVICE_NONE); +} void retro_set_controller_port_device(unsigned port, unsigned device) { - if (port < MAX_PORTS) /* port #0 = player1/player3, port #1 = player2/player4 */ + if ((port < 5) && (input_type[port] != device)) { - switch(device) + if (port < 2) /* player 1-2 */ { - case RETRO_DEVICE_NONE: - set_input_nes_controller(port, SI_NONE); - break; - case RETRO_DEVICE_GAMEPAD: - set_input_nes_controller(port, SI_GAMEPAD); - break; - case RETRO_DEVICE_ZAPPER: - set_input_nes_controller(port, SI_ZAPPER); - break; - case RETRO_DEVICE_ARKANOID: - set_input_nes_controller(port, SI_ARKANOID); - break; - case RETRO_DEVICE_JOYPAD: /* Assigned to auto configure devices */ - default: /* based on database */ - set_input_nes_controller(port, GameInfo->input[port]); - break; + if (device != RETRO_DEVICE_AUTO) + update_nes_controllers(port, device); + else + update_nes_controllers(port, nes_to_libretro(GameInfo->input[port])); + } + else + { + if (port < 4) /* player 3-4 */ + { + /* This section automatically enables 4players support + * when player 3 or 4 used */ + + input_type[port] = RETRO_DEVICE_NONE; + + if (device == RETRO_DEVICE_AUTO) + { + if (enable_4player) + input_type[port] = RETRO_DEVICE_GAMEPAD; + } + else if (device == RETRO_DEVICE_GAMEPAD) + input_type[port] = RETRO_DEVICE_GAMEPAD; + + FCEU_printf(" Player %u: %s\n", port + 1, + (input_type[port] == RETRO_DEVICE_NONE) ? "None Connected" : "Gamepad"); + } + else /* do famicom controllers here */ + { + if (device != RETRO_DEVICE_FC_AUTO) + update_nes_controllers(4, device); + else + update_nes_controllers(4, fc_to_libretro(GameInfo->inputfc)); + } + + if (input_type[2] == RETRO_DEVICE_GAMEPAD + || input_type[3] == RETRO_DEVICE_GAMEPAD) + FCEUI_DisableFourScore(0); + else + FCEUI_DisableFourScore(1); + + /* check if famicom 4player adapter is used */ + if (input_type[4] == RETRO_DEVICE_FC_4PLAYERS) + FCEUI_DisableFourScore(1); } } } @@ -592,33 +754,65 @@ void retro_set_environment(retro_environment_t cb) { "fceumm_sndvolume", "Sound Volume; 150|160|170|180|190|200|210|220|230|240|250|0|10|20|30|40|50|60|70|80|90|100|110|120|130|140" }, { "fceumm_sndquality", "Sound Quality; Low|High|Very High" }, { "fceumm_swapduty", "Swap Duty Cycles; disabled|enabled" }, +#ifdef DEBUG + { "fceumm_apu_1", "Enable Sound Channel 1 (Square 1); enabled|disabled" }, + { "fceumm_apu_2", "Enable Sound Channel 2 (Square 2); enabled|disabled" }, + { "fceumm_apu_3", "Enable Sound Channel 3 (Triangle); enabled|disabled" }, + { "fceumm_apu_4", "Enable Sound Channel 4 (Noise); enabled|disabled" }, + { "fceumm_apu_5", "Enable Sound Channel 5 (PCM); enabled|disabled" }, +#endif { "fceumm_turbo_enable", "Turbo Enable; None|Player 1|Player 2|Both" }, { "fceumm_turbo_delay", "Turbo Delay (in frames); 3|5|10|15|30|60|1|2" }, { "fceumm_zapper_mode", "Zapper Mode; lightgun|mouse" }, { "fceumm_show_crosshair", "Show Crosshair; enabled|disabled" }, { "fceumm_overclocking", "Overclocking; disabled|2x-Postrender|2x-VBlank" }, + { "fceumm_ramstate", "RAM power up state (Restart); fill $ff|fill $00|random" }, { NULL, NULL }, }; static const struct retro_controller_description pads1[] = { - { "Auto", RETRO_DEVICE_JOYPAD }, + { "Auto", RETRO_DEVICE_AUTO }, { "Gamepad", RETRO_DEVICE_GAMEPAD }, { "Zapper", RETRO_DEVICE_ZAPPER }, - { NULL, 0 }, + { 0, 0 }, }; static const struct retro_controller_description pads2[] = { - { "Auto", RETRO_DEVICE_JOYPAD }, + { "Auto", RETRO_DEVICE_AUTO }, { "Gamepad", RETRO_DEVICE_GAMEPAD }, { "Arkanoid", RETRO_DEVICE_ARKANOID }, { "Zapper", RETRO_DEVICE_ZAPPER }, - { NULL, 0 }, + { 0, 0 }, + }; + + static const struct retro_controller_description pads3[] = { + { "Auto", RETRO_DEVICE_AUTO }, + { "Gamepad", RETRO_DEVICE_GAMEPAD }, + { 0, 0 }, + }; + + static const struct retro_controller_description pads4[] = { + { "Auto", RETRO_DEVICE_AUTO }, + { "Gamepad", RETRO_DEVICE_GAMEPAD }, + { 0, 0 }, + }; + + static const struct retro_controller_description pads5[] = { + { "Auto", RETRO_DEVICE_FC_AUTO }, + { "Arkanoid", RETRO_DEVICE_FC_ARKANOID }, + { "(Bandai) Hyper Shot", RETRO_DEVICE_FC_SHADOW }, + { "Oeka Kids Tablet", RETRO_DEVICE_FC_OEKAKIDS }, + { "4-Player Adapter", RETRO_DEVICE_FC_4PLAYERS }, + { 0, 0 }, }; static const struct retro_controller_info ports[] = { { pads1, 3 }, { pads2, 4 }, - { 0 }, + { pads3, 2 }, + { pads4, 2 }, + { pads5, 5 }, + { 0, 0 }, }; environ_cb = cb; @@ -642,16 +836,16 @@ void retro_get_system_info(struct retro_system_info *info) void retro_get_system_av_info(struct retro_system_av_info *info) { #ifdef PSP - unsigned width = use_overscan ? 256 : (256 - 16); - unsigned height = use_overscan ? 240 : (240 - 16); + unsigned width = NES_WIDTH - (use_overscan ? 16 : 0); + unsigned height = NES_HEIGHT - (use_overscan ? 16 : 0); #else - unsigned width = 256 - (overscan_h ? 16 : 0); - unsigned height = 240 - (overscan_v ? 16 : 0); + unsigned width = NES_WIDTH - (overscan_h ? 16 : 0); + unsigned height = NES_HEIGHT - (overscan_v ? 16 : 0); #endif info->geometry.base_width = width; info->geometry.base_height = height; - info->geometry.max_width = width; - info->geometry.max_height = height; + info->geometry.max_width = NES_WIDTH; + info->geometry.max_height = NES_HEIGHT; info->geometry.aspect_ratio = (float)(use_par ? NES_8_7_PAR : NES_4_3); info->timing.sample_rate = (float)sndsamplerate; if (FSettings.PAL || dendy) @@ -681,6 +875,20 @@ void retro_init(void) if(environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) log_cb.log(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); #endif + + /* initialize some of the default variables */ +#ifdef GEKKO + sndsamplerate = 32000; +#else + sndsamplerate = 48000; +#endif + sndquality = 0; + sndvolume = 150; + swapDuty = 0; + + /* Wii: initialize this or else last variable is passed through + * when loading another rom causing save state size change. */ + serialize_size = 0; } static void retro_set_custom_palette(void) @@ -690,27 +898,24 @@ static void retro_set_custom_palette(void) ipalette = 0; use_raw_palette = false; - if (!current_palette || current_palette > MAXPAL || (GameInfo->type == GIT_VSUNI)) + if (current_palette == PAL_DEFAULT || current_palette == PAL_CUSTOM + || (GameInfo->type == GIT_VSUNI)) { - if (current_palette > MAXPAL && GameInfo->type != GIT_VSUNI) + if (current_palette == PAL_CUSTOM) { - if (external_palette_exist) - { - ipalette = 1; - } + if (external_palette_exist && (GameInfo->type != GIT_VSUNI)) + ipalette = 1; } - FCEU_ResetPalette(); /* Do palette reset. Priority will be: - * -ipalette : sets external palette - * -ntsccol : sets ntsc to default palette. - * If none of the above are true, then - * default palette will be used. - * VS Uniystem should always use default palette. + FCEU_ResetPalette(); /* if ipalette is set to 1, external palette + * is loaded when FCEU_ResetPalette is called, + * else it will load default NES palette. + * VS Unisystem should always use default palette. */ return; } - if (current_palette == MAXPAL) /* raw palette */ + if (current_palette == PAL_RAW) /* raw palette */ { use_raw_palette = true; for (i = 0; i < 64; i++) @@ -726,14 +931,21 @@ static void retro_set_custom_palette(void) for ( i = 0; i < 64; i++ ) { - r = palettes[current_palette-1].data[i] >> 16; - g = ( palettes[current_palette-1].data[i] & 0xff00 ) >> 8; - b = ( palettes[current_palette-1].data[i] & 0xff ); + unsigned palette_data = palettes[current_palette].data[i]; + r = ( palette_data >> 16 ) & 0xff; + g = ( ( palette_data & 0xff00 ) >> 8 ) & 0xff; + b = ( palette_data & 0xff ); FCEUD_SetPalette( i, r, g, b); - FCEUD_SetPalette( i+64, r, g, b); - FCEUD_SetPalette( i+128, r, g, b); - FCEUD_SetPalette( i+192, r, g, b); + FCEUD_SetPalette( i + 64, r, g, b); + FCEUD_SetPalette( i + 128, r, g, b); + FCEUD_SetPalette( i + 192, r, g, b); } + +#if defined(RENDER_GSKIT_PS2) + if (ps2) { + ps2->updatedPalette = true; + } +#endif } /* Set variables for NTSC(1) / PAL(2) / Dendy(3) @@ -787,6 +999,10 @@ void retro_deinit (void) free(fceu_video_out); fceu_video_out = NULL; #endif +#if defined(RENDER_GSKIT_PS2) + ps2 = NULL; +#endif + } void retro_reset(void) @@ -809,71 +1025,20 @@ static const keymap bindmap[] = { { RETRO_DEVICE_ID_JOYPAD_DOWN, JOY_DOWN }, { RETRO_DEVICE_ID_JOYPAD_LEFT, JOY_LEFT }, { RETRO_DEVICE_ID_JOYPAD_RIGHT, JOY_RIGHT }, +}; + +static const keymap turbomap[] = { { RETRO_DEVICE_ID_JOYPAD_X, JOY_A }, { RETRO_DEVICE_ID_JOYPAD_Y, JOY_B }, }; -/* Set NES controllers */ -void set_input_nes_controller(unsigned port, int x) +static void set_apu_channels(int chan) { - switch (x) - { - case SI_NONE: - input_type[port] = RETRO_DEVICE_NONE; - FCEUI_SetInput(port, SI_NONE, NULL, 0); - FCEU_printf(" Player %u: None\n", port + 1); - break; - case SI_ZAPPER: - input_type[port] = RETRO_DEVICE_ZAPPER; - FCEUI_SetInput(port, SI_ZAPPER, MouseData[port], 1); - FCEU_printf(" Player %u: Zapper\n", port + 1); - break; - case SI_ARKANOID: - input_type[port] = RETRO_DEVICE_ARKANOID; - FCEUI_SetInput(port, SI_ARKANOID, MouseData[port], 0); - FCEU_printf(" Player %u: Arkanoid\n", port + 1); - break; - case SI_GAMEPAD: /* Set gamepad as default when an unsupported device */ - default: /* is used */ - input_type[port] = RETRO_DEVICE_GAMEPAD; - FCEUI_SetInput(port, SI_GAMEPAD, &JSReturn, 0); - FCEU_printf(" Player %u: Gamepad\n", port + 1); - break; - } - - if (enable_4player) // check if 4-player mode is enabled - input_type[2] = input_type[3] = RETRO_DEVICE_GAMEPAD; -} - -/* Set Famicom controllers */ -void set_input_famicom_controller(int x) -{ - switch (x) - { - case SIFC_ARKANOID: - input_type[4] = RETRO_DEVICE_FC_ARKANOID; - FCEUI_SetInputFC(SIFC_ARKANOID, fc_MouseData, 0); - FCEU_printf("Famicom Expansion: Arkanoid\n"); - break; - case SIFC_SHADOW: - input_type[4] = RETRO_DEVICE_FC_SHADOW; - FCEUI_SetInputFC(SIFC_SHADOW, fc_MouseData, 1); - FCEU_printf("Famicom Expansion: (Bandai) Hyper Shot\n"); - break; - case SIFC_OEKAKIDS: - input_type[4] = RETRO_DEVICE_FC_OEKAKIDS; - FCEUI_SetInputFC(SIFC_OEKAKIDS, fc_MouseData, 1); - FCEU_printf("Famicom Expansion: Oeka Kids Tablet\n"); - break; - default: - /* Do not disable port if a 4-player adaptor is used */ - if (!enable_4player) - { - input_type[4] = 0; - FCEUI_SetInputFC(SIFC_NONE, NULL, 0); - break; - } - } + FSettings.SquareVolume[1] = 256 * ((chan >> 0) & 1); + FSettings.SquareVolume[0] = 256 * ((chan >> 1) & 1); + FSettings.TriangleVolume = 256 * ((chan >> 2) & 1); + FSettings.NoiseVolume = 256 * ((chan >> 3) & 1); + FSettings.PCMVolume = 256 * ((chan >> 4) & 1); } static void check_variables(bool startup) @@ -881,6 +1046,8 @@ static void check_variables(bool startup) struct retro_variable var = {0}; struct retro_system_av_info av_info; bool geometry_update = false; + char key[256]; + int i, enable_apu; var.key = "fceumm_palette"; @@ -889,43 +1056,43 @@ static void check_variables(bool startup) unsigned orig_value = current_palette; if (!strcmp(var.value, "default")) - current_palette = 0; - else if (!strcmp(var.value, "asqrealc")) - current_palette = 1; - else if (!strcmp(var.value, "nintendo-vc")) - current_palette = 2; - else if (!strcmp(var.value, "rgb")) - current_palette = 3; - else if (!strcmp(var.value, "yuv-v3")) - current_palette = 4; - else if (!strcmp(var.value, "unsaturated-final")) - current_palette = 5; - else if (!strcmp(var.value, "sony-cxa2025as-us")) - current_palette = 6; - else if (!strcmp(var.value, "pal")) - current_palette = 7; - else if (!strcmp(var.value, "bmf-final2")) - current_palette = 8; - else if (!strcmp(var.value, "bmf-final3")) - current_palette = 9; - else if (!strcmp(var.value, "smooth-fbx")) - current_palette = 10; - else if (!strcmp(var.value, "composite-direct-fbx")) - current_palette = 11; - else if (!strcmp(var.value, "pvm-style-d93-fbx")) - current_palette = 12; - else if (!strcmp(var.value, "ntsc-hardware-fbx")) - current_palette = 13; - else if (!strcmp(var.value, "nes-classic-fbx-fs")) - current_palette = 14; - else if (!strcmp(var.value, "nescap")) - current_palette = 15; - else if (!strcmp(var.value, "wavebeam")) - current_palette = 16; + current_palette = PAL_DEFAULT; else if (!strcmp(var.value, "raw")) - current_palette = MAXPAL; + current_palette = PAL_RAW; else if (!strcmp(var.value, "custom")) - current_palette = MAXPAL+1; + current_palette = PAL_CUSTOM; + else if (!strcmp(var.value, "asqrealc")) + current_palette = 0; + else if (!strcmp(var.value, "nintendo-vc")) + current_palette = 1; + else if (!strcmp(var.value, "rgb")) + current_palette = 2; + else if (!strcmp(var.value, "yuv-v3")) + current_palette = 3; + else if (!strcmp(var.value, "unsaturated-final")) + current_palette = 4; + else if (!strcmp(var.value, "sony-cxa2025as-us")) + current_palette = 5; + else if (!strcmp(var.value, "pal")) + current_palette = 6; + else if (!strcmp(var.value, "bmf-final2")) + current_palette = 7; + else if (!strcmp(var.value, "bmf-final3")) + current_palette = 8; + else if (!strcmp(var.value, "smooth-fbx")) + current_palette = 9; + else if (!strcmp(var.value, "composite-direct-fbx")) + current_palette = 10; + else if (!strcmp(var.value, "pvm-style-d93-fbx")) + current_palette = 11; + else if (!strcmp(var.value, "ntsc-hardware-fbx")) + current_palette = 12; + else if (!strcmp(var.value, "nes-classic-fbx-fs")) + current_palette = 13; + else if (!strcmp(var.value, "nescap")) + current_palette = 14; + else if (!strcmp(var.value, "wavebeam")) + current_palette = 15; if (current_palette != orig_value) retro_set_custom_palette(); @@ -1051,13 +1218,19 @@ static void check_variables(bool startup) { unsigned i; - for (i = 0; i < MAX_PLAYERS; i++) - turbo_enabler[i] = 0; + turbo_enabler[0] = 0; + turbo_enabler[1] = 0; if (!strcmp(var.value, "Player 1")) + { turbo_enabler[0] = 1; + turbo_enabler[1] = 0; + } else if (!strcmp(var.value, "Player 2")) + { + turbo_enabler[0] = 0; turbo_enabler[1] = 1; + } else if (!strcmp(var.value, "Both")) { turbo_enabler[0] = 1; @@ -1088,7 +1261,6 @@ static void check_variables(bool startup) FCEUD_RegionOverride(setregion); } - var.key = "fceumm_aspect"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -1140,6 +1312,27 @@ static void check_variables(bool startup) swapDuty = newval; } } + +#ifdef DEBUG + var.key = key; + + enable_apu = 0; + + strcpy(key, "fceumm_apu_x"); + for (i = 0; i < 5; i++) + { + key[strlen("fceumm_apu_")] = '1' + i; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && !strcmp(var.value, "disabled")) + { + enable_apu |= (1 << i); + } + } + set_apu_channels(enable_apu ^ 0xff); +#else + set_apu_channels(0xff); +#endif + } static int mzx = 0, mzy = 0; @@ -1226,55 +1419,58 @@ void get_mouse_input(unsigned port, uint32_t *zapdata) * each player */ +#define MAX_BUTTONS 8 #define TURBO_BUTTONS 2 unsigned char turbo_button_toggle[MAX_PLAYERS][TURBO_BUTTONS] = { {0} }; static void FCEUD_UpdateInput(void) { - unsigned player, port, i; + unsigned player, port; poll_cb(); JSReturn = 0; - // nes gamepad + /* nes gamepad */ for (player = 0; player < MAX_PLAYERS; player++) { - uint8_t input_buf = 0; - bool player_enabled = (input_type[player] == RETRO_DEVICE_GAMEPAD); + int i = 0; + uint8_t input_buf = 0; + int player_enabled = (input_type[player] == RETRO_DEVICE_GAMEPAD) || (input_type[player] == RETRO_DEVICE_JOYPAD); - for (i = 0; i < 8; i++) - input_buf |= (player_enabled && input_cb(player, RETRO_DEVICE_JOYPAD, 0, - bindmap[i].retro)) ? bindmap[i].nes : 0; - - /* Turbo A and Turbo B buttons are - * mapped to Joypad X and Joypad Y - * in RetroArch joypad. - * - * We achieve this by keeping track of - * the number of times it increments - * the toggle counter and fire or not fire - * depending on whether the delay value has - * been reached. - */ - - if (turbo_enabler[player] == 1 && player_enabled) + if (player_enabled) { - /* Handle Turbo A & B buttons */ - for (i = 8; i < 10; i++) + for (i = 0; i < MAX_BUTTONS; i++) + input_buf |= input_cb(player, RETRO_DEVICE_JOYPAD, 0, + bindmap[i].retro) ? bindmap[i].nes : 0; + + /* Turbo A and Turbo B buttons are + * mapped to Joypad X and Joypad Y + * in RetroArch joypad. + * + * We achieve this by keeping track of + * the number of times it increments + * the toggle counter and fire or not fire + * depending on whether the delay value has + * been reached. + */ + + if (turbo_enabler[player]) { - if (input_cb(player, RETRO_DEVICE_JOYPAD, 0, bindmap[i].retro)) + /* Handle Turbo A & B buttons */ + for (i = 0; i < TURBO_BUTTONS; i++) { - if (turbo_button_toggle[player][i-8] == 0) - input_buf |= bindmap[i].nes; - turbo_button_toggle[player][i-8]++; - if (turbo_button_toggle[player][i-8] > turbo_delay) - /* Reset the toggle if delay value is reached */ - turbo_button_toggle[player][i-8] = 0; + if (input_cb(player, RETRO_DEVICE_JOYPAD, 0, turbomap[i].retro)) + { + if (!turbo_button_toggle[player][i]) + input_buf |= turbomap[i].nes; + turbo_button_toggle[player][i]++; + turbo_button_toggle[player][i] %= turbo_delay + 1; + } + else + /* If the button is not pressed, just reset the toggle */ + turbo_button_toggle[player][i] = 0; } - else - /* If the button is not pressed, just reset the toggle */ - turbo_button_toggle[player][i-8] = 0; } } @@ -1289,7 +1485,6 @@ static void FCEUD_UpdateInput(void) } JSReturn |= (input_buf & 0xff) << (player << 3); - } /* other inputs*/ @@ -1382,6 +1577,37 @@ static void retro_run_blit(uint8_t *gfx) sceGuFinish(); video_cb(texture_vram_p, width, height, 256); +#elif defined(RENDER_GSKIT_PS2) + uint32_t *buf = (uint32_t *)RETRO_HW_FRAME_BUFFER_VALID; + + if (!ps2) { + if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&ps2) || !ps2) { + printf("Failed to get HW rendering interface!\n"); + return; + } + + if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) { + printf("HW render interface mismatch, expected %u, got %u!\n", + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version); + return; + } + + ps2->coreTexture->Width = width; + ps2->coreTexture->Height = height; + ps2->coreTexture->PSM = GS_PSM_T8; + ps2->coreTexture->ClutPSM = GS_PSM_CT16; + ps2->coreTexture->Filter = GS_FILTER_LINEAR; + ps2->padding = (struct retro_hw_ps2_insets){ overscan_v ? 8.0f : 0.0f, + overscan_h ? 8.0f : 0.0f, + overscan_v ? 8.0f : 0.0f, + overscan_h ? 8.0f : 0.0f}; + } + + ps2->updatedPalette = true; + ps2->coreTexture->Clut = (u32*)retro_palette; + ps2->coreTexture->Mem = (u32*)gfx; + + video_cb(buf, width, height, pitch); #else incr += (overscan_h ? 16 : 0); width -= (overscan_h ? 16 : 0); @@ -1408,8 +1634,6 @@ static void retro_run_blit(uint8_t *gfx) #endif } -static bool firstrun = true; - void retro_run(void) { unsigned i; @@ -1417,13 +1641,6 @@ void retro_run(void) int32_t ssize = 0; bool updated = false; - if (firstrun) - { - /* setup famicom expansion devices */ - set_input_famicom_controller(GameInfo->inputfc); - firstrun = false; - } - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) check_variables(false); @@ -1438,8 +1655,6 @@ void retro_run(void) retro_run_blit(gfx); } -static unsigned serialize_size = 0; - size_t retro_serialize_size(void) { if (serialize_size == 0) @@ -1763,7 +1978,14 @@ static const struct cartridge_db famicom_4p_db_list[] = } }; +#ifdef _WIN32 +static char slash = '\\'; +#else +static char slash = '/'; +#endif + extern uint32_t iNESGameCRC32; +extern int option_ramstate; bool retro_load_game(const struct retro_game_info *game) { @@ -1826,10 +2048,25 @@ bool retro_load_game(const struct retro_game_info *game) struct retro_memory_descriptor descs[64]; struct retro_memory_map mmaps; + struct retro_variable var = {0}; if (!game) return false; + var.value = 0; + var.key = "fceumm_ramstate"; + + /* set this variable before calling PowerNES() */ + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "random")) + option_ramstate = 2; + else if (!strcmp(var.value, "fill $00")) + option_ramstate = 1; + else + option_ramstate = 0; + } + PowerNES(); check_system_specs(); #if defined(_3DS) @@ -1864,17 +2101,14 @@ bool retro_load_game(const struct retro_game_info *game) return false; } - for (i = 0; i < MAX_PORTS; i++) + for (i = 0; i < MAX_PORTS; i++) { FCEUI_SetInput(i, SI_GAMEPAD, &JSReturn, 0); + input_type[i] == RETRO_DEVICE_JOYPAD; + } external_palette_exist = ipalette; if (external_palette_exist) - FCEU_printf("nes.pal loaded from system directory.\n"); - else - FCEU_PrintError("Cannot find nes.pal from system directory.\n"); - - if (GameInfo->type == GIT_VSUNI) - FCEU_PrintError("VS Unisystem rom loaded, will use default palette.\n"); + FCEU_printf(" Loading custom palette: %s%cnes.pal\n", dir, slash); is_PAL = retro_get_region(); /* Save current loaded region info */ @@ -1899,6 +2133,7 @@ bool retro_load_game(const struct retro_game_info *game) { if (famicom_4p_db_list[i].crc == iNESGameCRC32) { + GameInfo->inputfc = SIFC_4PLAYER; FCEUI_SetInputFC(SIFC_4PLAYER, &JSReturn, 0); enable_4player = true; break; @@ -1946,6 +2181,9 @@ void retro_unload_game(void) free(fceu_video_out); fceu_video_out = NULL; #endif +#if defined(RENDER_GSKIT_PS2) + ps2 = NULL; +#endif } unsigned retro_get_region(void) @@ -1953,7 +2191,6 @@ unsigned retro_get_region(void) return FSettings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; } - void *retro_get_memory_data(unsigned type) { uint8_t* data; @@ -1961,10 +2198,12 @@ void *retro_get_memory_data(unsigned type) switch(type) { case RETRO_MEMORY_SAVE_RAM: - if (iNESCart.battery) + if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) return iNESCart.SaveGame[0]; - else if (UNIFCart.battery) + else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0]) return UNIFCart.SaveGame[0]; + else if (GameInfo->type == GIT_FDS) + return FDSROM_ptr(); else data = NULL; break; @@ -1986,10 +2225,12 @@ size_t retro_get_memory_size(unsigned type) switch(type) { case RETRO_MEMORY_SAVE_RAM: - if (iNESCart.battery) + if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) size = iNESCart.SaveGameLen[0]; - else if (UNIFCart.battery) + else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0]) size = UNIFCart.SaveGameLen[0]; + else if (GameInfo->type == GIT_FDS) + size = FDSROM_size(); else size = 0; break; diff --git a/src/fceu-endian.c b/src/fceu-endian.c index 754489f..cfe35d9 100644 --- a/src/fceu-endian.c +++ b/src/fceu-endian.c @@ -31,7 +31,10 @@ void FlipByteOrder(uint8 *src, uint32 count) uint8 *start = src; uint8 *end = src + count - 1; - while(start < end) + if ((count & 1) || !count) + return; /* This shouldn't happen. */ + + while (count--) { uint8 tmp; diff --git a/src/fceu-memory.c b/src/fceu-memory.c index 0e38cc8..6dfecfe 100644 --- a/src/fceu-memory.c +++ b/src/fceu-memory.c @@ -19,6 +19,7 @@ */ #include +#include #include "fceu-types.h" #include "fceu.h" diff --git a/src/fceu-types.h b/src/fceu-types.h index dda3a8e..53c5ec5 100644 --- a/src/fceu-types.h +++ b/src/fceu-types.h @@ -53,6 +53,19 @@ typedef unsigned long long uint64; typedef long long int64; #endif +#ifndef INLINE + +#if defined(_MSC_VER) +#define INLINE __forceinline +#elif defined(__GNUC__) +#define INLINE __inline__ +#elif defined(_MWERKS_) +#define INLINE inline +#else +#define INLINE +#endif +#endif + #if PSS_STYLE == 2 #define PSS "\\" diff --git a/src/fceu.c b/src/fceu.c index 6ede5fc..4f87771 100644 --- a/src/fceu.c +++ b/src/fceu.c @@ -381,6 +381,8 @@ void ResetNES(void) X6502_Reset(); } +int option_ramstate = 0; + void FCEU_MemoryRand(uint8 *ptr, uint32 size) { int x = 0; @@ -394,7 +396,14 @@ void FCEU_MemoryRand(uint8 *ptr, uint32 size) *ptr = (x & 1) ? 0x55 : 0xAA; /* F-15 Sity War HISCORE is screwed... */ /* 1942 SCORE/HISCORE is screwed... */ #endif - *ptr = 0xFF; + uint8_t v; + switch (option_ramstate) + { + case 0: v = 0xff; break; + case 1: v = 0x00; break; + case 2: v = (uint8_t)rand(); break; + } + *ptr = v; x++; size--; ptr++; diff --git a/src/fceu.h b/src/fceu.h index b15d374..f50c5c0 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -83,6 +83,10 @@ typedef struct { int PAL; int NetworkPlay; int SoundVolume; + int TriangleVolume; + int SquareVolume[2]; + int NoiseVolume; + int PCMVolume; int GameGenie; /* Current first and last rendered scanlines. */ diff --git a/src/fds.c b/src/fds.c index 775118a..2dc76a6 100644 --- a/src/fds.c +++ b/src/fds.c @@ -62,6 +62,8 @@ static uint8 FDSRegs[6]; static int32 IRQLatch, IRQCount; static uint8 IRQa; +static uint8 *FDSROM = NULL; +static uint32 FDSROMSize = 0; static uint8 *FDSRAM = NULL; static uint32 FDSRAMSize; static uint8 *FDSBIOS = NULL; @@ -71,7 +73,6 @@ static uint32 CHRRAMSize; /* Original disk data backup, to help in creating save states. */ static uint8 *diskdatao[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - static uint8 *diskdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static uint32 TotalSides; @@ -84,6 +85,15 @@ static uint8 SelectDisk, InDisk; uint32 lastDiskPtrRead, lastDiskPtrWrite; #define DC_INC 1 +#define BYTES_PER_SIDE 65500 + +uint8 *FDSROM_ptr(void) { + return (FDSROM); +} + +uint32 FDSROM_size(void) { + return (FDSROMSize); +} void FDSGI(int h) { switch (h) { @@ -142,10 +152,12 @@ static void FDSInit(void) { void FCEU_FDSInsert(int oride) { if (InDisk == 255) { - FCEU_DispMessage("Disk %d Side %s Inserted", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); + FCEU_DispMessage("Disk %d of %d Side %s Inserted", + 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); InDisk = SelectDisk; } else { - FCEU_DispMessage("Disk %d Side %s Ejected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); + FCEU_DispMessage("Disk %d of %d Side %s Ejected", + 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); InDisk = 255; } } @@ -160,21 +172,23 @@ void FCEU_FDSSelect(void) { return; } SelectDisk = ((SelectDisk + 1) % TotalSides) & 3; - FCEU_DispMessage("Disk %d Side %s Selected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); + FCEU_DispMessage("Disk %d of %d Side %s Selected", + 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); } +/* 2018/12/15 - update irq timings */ static void FP_FASTAPASS(1) FDSFix(int a) { - if ((IRQa & 2) && IRQCount) { - IRQCount -= a; + if ((IRQa & 2) && (FDSRegs[3] & 0x1)) { if (IRQCount <= 0) { - if (!(IRQa & 1)) { - IRQa &= ~2; - IRQCount = IRQLatch = 0; - } else - IRQCount = IRQLatch; + if (!(IRQa & 1)) + IRQa &= ~2; /* does not clear latch, fix Druid */ + IRQCount = IRQLatch; X6502_IRQBegin(FCEU_IQEXT); + } else { + IRQCount -= a; } } + if (DiskSeekIRQ > 0) { DiskSeekIRQ -= a; if (DiskSeekIRQ <= 0) { @@ -492,20 +506,29 @@ void FDSSoundReset(void) { static DECLFW(FDSWrite) { switch (A) { case 0x4020: - X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0x4021: - X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xFF; IRQLatch |= V << 8; break; case 0x4022: - X6502_IRQEnd(FCEU_IQEXT); - IRQCount = IRQLatch; - IRQa = V & 3; + if (FDSRegs[3] & 0x1) { + IRQa = (V & 0x3); + if (IRQa & 2) { + IRQCount = IRQLatch; + } else { + X6502_IRQEnd(FCEU_IQEXT); + X6502_IRQEnd(FCEU_IQEXT2); + } + } break; + case 0x4023: + if (!(V & 1)) { + X6502_IRQEnd(FCEU_IQEXT); + X6502_IRQEnd(FCEU_IQEXT2); + } case 0x4024: if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) { if (DiskPtr >= 0 && DiskPtr < 65500) { @@ -541,14 +564,180 @@ static DECLFW(FDSWrite) { FDSRegs[A & 7] = V; } -static void FreeFDSMemory(void) { - int x; +struct codes_t { + uint8 code; + char *name; +}; - for (x = 0; x < TotalSides; x++) - if (diskdata[x]) { - free(diskdata[x]); - diskdata[x] = 0; +static const struct codes_t list[] = { + { 0x01, "Nintendo" }, + { 0x02, "Rocket Games" }, + { 0x08, "Capcom" }, + { 0x09, "Hot B Co." }, + { 0x0A, "Jaleco" }, + { 0x0B, "Coconuts Japan" }, + { 0x0C, "Coconuts Japan/G.X.Media" }, + { 0x13, "Electronic Arts Japan" }, + { 0x18, "Hudson Soft Japan" }, + { 0x19, "S.C.P." }, + { 0x1A, "Yonoman" }, + { 0x20, "Destination Software" }, + { 0x22, "VR 1 Japan" }, + { 0x25, "San-X" }, + { 0x28, "Kemco Japan" }, + { 0x29, "Seta" }, + { 0x36, "Codemasters" }, + { 0x37, "GAGA Communications" }, + { 0x38, "Laguna" }, + { 0x39, "Telstar Fun and Games" }, + { 0x41, "Ubi Soft Entertainment" }, + { 0x42, "Sunsoft" }, + { 0x47, "Spectrum Holobyte" }, + { 0x49, "Irem" }, + { 0x4A, "Gakken" }, + { 0x4D, "Malibu Games" }, + { 0x4F, "Eidos/U.S. Gold" }, + { 0x50, "Absolute Entertainment" }, + { 0x51, "Acclaim" }, + { 0x52, "Activision" }, + { 0x53, "American Sammy Corp." }, + { 0x54, "Take 2 Interactive" }, + { 0x55, "Hi Tech" }, + { 0x56, "LJN LTD." }, + { 0x58, "Mattel" }, + { 0x5A, "Mindscape/Red Orb Ent." }, + { 0x5C, "Taxan" }, + { 0x5D, "Midway" }, + { 0x5F, "American Softworks" }, + { 0x60, "Titus Interactive Studios" }, + { 0x61, "Virgin Interactive" }, + { 0x62, "Maxis" }, + { 0x64, "LucasArts Entertainment" }, + { 0x67, "Ocean" }, + { 0x69, "Electronic Arts" }, + { 0x6E, "Elite Systems Ltd." }, + { 0x6F, "Electro Brain" }, + { 0x70, "Infogrames" }, + { 0x71, "Interplay" }, + { 0x72, "JVC Musical Industries Inc" }, + { 0x73, "Parker Brothers" }, + { 0x75, "SCI" }, + { 0x78, "THQ" }, + { 0x79, "Accolade" }, + { 0x7A, "Triffix Ent. Inc." }, + { 0x7C, "Microprose Software" }, + { 0x7D, "Universal Interactive Studios" }, + { 0x7F, "Kemco" }, + { 0x80, "Misawa" }, + { 0x83, "LOZC" }, + { 0x8B, "Bulletproof Software" }, + { 0x8C, "Vic Tokai Inc." }, + { 0x91, "Chun Soft" }, + { 0x92, "Video System" }, + { 0x93, "BEC" }, + { 0x96, "Yonezawa/S'pal" }, + { 0x97, "Kaneko" }, + { 0x99, "Victor Interactive Software" }, + { 0x9A, "Nichibutsu/Nihon Bussan" }, + { 0x9B, "Tecmo" }, + { 0x9C, "Imagineer" }, + { 0x9F, "Nova" }, + { 0xA0, "Telenet" }, + { 0xA1, "Hori" }, + { 0xA2, "Scorpion Soft " }, + { 0xA4, "Konami" }, + { 0xA6, "Kawada" }, + { 0xA7, "Takara" }, + { 0xA8, "Royal Industries" }, + { 0xA9, "Technos Japan Corp." }, + { 0xAA, "JVC" }, + { 0xAC, "Toei Animation" }, + { 0xAD, "Toho" }, + { 0xAF, "Namco" }, + { 0xB0, "Acclaim Japan" }, + { 0xB1, "ASCII" }, + { 0xB2, "Bandai" }, + { 0xB3, "Soft Pro Inc." }, + { 0xB4, "Enix" }, + { 0xB6, "HAL Laboratory" }, + { 0xB7, "SNK" }, + { 0xB9, "Pony Canyon Hanbai" }, + { 0xBA, "Culture Brain" }, + { 0xBB, "Sunsoft" }, + { 0xBC, "Toshiba EMI" }, + { 0xBD, "Sony Imagesoft" }, + { 0xBF, "Sammy" }, + { 0xC0, "Taito" }, + { 0xC1, "Sunsoft / Ask Co., Ltd." }, + { 0xC2, "Kemco" }, + { 0xC3, "Square Soft" }, + { 0xC4, "Tokuma Shoten " }, + { 0xC5, "Data East" }, + { 0xC6, "Tonkin House" }, + { 0xC7, "East Cube" }, + { 0xC8, "Koei" }, + { 0xCA, "Konami/Palcom/Ultra" }, + { 0xCB, "Vapinc/NTVIC" }, + { 0xCC, "Use Co.,Ltd." }, + { 0xCD, "Meldac" }, + { 0xCE, "FCI/Pony Canyon" }, + { 0xCF, "Angel" }, + { 0xD1, "Sofel" }, + /*{ 0xD2, "Quest" },*/ + { 0xD2, "Bothtec, Inc." }, + { 0xD3, "Sigma Enterprises" }, + { 0xD4, "Ask Kodansa" }, + { 0xD6, "Naxat" }, + { 0xD7, "Copya System" }, + { 0xD9, "Banpresto" }, + { 0xDA, "TOMY" }, + /*{ 0xDB, "LJN Japan" },*/ + { 0xDB, "Hiro Co., Ltd." }, + { 0xDD, "NCS" }, + { 0xDF, "Altron Corporation" }, + { 0xE2, "Yutaka" }, + { 0xE3, "Varie" }, + { 0xE5, "Epoch" }, + { 0xE7, "Athena" }, + { 0xE8, "Asmik Ace Entertainment Inc." }, + { 0xE9, "Natsume" }, + { 0xEA, "King Records" }, + { 0xEB, "Atlus" }, + { 0xEC, "Epic/Sony Records" }, + { 0xEE, "IGS" }, + { 0xF0, "A Wave" }, + { 0 } + }; + +static const char *getManufacturer(uint8 code) +{ + int x = 0; + char *ret = "unlicensed"; + + while (list[x].code != 0) { + if (list[x].code == code) { + ret = list[x].name; + break; } + x++; + } + + return ret; +} + +static void FreeFDSMemory(void) { + if (FDSROM) + free(FDSROM); + FDSROM = NULL; + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + if (FDSRAM) + free(FDSRAM); + FDSRAM = NULL; + if (CHRRAM) + free(CHRRAM); + CHRRAM = NULL; } static int SubLoad(FCEUFILE *fp) { @@ -571,19 +760,21 @@ static int SubLoad(FCEUFILE *fp) { } else TotalSides = header[4]; - md5_starts(&md5); - if (TotalSides > 8) TotalSides = 8; if (TotalSides < 1) TotalSides = 1; + FDSROMSize = TotalSides * BYTES_PER_SIDE; + FDSROM = (uint8*)FCEU_malloc(FDSROMSize); + + if (!FDSROM) + return (0); + + for (x = 0; x < TotalSides; x++) + diskdata[x] = &FDSROM[x * BYTES_PER_SIDE]; + + md5_starts(&md5); + for (x = 0; x < TotalSides; x++) { - diskdata[x] = (uint8*)FCEU_malloc(65500); - if (!diskdata[x]) { - int zol; - for (zol = 0; zol < x; zol++) - free(diskdata[zol]); - return 0; - } FCEU_fread(diskdata[x], 1, 65500, fp); md5_update(&md5, diskdata[x], 65500); } @@ -623,17 +814,9 @@ int FDSLoad(const char *name, FCEUFILE *fp) { free(fn); - ResetCartMapping(); + FreeFDSMemory(); - if (FDSBIOS) - free(FDSBIOS); - FDSBIOS = NULL; - if (FDSRAM) - free(FDSRAM); - FDSRAM = NULL; - if (CHRRAM) - free(CHRRAM); - CHRRAM = NULL; + ResetCartMapping(); FDSBIOSsize = 8192; FDSBIOS = (uint8*)FCEU_gmalloc(FDSBIOSsize); @@ -643,16 +826,17 @@ int FDSLoad(const char *name, FCEUFILE *fp) { if (FDSBIOS) free(FDSBIOS); FDSBIOS = NULL; + free(zp->fp->data); FCEU_fclose(zp); FCEU_PrintError("Error reading FDS BIOS ROM image.\n"); return 0; } + free(zp->fp->data); FCEU_fclose(zp); FCEU_fseek(fp, 0, SEEK_SET); - FreeFDSMemory(); if (!SubLoad(fp)) { if (FDSBIOS) free(FDSBIOS); @@ -660,6 +844,16 @@ int FDSLoad(const char *name, FCEUFILE *fp) { return(0); } + for (x = 0; x < TotalSides; x++) { + diskdatao[x] = (uint8*)FCEU_malloc(65500); + memcpy(diskdatao[x], diskdata[x], 65500); + } + + DiskWritten = 1; + +#if 0 + /* auxillary rom loading for save file is now handled + * using retro_get_memory_size/data */ { FCEUFILE *tp; char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0); @@ -686,6 +880,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) { } free(fn); } +#endif GameInfo->type = GIT_FDS; GameInterface = FDSGI; @@ -702,7 +897,12 @@ int FDSLoad(const char *name, FCEUFILE *fp) { AddExState(diskdata[x], 65500, 0, temp); } - AddExState(FDSRegs, sizeof(FDSRegs), 0, "FREG"); + AddExState(&FDSRegs[0], 1, 0, "REG1"); + AddExState(&FDSRegs[1], 1, 0, "REG2"); + AddExState(&FDSRegs[2], 1, 0, "REG3"); + AddExState(&FDSRegs[3], 1, 0, "REG4"); + AddExState(&FDSRegs[4], 1, 0, "REG5"); + AddExState(&FDSRegs[5], 1, 0, "REG6"); AddExState(&IRQCount, 4, 1, "IRQC"); AddExState(&IRQLatch, 4, 1, "IQL1"); AddExState(&IRQa, 1, 0, "IRQA"); @@ -715,19 +915,20 @@ int FDSLoad(const char *name, FCEUFILE *fp) { CHRRAMSize = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); - memset(CHRRAM, 0, CHRRAMSize); SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); FDSRAMSize = 32768; FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize); - memset(FDSRAM, 0, FDSRAMSize); SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1); AddExState(FDSRAM, FDSRAMSize, 0, "FDSR"); SetupCartMirroring(0, 0, 0); - FCEU_printf(" Sides: %d\n\n", TotalSides); + FCEU_printf(" Code : %02x\n", diskdata[0][0xf]); + FCEU_printf(" Manufacturer : %s\n", getManufacturer(diskdata[0][0xf])); + FCEU_printf(" # of Sides : %d\n", TotalSides); + FCEU_printf(" ROM MD5 : 0x%s\n", md5_asciistr(GameInfo->MD5)); FCEUI_SetVidSystem(0); @@ -735,27 +936,10 @@ int FDSLoad(const char *name, FCEUFILE *fp) { } void FDSClose(void) { - FILE *fp; int x; - char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0); if (!DiskWritten) return; - if (!(fp = fopen(fn, "wb"))) { - free(fn); - return; - } - FCEU_printf("FDS Save \"%s\"\n", fn); - free(fn); - - for (x = 0; x < TotalSides; x++) { - if (fwrite(diskdata[x], 1, 65500, fp) != 65500) { - FCEU_PrintError("Error saving FDS image!\n"); - fclose(fp); - return; - } - } - for (x = 0; x < TotalSides; x++) if (diskdatao[x]) { free(diskdatao[x]); @@ -763,14 +947,4 @@ void FDSClose(void) { } FreeFDSMemory(); - if (FDSBIOS) - free(FDSBIOS); - FDSBIOS = NULL; - if (FDSRAM) - free(FDSRAM); - FDSRAM = NULL; - if (CHRRAM) - free(CHRRAM); - CHRRAM = NULL; - fclose(fp); } diff --git a/src/fds.h b/src/fds.h index a07dbba..236d936 100644 --- a/src/fds.h +++ b/src/fds.h @@ -1,6 +1,9 @@ #ifndef _FCEU_FDS_H #define _FCEU_FDS_H +uint8 *FDSROM_ptr(void); +uint32 FDSROM_size(void); + void FDSSoundReset(void); void FCEU_FDSInsert(int oride); diff --git a/src/file.c b/src/file.c index 02a074c..2ceb96f 100644 --- a/src/file.c +++ b/src/file.c @@ -58,8 +58,6 @@ static MEMWRAP *MakeMemWrap(void *tz, int type) fread(tmp->data, 1, tmp->size, (FILE*)tz); doret: - if (type == 0) - fclose((FILE*)tz); return tmp; } @@ -97,6 +95,7 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, fseek((FILE*)t, 0, SEEK_SET); fceufp->fp = MakeMemWrap(t, 0); + fclose((FILE*)t); } return fceufp; } diff --git a/src/filter.c b/src/filter.c index 0627058..33fa188 100644 --- a/src/filter.c +++ b/src/filter.c @@ -100,7 +100,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { #endif max = (inlen - 1) << 16; - if (FSettings.soundq == 2) + if (FSettings.soundq == 2) { for (x = mrindex; x < max; x += mrratio) { int32 acc = 0, acc2 = 0; uint32 c; @@ -116,7 +116,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { out++; count++; } - else + } else { for (x = mrindex; x < max; x += mrratio) { int32 acc = 0, acc2 = 0; uint32 c; @@ -132,6 +132,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { out++; count++; } + } mrindex = x - max; diff --git a/src/sound.c b/src/sound.c index df4b878..03646af 100644 --- a/src/sound.c +++ b/src/sound.c @@ -70,6 +70,7 @@ static int32 RectDutyCount[2]; static uint8 sweepon[2]; static int32 curfreq[2]; static uint8 SweepCount[2]; +static uint8 sweepReload[2]; static uint16 nreg = 0; @@ -84,6 +85,9 @@ int32 nesincsize = 0; uint32 soundtsinc = 0; uint32 soundtsi = 0; static int32 sqacc[2]; +static uint32 lq_tcout; +static int32 lq_triacc; +static int32 lq_noiseacc; /* LQ variables segment ends. */ static int32 lengthcount[4]; @@ -125,9 +129,9 @@ static const uint32 PALDMCTable[0x10] = * $4013 - Size register: Size in bytes = (V+1)*64 */ -/*static*/ int32 DMCacc = 1; +static int32 DMCacc = 1; static int32 DMCPeriod = 0; -/*static*/ uint8 DMCBitCount = 0; +static uint8 DMCBitCount = 0; static uint8 DMCAddressLatch = 0, DMCSizeLatch = 0; /* writes to 4012 and 4013 */ static uint8 DMCFormat = 0; /* Write to $4010 */ @@ -175,21 +179,12 @@ static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr) { } static void SQReload(int x, uint8 V) { - if (EnabledChannels & (1 << x)) { - if (x) - DoSQ2(); - else - DoSQ1(); + if (EnabledChannels & (1 << x)) lengthcount[x] = lengthtable[(V >> 3) & 0x1f]; - } - - sweepon[x] = PSG[(x << 2) | 1] & 0x80; - curfreq[x] = PSG[(x << 2) | 0x2] | ((V & 7) << 8); - SweepCount[x] = ((PSG[(x << 2) | 0x1] >> 4) & 7) + 1; + curfreq[x] = (curfreq[x] & 0xff) | ((V & 7) << 8); RectDutyCount[x] = 7; EnvUnits[x].reloaddec = 1; - /* reloadfreq[x]=1; */ } static DECLFW(Write_PSG) { @@ -200,11 +195,11 @@ static DECLFW(Write_PSG) { DoSQ1(); EnvUnits[0].Mode = (V & 0x30) >> 4; EnvUnits[0].Speed = (V & 0xF); - if (swapDuty) - V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); break; case 0x1: - sweepon[0] = V & 0x80; + DoSQ1(); + sweepReload[0] = 1; + sweepon[0] = (V & 0x80); break; case 0x2: DoSQ1(); @@ -212,17 +207,18 @@ static DECLFW(Write_PSG) { curfreq[0] |= V; break; case 0x3: + DoSQ1(); SQReload(0, V); break; case 0x4: DoSQ2(); EnvUnits[1].Mode = (V & 0x30) >> 4; EnvUnits[1].Speed = (V & 0xF); - if (swapDuty) - V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); break; case 0x5: - sweepon[1] = V & 0x80; + DoSQ2(); + sweepReload[1] = 1; + sweepon[1] = (V & 0x80); break; case 0x6: DoSQ2(); @@ -230,6 +226,7 @@ static DECLFW(Write_PSG) { curfreq[1] |= V; break; case 0x7: + DoSQ2(); SQReload(1, V); break; case 0xa: @@ -288,17 +285,17 @@ static DECLFW(Write_DMCRegs) { break; case 0x01: DoPCM(); RawDALatch = V & 0x7F; - if (RawDALatch) - DMC_7bit = 1; + if (RawDALatch) + DMC_7bit = 1; break; case 0x02: - DMCAddressLatch = V; - if (V) + DMCAddressLatch = V; + if (V) DMC_7bit = 0; - break; + break; case 0x03: - DMCSizeLatch = V; - if (V) + DMCSizeLatch = V; + if (V) DMC_7bit = 0; break; } @@ -313,6 +310,7 @@ static DECLFW(StatusWrite) { DoTriangle(); DoNoise(); DoPCM(); + for (x = 0; x < 4; x++) if (!(V & (1 << x))) lengthcount[x] = 0; /* Force length counters to 0. */ @@ -336,9 +334,9 @@ static DECLFR(StatusRead) { for (x = 0; x < 4; x++) ret |= lengthcount[x] ? (1 << x) : 0; if (DMCSize) ret |= 0x10; - #ifdef FCEUDEF_DEBUGGER + #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif + #endif { SIRQStat &= ~0x40; X6502_IRQEnd(FCEU_IQFCOUNT); @@ -371,34 +369,25 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { /* Frequency Sweep Code Here */ /* xxxx 0000 */ /* xxxx = hz. 120/(x+1)*/ - if (sweepon[P]) { - int32 mod = 0; - - if (SweepCount[P] > 0) SweepCount[P]--; - if (SweepCount[P] <= 0) { - SweepCount[P] = ((PSG[(P << 2) + 0x1] >> 4) & 7) + 1; /* +1; */ + /* http://wiki.nesdev.com/w/index.php/APU_Sweep */ + if (SweepCount[P] > 0) SweepCount[P]--; + if (SweepCount[P] <= 0) { + uint32 sweepShift = (PSG[(P << 2) + 0x1] & 7); + if (sweepon[P] && sweepShift && curfreq[P] >= 8) { + int32 mod = (curfreq[P] >> sweepShift); if (PSG[(P << 2) + 0x1] & 0x8) { - mod -= (P ^ 1) + ((curfreq[P]) >> (PSG[(P << 2) + 0x1] & 7)); - if (curfreq[P] && (PSG[(P << 2) + 0x1] & 7) /* && sweepon[P]&0x80*/) { - curfreq[P] += mod; - } - } else { - mod = curfreq[P] >> (PSG[(P << 2) + 0x1] & 7); - if ((mod + curfreq[P]) & 0x800) { - sweepon[P] = 0; - curfreq[P] = 0; - } else { - if (curfreq[P] && (PSG[(P << 2) + 0x1] & 7) /* && sweepon[P]&0x80*/) { - curfreq[P] += mod; - } - } + curfreq[P] -= (mod + (P ^ 1)); + } else if ((mod + curfreq[P]) < 0x800) { + curfreq[P] += mod; } } - } else {/* Sweeping is disabled: */ -#if 0 - curfreq[P]&=0xFF00; - curfreq[P]|=PSG[(P<<2)|0x2]; /* |((PSG[(P<<2)|3]&7)<<8); */ -#endif + + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + } + + if (sweepReload[P]) { + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + sweepReload[P] = 0; } } } @@ -437,19 +426,21 @@ void FrameSoundUpdate(void) { * Length counter: Bit 4-7 of $4003, $4007, $400b, $400f */ - if (!fcnt && !(IRQFrameMode & 0x3)) { - SIRQStat |= 0x40; - X6502_IRQBegin(FCEU_IQFCOUNT); - } - if (fcnt == 3) { if (IRQFrameMode & 0x2) fhcnt += fhinc; } + FrameSoundStuff(fcnt); fcnt = (fcnt + 1) & 3; -} + /* has to be moved here to fix Dragon Warrior 4 + * after irq inhibit fix for $4017 */ + if (!fcnt && !(IRQFrameMode & 0x3)) { + SIRQStat |= 0x40; + X6502_IRQBegin(FCEU_IQFCOUNT); + } +} static INLINE void tester(void) { if (DMCBitCount == 0) { @@ -476,9 +467,10 @@ static INLINE void DMCDMA(void) { if (DMCFormat & 0x40) PrepDPCM(); else { - SIRQStat |= 0x80; - if (DMCFormat & 0x80) + if (DMCFormat & 0x80) { + SIRQStat |= 0x80; X6502_IRQBegin(FCEU_IQDPCM); + } } } } @@ -520,7 +512,8 @@ void RDoPCM(void) { uint32 V; for (V = ChannelBC[4]; V < SOUNDTS; V++) - WaveHi[V] += RawDALatch << 16; + /* TODO: get rid of floating calculations to binary. set log volume scaling. */ + WaveHi[V] += (((RawDALatch << 16) / 256) * FSettings.PCMVolume ) & (~0xFFFF); ChannelBC[4] = SOUNDTS; } @@ -535,45 +528,61 @@ static INLINE void RDoSQ(int x) { int32 cf; int32 rc; - if (curfreq[x] < 8 || curfreq[x] > 0x7ff) - goto endit; - if (!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1])) - goto endit; - if (!lengthcount[x]) - goto endit; - - if (EnvUnits[x].Mode & 0x1) - amp = EnvUnits[x].Speed; - else - amp = EnvUnits[x].decvolume; -/* printf("%d\n",amp); */ - amp <<= 24; - - rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6]; - - D = &WaveHi[ChannelBC[x]]; V = SOUNDTS - ChannelBC[x]; - - currdc = RectDutyCount[x]; cf = (curfreq[x] + 1) * 2; rc = wlcount[x]; - while (V > 0) { - if (currdc < rthresh) - *D += amp; - rc--; - if (!rc) { - rc = cf; - currdc = (currdc + 1) & 7; + /* added 2018/12/08 */ + /* when pulse channel is silenced, resets length counters but not + * duty cycle, instead of resetting both */ + if ((curfreq[x] < 8 || curfreq[x] > 0x7ff) || + !CheckFreq(curfreq[x], PSG[(x << 2) | 0x1]) || + !lengthcount[x]) { + rc -= V; + if (rc <= 0) { + rc = cf - (-rc % cf); } - V--; - D++; + } else { + int dutyCycle; + + if (EnvUnits[x].Mode & 0x1) + amp = EnvUnits[x].Speed; + else + amp = EnvUnits[x].decvolume; + /* printf("%d\n",amp); */ + + /* Modify Square wave volume based on channel volume modifiers + * Note: the formulat x = x * y /100 does not yield exact results, + * but is "close enough" and avoids the need for using double values + * or implicit cohersion which are slower (we need speed here) */ + /* TODO: Optimize this. */ + if (FSettings.SquareVolume[x] != 256) + amp = (amp * FSettings.SquareVolume[x]) / 256; + + amp <<= 24; + dutyCycle = (PSG[(x << 2)] & 0xC0) >> 6; + if (swapDuty) + dutyCycle = ((dutyCycle & 2) >> 1) | ((dutyCycle & 1) << 1); + rthresh = RectDuties[dutyCycle]; + currdc = RectDutyCount[x]; + D = &WaveHi[ChannelBC[x]]; + + while (V > 0) { + if (currdc < rthresh) + *D += amp; + rc--; + if (!rc) { + rc = cf; + currdc = (currdc + 1) & 7; + } + V--; + D++; + } + + RectDutyCount[x] = currdc; } - RectDutyCount[x] = currdc; wlcount[x] = rc; - - endit: ChannelBC[x] = SOUNDTS; } @@ -604,6 +613,7 @@ static void RDoSQLQ(void) { for (x = 0; x < 2; x++) { int y; + int dutyCycle; inie[x] = nesincsize; if (curfreq[x] < 8 || curfreq[x] > 0x7ff) @@ -618,9 +628,21 @@ static void RDoSQLQ(void) { else amp[x] = EnvUnits[x].decvolume; + /* Modify Square wave volume based on channel volume modifiers + * Note: the formulat x = x * y /100 does not yield exact results, + * but is "close enough" and avoids the need for using double vales + * or implicit cohersion which are slower (we need speed here) + * fixed - setting up maximum volume for square2 caused complete mute square2 channel. + * TODO: Optimize this. */ + if (FSettings.SquareVolume[x] != 256) + amp[x] = (amp[x] * FSettings.SquareVolume[x]) / 256; + if (!inie[x]) amp[x] = 0; /* Correct? Buzzing in MM2, others otherwise... */ - rthresh[x] = RectDuties[(PSG[x * 4] & 0xC0) >> 6]; + dutyCycle = (PSG[(x << 2)] & 0xC0) >> 6; + if (swapDuty) + dutyCycle = ((dutyCycle & 2) >> 1) | ((dutyCycle & 1) << 1); + rthresh[x] = RectDuties[dutyCycle]; for (y = 0; y < 8; y++) { if (y < rthresh[x]) @@ -637,7 +659,7 @@ static void RDoSQLQ(void) { if (!inie[0] && !inie[1]) { for (V = start; V < end; V++) Wave[V >> 4] += totalout; - } else + } else { for (V = start; V < end; V++) { /* int tmpamp=0; if(RectDutyCount[0]> 0xe) & 1]; } } - else + } else { for (V = ChannelBC[3]; V < SOUNDTS; V++) { WaveHi[V] += outo; wlcount[3]--; @@ -885,6 +921,7 @@ static void RDoNoise(void) { outo = amptab[(nreg >> 0xe) & 1]; } } + } ChannelBC[3] = SOUNDTS; } @@ -893,10 +930,12 @@ DECLFW(Write_IRQFM) { fcnt = 0; if (V & 2) FrameSoundUpdate(); - fcnt = 1; + /* fcnt = 1; */ fhcnt = fhinc; - X6502_IRQEnd(FCEU_IQFCOUNT); - SIRQStat &= ~0x40; + if (V & 1) { + X6502_IRQEnd(FCEU_IQFCOUNT); + SIRQStat &= ~0x40; + } IRQFrameMode = V; } @@ -938,6 +977,7 @@ int FlushEmulateSound(void) { *tmpo = (b & 65535) + wlookup2[(b >> 16) & 255] + wlookup1[b >> 24]; tmpo++; } + end = NeoFilterSound(WaveHi, WaveFinal, SOUNDTS, &left); memmove(WaveHi, WaveHi + SOUNDTS - left, left * sizeof(uint32)); @@ -953,10 +993,9 @@ int FlushEmulateSound(void) { SexyFilter(Wave, WaveFinal, end >> 4); -#if 0 - if (FSettings.lowpass) - SexyFilter2(WaveFinal, end >> 4); -#endif + /* if (FSettings.lowpass) + SexyFilter2(WaveFinal, end >> 4); */ + if (end & 0xF) Wave[0] = Wave[(end >> 4)]; Wave[end >> 4] = 0; @@ -1023,6 +1062,8 @@ void FCEUSND_Reset(void) { DMCAddress = 0; DMCSize = 0; DMCShift = 0; + DMCacc=1; + DMCBitCount=0; } void FCEUSND_Power(void) { @@ -1162,8 +1203,8 @@ SFORMAT FCEUSND_STATEINFO[] = { { &DMCAddressLatch, 1, "5ADL" }, { &DMCFormat, 1, "5FMT" }, { &RawDALatch, 1, "RWDA" }, - - //these are important for smooth sound after loading state + + /* these are important for smooth sound after loading state */ { &sqacc[0], sizeof(sqacc[0]) | FCEUSTATE_RLSB, "SAC1" }, { &sqacc[1], sizeof(sqacc[1]) | FCEUSTATE_RLSB, "SAC2" }, { &RectDutyCount[0], sizeof(RectDutyCount[0]) | FCEUSTATE_RLSB, "RCD1"}, @@ -1171,8 +1212,8 @@ SFORMAT FCEUSND_STATEINFO[] = { { &tristep, sizeof(tristep) | FCEUSTATE_RLSB, "TRIS"}, { &lq_triacc, sizeof(lq_triacc) | FCEUSTATE_RLSB, "TACC" }, { &lq_noiseacc, sizeof(lq_noiseacc) | FCEUSTATE_RLSB, "NACC" }, - - //less important but still necessary + + /* less important but still necessary */ { &ChannelBC[0], sizeof(ChannelBC[0]) | FCEUSTATE_RLSB, "CBC1" }, { &ChannelBC[1], sizeof(ChannelBC[1]) | FCEUSTATE_RLSB, "CBC2" }, { &ChannelBC[2], sizeof(ChannelBC[2]) | FCEUSTATE_RLSB, "CBC3" }, @@ -1187,10 +1228,17 @@ SFORMAT FCEUSND_STATEINFO[] = { { &sexyfilter_acc1, sizeof(sexyfilter_acc1) | FCEUSTATE_RLSB, "FAC1" }, { &sexyfilter_acc2, sizeof(sexyfilter_acc2) | FCEUSTATE_RLSB, "FAC2" }, { &lq_tcout, sizeof(lq_tcout) | FCEUSTATE_RLSB, "TCOU"}, - - //wave buffer is used for filtering, only need first 17 values from it + +/* 2018-12-14 - Wii and possibly other big-endian platforms are having + * issues loading states with this. Increasing it only helps a few games. + * Disabling this state variable for Wii/WiiU/GC for now. */ +/* TODO: fix this for better runahead feature for big-endian */ +#ifndef GEKKO + /* wave buffer is used for filtering, only need first 17 values from it */ { &Wave, 32 * sizeof(int32), "WAVE"}, -{ 0 } +#endif + + { 0 } }; void FCEUSND_SaveState(void) { @@ -1202,10 +1250,20 @@ void FCEUSND_LoadState(int version) { RawDALatch &= 0x7F; DMCAddress &= 0x7FFF; - //minimal validation + /* minimal validation */ for (i = 0; i < 5; i++) { - if (ChannelBC[i] < 0 || ChannelBC[i] > 15) + int BC_max = 15; + + if (FSettings.soundq == 2) + { + BC_max = 1025; + } + else if (FSettings.soundq == 1) + { + BC_max = 485; + } + if (ChannelBC[i] < 0 || ChannelBC[i] > BC_max) { ChannelBC[i] = 0; } diff --git a/src/state.c b/src/state.c index 35f7d6a..baeab1c 100644 --- a/src/state.c +++ b/src/state.c @@ -108,7 +108,7 @@ static int SubWrite(memstream_t *mem, SFORMAT *sf) if(sf->s & RLSB) FlipByteOrder((uint8 *)sf->v, sf->s & (~RLSB)); #endif - memstream_write(mem, (uint8 *)sf->v, sf->s & (~RLSB)); + memstream_write(mem, (char *)sf->v, sf->s & (~RLSB)); /* Now restore the original byte order. */ #ifdef MSB_FIRST @@ -176,7 +176,7 @@ static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size) if((tmp = CheckS(sf, tsize, toa))) { - memstream_read(mem, (uint8 *)tmp->v, tmp->s & (~RLSB)); + memstream_read(mem, (char *)tmp->v, tmp->s & (~RLSB)); #ifdef MSB_FIRST if(tmp->s & RLSB) @@ -213,8 +213,8 @@ static int ReadStateChunks(memstream_t *st, int32 totalsize) case 2: if (!ReadStateChunk(st, SFCPUC, size)) ret = 0; - else - X.mooPI = X.P; /* Quick and dirty hack. */ + /* else + X.mooPI = X.P; */ /* Quick and dirty hack. */ break; case 3: if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) @@ -320,6 +320,7 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) SPreSave = PreSave; SPostSave = PostSave; SFEXINDEX = 0; + SFMDATA[0].s = 0; } void AddExState(void *v, uint32 s, int type, char *desc)