From d4753076e89d42cdad4a4f1ca4688fad3c56d873 Mon Sep 17 00:00:00 2001 From: gameblabla Date: Sat, 5 Oct 2019 03:04:57 +0200 Subject: Port the libretro core and make it standalone. TODO : - Input should use our config file instead. - Missing audio in some games. (Star Ocean, doesn't happen with stock retroarch code. Odd...) --- .travis.yml | 36 - Makefile | 570 +------ Makefile.common | 53 - README.md | 8 + control | 10 - jni/Android.mk | 24 - jni/Application.mk | 1 - libretro-common/include/boolean.h | 39 - libretro-common/include/compat/msvc.h | 132 -- libretro-common/include/compat/msvc/stdint.h | 258 --- libretro-common/include/retro_inline.h | 39 - libretro-common/include/retro_miscellaneous.h | 155 -- libretro.c | 933 ----------- libretro.h | 2149 ------------------------- link.T | 4 - shell/audio/alsa/sound_output.c | 142 ++ shell/audio/oss/sound_output.c | 59 + shell/audio/portaudio/sound_output.c | 41 + shell/audio/sdl/sound_output.c | 104 ++ shell/audio/sound_output.h | 10 + shell/emu/core.c | 435 +++++ shell/emu/main.h | 9 + shell/headers/boolean.h | 39 + shell/headers/retro_inline.h | 39 + shell/headers/shared.h | 31 + shell/input/input.h | 6 + shell/input/sdl/input.c | 74 + shell/menu/config.h | 11 + shell/menu/font_drawing.c | 131 ++ shell/menu/font_drawing.h | 13 + shell/menu/font_menudata.h | 135 ++ shell/menu/menu.c | 597 +++++++ shell/menu/menu.h | 18 + shell/other/compatibility_layer.c | 185 +++ shell/scalers/scaler.c | 139 ++ shell/scalers/scaler.h | 11 + shell/video/retrostone/video_blit.c | 155 ++ shell/video/retrostone/video_blit.h | 24 + shell/video/sdl/video_blit.c | 132 ++ shell/video/sdl/video_blit.h | 24 + source/dsp1.c | 6 +- source/dsp1emu.c | 1127 ------------- source/dsp1emu.h | 1127 +++++++++++++ source/dsp2emu.c | 112 -- source/dsp2emu.h | 112 ++ source/dsp4emu.c | 1227 -------------- source/dsp4emu.h | 1227 ++++++++++++++ source/port.h | 8 +- source/snes9x.h | 3 +- source/srtc.c | 4 +- 50 files changed, 5075 insertions(+), 6853 deletions(-) delete mode 100644 .travis.yml delete mode 100644 Makefile.common delete mode 100644 control delete mode 100644 jni/Android.mk delete mode 100644 jni/Application.mk delete mode 100644 libretro-common/include/boolean.h delete mode 100644 libretro-common/include/compat/msvc.h delete mode 100644 libretro-common/include/compat/msvc/stdint.h delete mode 100644 libretro-common/include/retro_inline.h delete mode 100644 libretro-common/include/retro_miscellaneous.h delete mode 100644 libretro.c delete mode 100644 libretro.h delete mode 100644 link.T create mode 100644 shell/audio/alsa/sound_output.c create mode 100644 shell/audio/oss/sound_output.c create mode 100644 shell/audio/portaudio/sound_output.c create mode 100644 shell/audio/sdl/sound_output.c create mode 100644 shell/audio/sound_output.h create mode 100644 shell/emu/core.c create mode 100644 shell/emu/main.h create mode 100644 shell/headers/boolean.h create mode 100644 shell/headers/retro_inline.h create mode 100644 shell/headers/shared.h create mode 100644 shell/input/input.h create mode 100644 shell/input/sdl/input.c create mode 100644 shell/menu/config.h create mode 100644 shell/menu/font_drawing.c create mode 100644 shell/menu/font_drawing.h create mode 100644 shell/menu/font_menudata.h create mode 100644 shell/menu/menu.c create mode 100644 shell/menu/menu.h create mode 100644 shell/other/compatibility_layer.c create mode 100644 shell/scalers/scaler.c create mode 100644 shell/scalers/scaler.h create mode 100644 shell/video/retrostone/video_blit.c create mode 100644 shell/video/retrostone/video_blit.h create mode 100644 shell/video/sdl/video_blit.c create mode 100644 shell/video/sdl/video_blit.h delete mode 100644 source/dsp1emu.c create mode 100644 source/dsp1emu.h delete mode 100644 source/dsp2emu.c create mode 100644 source/dsp2emu.h delete mode 100644 source/dsp4emu.c create mode 100644 source/dsp4emu.h diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3f95faf..0000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: generic -os: linux -dist: trusty -sudo: required -addons: - apt: - packages: - - g++-7 - sources: - - ubuntu-toolchain-r-test -env: - global: - - CORE=snes9x2005 - - COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7 - matrix: - - PLATFORM=3ds - - PLATFORM=linux_x64 - - PLATFORM=ngc - - PLATFORM=wii - - PLATFORM=wiiu -before_script: - - pwd - - mkdir -p ~/bin - - ln -s /usr/bin/gcc-7 ~/bin/gcc - - ln -s /usr/bin/g++-7 ~/bin/g++ - - ln -s /usr/bin/cpp-7 ~/bin/cpp - - export PATH=~/bin:$PATH - - ls -l ~/bin - - echo $PATH - - g++-7 --version - - g++ --version -script: - - cd ~/ - - git clone --depth=50 https://github.com/libretro/libretro-super - - cd libretro-super/travis - - ./build.sh diff --git a/Makefile b/Makefile index 384e2a9..e0e5339 100644 --- a/Makefile +++ b/Makefile @@ -1,555 +1,33 @@ -DEBUG = 0 -PERF_TEST = 0 -LOAD_FROM_MEMORY_TEST = 1 -USE_BLARGG_APU = 0 -LAGFIX = 1 +PRGNAME = PocketSNES -SPACE := -SPACE := $(SPACE) $(SPACE) -BACKSLASH := -BACKSLASH := \$(BACKSLASH) -filter_out1 = $(filter-out $(firstword $1),$1) -filter_out2 = $(call filter_out1,$(call filter_out1,$1)) -unixpath = $(subst \,/,$1) -unixcygpath = /$(subst :,,$(call unixpath,$1)) +# define regarding OS, which compiler to use +CC = gcc -ifeq ($(platform),) - ifeq (,$(findstring classic_,$(platform))) - platform = unix - endif -ifeq ($(shell uname -a),) - platform = win -else ifneq ($(findstring Darwin,$(shell uname -a)),) - platform = osx - arch = intel -ifeq ($(shell uname -p),powerpc) - arch = ppc -endif -else ifneq ($(findstring MINGW,$(shell uname -a)),) - platform = win -else ifneq ($(findstring SunOS,$(shell uname -a)),) - platform = sun -endif -endif +# change compilation / linking flag options +CFLAGS = -DLSB_FIRST -I. -Ilibretro-common/include -Isrc -DINLINE="inline" -DRIGHTSHIFT_IS_SAR +CFLAGS += -Isource -I./shell/emu -I./shell/scalers -I./shell/emu -I./shell/audio -I./shell/menu -I./shell/video/sdl -I./shell/input -Ishell/headers -# system platform -system_platform = unix -ifeq ($(shell uname -a),) - EXE_EXT = .exe - system_platform = win -else ifneq ($(findstring Darwin,$(shell uname -a)),) - system_platform = osx - arch = intel - ifeq ($(shell uname -p),powerpc) - arch = ppc - endif -else ifneq ($(findstring MINGW,$(shell uname -a)),) - system_platform = win -endif +CFLAGS += -O2 -DNDEBUG -DLAGFIX -DGIT_VERSION=\"" c9b3980"\" -fno-builtin -fno-exceptions -ffunction-sections -std=gnu99 +CFLAGS += -Wall -Wextra -pedantic -Wno-implicit-function-declaration -Wno-implicit-fallthrough -Wno-sign-compare -Wno-unused-variable -Wno-unused-function -Wno-uninitialized -Wno-strict-aliasing -Wno-overflow -fno-strict-overflow -ifeq ($(USE_BLARGG_APU), 1) - TARGET_NAME := snes9x2005_plus -else - TARGET_NAME := snes9x2005 -endif -GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" -ifneq ($(GIT_VERSION)," unknown") - CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" -endif +#-fprofile-generate=/mnt/int_sd/profile +LDFLAGS = -lSDL -lasound -lm -DEFS := -ifneq (,$(findstring msvc,$(platform))) -LIBM := -else -LIBM := -lm -endif -LIBS := +# Files to be compiled +SRCDIR = ./source ./shell/emu ./shell/scalers ./shell/audio/alsa ./shell/menu ./shell/video/sdl ./shell/input/sdl ./shell/other +VPATH = $(SRCDIR) +SRC_C = $(foreach dir, $(SRCDIR), $(wildcard $(dir)/*.c)) +SRC_CP = $(foreach dir, $(SRCDIR), $(wildcard $(dir)/*.cpp)) +OBJ_C = $(notdir $(patsubst %.c, %.o, $(SRC_C))) +OBJ_CP = $(notdir $(patsubst %.cpp, %.o, $(SRC_CP))) +OBJS = $(OBJ_C) $(OBJ_CP) -ifeq ($(platform), unix) - TARGET := $(TARGET_NAME)_libretro.so - fpic := -fPIC - SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T - CFLAGS += -fno-builtin -fno-exceptions -ffunction-sections -else ifeq ($(platform), linux-portable) - TARGET := $(TARGET_NAME)_libretro.so - fpic := -fPIC -nostdlib - SHARED := -shared -Wl,--version-script=link.T - CFLAGS += -fno-builtin -fno-exceptions -ffunction-sections - LIBM := -else ifeq ($(platform),sun) - TARGET := $(TARGET_NAME)_libretro.so - fpic := -fPIC - SHARED := -shared -z defs - CFLAGS += -fno-builtin -fno-exceptions -ffunction-sections - CC = gcc -else ifeq ($(platform), osx) - TARGET := $(TARGET_NAME)_libretro.dylib - fpic := -fPIC - SHARED := -dynamiclib +# Rules to make executable +$(PRGNAME): $(OBJS) + $(CC) $(CFLAGS) -o $(PRGNAME) $^ $(LDFLAGS) -ifeq ($(arch),ppc) - FLAGS += -DMSB_FIRST - OLD_GCC = 1 -endif - OSXVER = $(shell sw_vers -productVersion | cut -d. -f 2) - OSX_GT_MOJAVE = $(shell (( $(OSXVER) >= 14)) && echo "YES") -ifneq ($(OSX_GT_MOJAVE),YES) - #this breaks compiling on Mac OS Mojave - fpic += -mmacosx-version-min=10.1 -endif -ifndef ($(NOUNIVERSAL)) - FLAGS += $(ARCHFLAGS) - LDFLAGS += $(ARCHFLAGS) -endif -# iOS -else ifneq (,$(findstring ios,$(platform))) - TARGET := $(TARGET_NAME)_libretro_ios.dylib - fpic := -fPIC - SHARED := -dynamiclib - -ifeq ($(IOSSDK),) - IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path) -endif - -ifeq ($(platform),ios-arm64) - CC = cc -arch arm64 -isysroot $(IOSSDK) - CXX = c++ -arch arm64 -isysroot $(IOSSDK) -else - CC = cc -arch armv7 -isysroot $(IOSSDK) - CXX = c++ -arch armv7 -isysroot $(IOSSDK) -endif - -ifeq ($(platform),$(filter $(platform),ios9 ios-arm64)) - SHARED += -miphoneos-version-min=8.0 - CC += -miphoneos-version-min=8.0 - CXX += -miphoneos-version-min=8.0 -else - SHARED += -miphoneos-version-min=5.0 - CC += -miphoneos-version-min=5.0 - CXX += -miphoneos-version-min=5.0 -endif -# Theos iOS -else ifeq ($(platform), theos_ios) - DEPLOYMENT_IOSVERSION = 5.0 - TARGET = iphone:latest:$(DEPLOYMENT_IOSVERSION) - ARCHS = armv7 armv7s - TARGET_IPHONEOS_DEPLOYMENT_VERSION=$(DEPLOYMENT_IOSVERSION) - THEOS_BUILD_DIR := objs - include $(THEOS)/makefiles/common.mk - LIBRARY_NAME = $(TARGET_NAME)_libretro_ios -else ifeq ($(platform), qnx) - TARGET := $(TARGET_NAME)_libretro_$(platform).so - fpic := -fPIC - SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T - CC = qcc -Vgcc_ntoarmv7le - CXX = QCC -Vgcc_ntoarmv7le_cpp -# PS3 -else ifeq ($(platform), ps3) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe - CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe - AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe - STATIC_LINKING = 1 - FLAGS += -DMSB_FIRST - OLD_GCC = 1 -# PS3 (SNC) -else ifeq ($(platform), sncps3) - TARGET := $(TARGET_NAME)_libretro_ps3.a - CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe - CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe - AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe - STATIC_LINKING = 1 - FLAGS += -DMSB_FIRST - NO_GCC = 1 -# PSP1 -else ifeq ($(platform), psp1) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = psp-gcc$(EXE_EXT) - CXX = psp-g++$(EXE_EXT) - AR = psp-ar$(EXE_EXT) - STATIC_LINKING = 1 - LOAD_FROM_MEMORY_TEST = 0 - FLAGS += -G0 - CFLAGS += \ - -march=allegrex -mno-abicalls -fno-pic \ - -fno-builtin -fno-exceptions -ffunction-sections - DEFS += -DPSP -D_PSP_FW_VERSION=371 - STATIC_LINKING := 1 -# Vita -else ifeq ($(platform), vita) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = arm-vita-eabi-gcc$(EXE_EXT) - CXX = arm-vita-eabi-g++$(EXE_EXT) - AR = arm-vita-eabi-ar$(EXE_EXT) - STATIC_LINKING = 1 - LOAD_FROM_MEMORY_TEST = 0 - DEFS += -DVITA - STATIC_LINKING := 1 -# CTR (3DS) -else ifeq ($(platform), ctr) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT) - CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT) - AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT) - CFLAGS += -DARM11 -D_3DS - CFLAGS += -march=armv6k -mtune=mpcore -mfloat-abi=hard - CFLAGS += -Wall -mword-relocations - CFLAGS += -fomit-frame-pointer -ffast-math - CFLAGS += -D_3DS - PLATFORM_DEFINES := -D_3DS - STATIC_LINKING = 1 -# Nintendo Game Cube -else ifeq ($(platform), ngc) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) - AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST - CFLAGS += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int - STATIC_LINKING = 1 -# Nintendo Wii -else ifeq ($(platform), wii) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) - AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST - CFLAGS += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int - STATIC_LINKING = 1 -# Nintendo WiiU -else ifeq ($(platform), wiiu) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) - AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - CFLAGS += -DGEKKO -DWIIU -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float -D__ppc__ -DMSB_FIRST - CFLAGS += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int - STATIC_LINKING = 1 -else ifeq ($(platform), emscripten) - TARGET := $(TARGET_NAME)_libretro_$(platform).bc - STATIC_LINKING = 1 -# GCW0 -else ifeq ($(platform), gcw0) - TARGET := $(TARGET_NAME)_libretro.so - CC = /opt/gcw0-toolchain/usr/bin/mipsel-linux-gcc - CXX = /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++ - AR = /opt/gcw0-toolchain/usr/bin/mipsel-linux-ar - fpic := -fPIC -nostdlib - SHARED := -shared -Wl,--version-script=link.T - LIBM := - LOAD_FROM_MEMORY_TEST = 0 - CFLAGS += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float - -# (armv7 a7, hard point, neon based) ### -# NESC, SNESC, C64 mini -else ifeq ($(platform), classic_armv7_a7) - TARGET := $(TARGET_NAME)_libretro.so - fpic := -fPIC - SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined - CFLAGS += -Ofast \ - -flto=4 -fwhole-program -fuse-linker-plugin \ - -fdata-sections -ffunction-sections -Wl,--gc-sections \ - -fno-stack-protector -fno-ident -fomit-frame-pointer \ - -falign-functions=1 -falign-jumps=1 -falign-loops=1 \ - -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \ - -fmerge-all-constants -fno-math-errno \ - -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard - CXXFLAGS += $(CFLAGS) - CPPFLAGS += $(CFLAGS) - ASFLAGS += $(CFLAGS) - HAVE_NEON = 1 - ARCH = arm - BUILTIN_GPU = neon - USE_DYNAREC = 1 - ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1) - CFLAGS += -march=armv7-a - else - CFLAGS += -march=armv7ve - # If gcc is 5.0 or later - ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1) - LDFLAGS += -static-libgcc -static-libstdc++ - endif - endif -####################################### - -# Windows MSVC 2010 x86 -else ifeq ($(platform), windows_msvc2010_x86) - CC = cl.exe - CXX = cl.exe - -PATH := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin"):$(PATH) -PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE") -INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") -LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS100COMNTOOLS)../../VC/lib") -BIN := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin") - -WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib -WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib - -WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include -WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include - -INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)" -export INCLUDE := $(INCLUDE) -export LIB := $(LIB);$(WindowsSdkDir) -TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 -LDFLAGS += -DLL -CFLAGS += -D_CRT_SECURE_NO_DEPRECATE -NO_GCC = 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;libretro-common/include/compat/msvc -export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib -TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 -LDFLAGS += -DLL -CFLAGS += -D_CRT_SECURE_NO_DEPRECATE -NO_GCC = 1 - -# Windows MSVC 2005 x86 -else ifeq ($(platform), windows_msvc2005_x86) - CC = cl.exe - CXX = cl.exe - -PATH := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin"):$(PATH) -PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../IDE") -INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/include") -LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS80COMNTOOLS)../../VC/lib") -BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin") - -WindowsSdkDir := $(INETSDK) - -export INCLUDE := $(INCLUDE);$(INETSDK)/Include;libretro-common/include/compat/msvc -export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib -TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 -LDFLAGS += -DLL -CFLAGS += -D_CRT_SECURE_NO_DEPRECATE -NO_GCC = 1 - -# Windows MSVC 2003 x86 -else ifeq ($(platform), windows_msvc2003_x86) - CC = cl.exe - CXX = cl.exe - -PATH := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin"):$(PATH) -PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../IDE") -INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/include") -LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS71COMNTOOLS)../../Vc7/lib") -BIN := $(shell IFS=$$'\n'; cygpath "$(VS71COMNTOOLS)../../Vc7/bin") - -WindowsSdkDir := $(INETSDK) - -export INCLUDE := $(INCLUDE);$(INETSDK)/Include;libretro-common/include/compat/msvc -export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib -TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 -LDFLAGS += -DLL -CFLAGS += -D_CRT_SECURE_NO_DEPRECATE -NO_GCC = 1 - -# Windows MSVC 2017 all architectures -else ifneq (,$(findstring windows_msvc2017,$(platform))) - - NO_GCC := 1 - CFLAGS += -DNOMINMAX - CXXFLAGS += -DNOMINMAX - WINDOWS_VERSION = 1 - - PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) - ifneq (,$(findstring desktop,$(PlatformSuffix))) - WinPartition = desktop - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS - LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 - LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib - else ifneq (,$(findstring uwp,$(PlatformSuffix))) - WinPartition = uwp - MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WINDLL -D_UNICODE -DUNICODE -D__WRL_NO_DEFAULT_LIB__ -EHsc -FS - LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO - LIBS += WindowsApp.lib - endif - - CFLAGS += $(MSVC2017CompileFlags) - CXXFLAGS += $(MSVC2017CompileFlags) - - 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))) - fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) - - ProgramFiles86w := $(shell cmd /c "echo %PROGRAMFILES(x86)%") - ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") - - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) - WindowsSdkDir := $(WindowsSdkDir) - - WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) - WindowsSDKVersion := $(WindowsSDKVersion) - - VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools - VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise - VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional - VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community - - VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) - endif - ifeq ($(VsInstallRoot), ) - VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) - endif - VsInstallRoot := $(VsInstallRoot) - - VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') - VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) - - WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") - WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") - WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") - WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") - WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") - - # For some reason the HostX86 compiler doesn't like compiling for x64 - # ("no such file" opening a shared library), and vice-versa. - # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. - # NOTE: What about ARM? - ifneq (,$(findstring x64,$(TargetArchMoniker))) - VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64 - else - VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86 - endif - - PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH) - PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") - INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") - LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)") - ifneq (,$(findstring uwp,$(PlatformSuffix))) - LIB := $(LIB);$(shell IFS=$$'\n'; cygpath -w "$(LIB)/store") - endif - - export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) - export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir) - TARGET := $(TARGET_NAME)_libretro.dll - PSS_STYLE :=2 - LDFLAGS += -DLL - -else - TARGET := $(TARGET_NAME)_libretro.dll - CC = gcc - CXX = g++ - SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T - LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm -endif - -LDFLAGS += $(LIBM) - -CORE_DIR := ./source -LIBRETRO_DIR := . - -include Makefile.common - -ifeq ($(OLD_GCC), 1) - WARNINGS := -Wall -else ifeq ($(NO_GCC), 1) - WARNINGS := -else - WARNINGS := \ - -Wall \ - -Wextra \ - -pedantic \ - -Wno-implicit-function-declaration \ - -Wno-implicit-fallthrough \ - -Wno-sign-compare \ - -Wno-unused-variable \ - -Wno-unused-function \ - -Wno-uninitialized \ - -Wno-strict-aliasing \ - -Wno-overflow \ - -fno-strict-overflow -endif - -ifeq ($(DEBUG),1) - FLAGS += -O0 -g -else - FLAGS += -O2 -DNDEBUG -endif - -ifeq ($(PERF_TEST),1) - FLAGS += -DPERF_TEST -endif - -ifeq ($(LAGFIX),1) - FLAGS += -DLAGFIX -endif - -FLAGS += $(INCFLAGS_PLATFORM) - -ifeq ($(platform), psp1) - INCFLAGS += -I$(shell psp-config --pspsdk-path)/include -endif - -OBJECTS := $(SOURCES_C:.c=.o) - -LDFLAGS += $(fpic) - -FLAGS += $(fpic) - -CXXFLAGS += $(FLAGS) -CFLAGS += $(FLAGS) - -ifneq (,$(findstring msvc,$(platform))) - LIBM = - OBJOUT = -Fo - LINKOUT = -out: - LD = link.exe -else - OBJOUT = -o - LINKOUT = -o - LD = $(CC) -endif - -%.o: %.cpp - $(CXX) $(CXXFLAGS) -c $(OBJOUT)$@ $< - -%.o: %.c - $(CC) $(CFLAGS) -c $(OBJOUT)$@ $< - -ifeq ($(platform), theos_ios) - COMMON_FLAGS := -DIOS $(COMMON_DEFINES) $(INCFLAGS) -I$(THEOS_INCLUDE_PATH) -Wno-error - $(LIBRARY_NAME)_CFLAGS += $(COMMON_FLAGS) $(CFLAGS) - ${LIBRARY_NAME}_FILES = $(SOURCES_C) - include $(THEOS_MAKE_PATH)/library.mk -else -all: $(TARGET) -$(TARGET): $(OBJECTS) -ifeq ($(STATIC_LINKING), 1) - $(AR) rcs $@ $(OBJECTS) -else - $(LD) $(LINKOUT)$@ $(SHARED) $(OBJECTS) $(LDFLAGS) $(LIBS) -endif +$(OBJ_C) : %.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f $(TARGET) $(OBJECTS) - -.PHONY: clean -endif + rm -f $(PRGNAME)$(EXESUFFIX) *.o diff --git a/Makefile.common b/Makefile.common deleted file mode 100644 index 48256bb..0000000 --- a/Makefile.common +++ /dev/null @@ -1,53 +0,0 @@ -LIBRETRO_COMM_DIR := $(LIBRETRO_DIR)/libretro-common - -INCFLAGS := -I$(CORE_DIR) -I$(LIBRETRO_DIR) -I$(LIBRETRO_COMM_DIR)/include - -SOURCES_C := \ - $(CORE_DIR)/c4.c \ - $(CORE_DIR)/c4emu.c \ - $(CORE_DIR)/cheats2.c \ - $(CORE_DIR)/cheats.c \ - $(CORE_DIR)/clip.c \ - $(CORE_DIR)/cpu.c \ - $(CORE_DIR)/cpuexec.c \ - $(CORE_DIR)/cpuops.c \ - $(CORE_DIR)/data.c\ - $(CORE_DIR)/dma.c \ - $(CORE_DIR)/dsp1.c \ - $(CORE_DIR)/fxemu.c \ - $(CORE_DIR)/fxinst.c \ - $(CORE_DIR)/gfx.c \ - $(CORE_DIR)/getset.c \ - $(CORE_DIR)/globals.c \ - $(CORE_DIR)/memmap.c \ - $(CORE_DIR)/obc1.c \ - $(CORE_DIR)/ppu.c \ - $(CORE_DIR)/sa1.c \ - $(CORE_DIR)/sa1cpu.c \ - $(CORE_DIR)/sdd1.c \ - $(CORE_DIR)/sdd1emu.c \ - $(CORE_DIR)/seta010.c \ - $(CORE_DIR)/seta011.c \ - $(CORE_DIR)/seta018.c \ - $(CORE_DIR)/seta.c \ - $(CORE_DIR)/spc7110.c \ - $(CORE_DIR)/spc7110dec.c \ - $(CORE_DIR)/srtc.c \ - $(CORE_DIR)/tile.c \ - $(LIBRETRO_DIR)/libretro.c - -ifeq ($(USE_BLARGG_APU),1) - SOURCES_C += $(CORE_DIR)/apu_blargg.c - FLAGS += -DUSE_BLARGG_APU -else - SOURCES_C += \ - $(CORE_DIR)/apu.c \ - $(CORE_DIR)/soundux.c \ - $(CORE_DIR)/spc700.c -endif - -ifeq ($(LOAD_FROM_MEMORY_TEST),1) - FLAGS += -DLOAD_FROM_MEMORY_TEST -endif - -FLAGS += $(DEFS) $(WARNINGS) $(INCFLAGS) diff --git a/README.md b/README.md index a469bda..768a61a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +SnesEmu fork based on snes9x2005 libretro core by the Retroarch team. + +The libretro team had switched the core entirely to C and made it less prone to crashes. +It made more sense to me to just reuse that work rather than trying to fix up PocketSNES, +which is now unmaintained. + +========================== + snes9x2005 libretro core. A Super Nintendo emulator core using the libretro API. diff --git a/control b/control deleted file mode 100644 index 9397a89..0000000 --- a/control +++ /dev/null @@ -1,10 +0,0 @@ -Package: com.libretro.catsfc -Name: catsfc -Depends: -Version: 0.0.1 -Architecture: iphoneos-arm -Description: Libretro iOS core of catSFC -Maintainer: libretro -Author: libretro -Section: System -Tag: role::developer diff --git a/jni/Android.mk b/jni/Android.mk deleted file mode 100644 index e5cf6e3..0000000 --- a/jni/Android.mk +++ /dev/null @@ -1,24 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -ROOT_DIR := $(LOCAL_PATH)/.. -CORE_DIR := $(ROOT_DIR)/source -LIBRETRO_DIR := $(ROOT_DIR) - -LOAD_FROM_MEMORY_TEST := 1 -FLAGS := - -include $(ROOT_DIR)/Makefile.common - -COREFLAGS := -ffast-math $(FLAGS) - -GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" -ifneq ($(GIT_VERSION)," unknown") - COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" -endif - -include $(CLEAR_VARS) -LOCAL_MODULE := retro -LOCAL_SRC_FILES := $(SOURCES_C) -LOCAL_CFLAGS := $(COREFLAGS) -LOCAL_LDFLAGS := -Wl,-version-script=$(LIBRETRO_DIR)/link.T -include $(BUILD_SHARED_LIBRARY) diff --git a/jni/Application.mk b/jni/Application.mk deleted file mode 100644 index a252a72..0000000 --- a/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := all diff --git a/libretro-common/include/boolean.h b/libretro-common/include/boolean.h deleted file mode 100644 index 2c18ef7..0000000 --- a/libretro-common/include/boolean.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2010-2017 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (boolean.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_SDK_BOOLEAN_H -#define __LIBRETRO_SDK_BOOLEAN_H - -#ifndef __cplusplus - -#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) -/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */ -#define bool unsigned char -#define true 1 -#define false 0 -#else -#include -#endif - -#endif - -#endif diff --git a/libretro-common/include/compat/msvc.h b/libretro-common/include/compat/msvc.h deleted file mode 100644 index 5175214..0000000 --- a/libretro-common/include/compat/msvc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2010-2017 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (msvc.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_SDK_COMPAT_MSVC_H -#define __LIBRETRO_SDK_COMPAT_MSVC_H - -#ifdef _MSC_VER - -#ifdef __cplusplus -extern "C" { -#endif - -/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */ -#if _MSC_VER < 1900 - #include - #ifndef snprintf - #define snprintf c99_snprintf_retro__ - #endif - - int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...); -#endif - -/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ -#if _MSC_VER < 1600 - #include - #include - #ifndef vsnprintf - #define vsnprintf c99_vsnprintf_retro__ - #endif - int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap); -#endif - -#ifdef __cplusplus -} -#endif - -#undef UNICODE /* Do not bother with UNICODE at this time. */ -#include -#include -#include - -/* Python headers defines ssize_t and sets HAVE_SSIZE_T. - * Cannot duplicate these efforts. - */ -#ifndef HAVE_SSIZE_T -#if defined(_WIN64) -typedef __int64 ssize_t; -#elif defined(_WIN32) -typedef int ssize_t; -#endif -#endif - -#define mkdir(dirname, unused) _mkdir(dirname) -#define strtoull _strtoui64 -#undef strcasecmp -#define strcasecmp _stricmp -#undef strncasecmp -#define strncasecmp _strnicmp - -/* Disable some of the annoying warnings. */ -#pragma warning(disable : 4800) -#pragma warning(disable : 4805) -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) -#pragma warning(disable : 4146) -#pragma warning(disable : 4267) -#pragma warning(disable : 4723) -#pragma warning(disable : 4996) - -/* roundf and va_copy is available since MSVC 2013 */ -#if _MSC_VER < 1800 -#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f)) -#define va_copy(x, y) ((x) = (y)) -#endif - -#if _MSC_VER <= 1200 - #ifndef __cplusplus - /* VC6 math.h doesn't define some functions when in C mode. - * Trying to define a prototype gives "undefined reference". - * But providing an implementation then gives "function already has body". - * So the equivalent of the implementations from math.h are used as - * defines here instead, and it seems to work. - */ - #define cosf(x) ((float)cos((double)x)) - #define powf(x, y) ((float)pow((double)x, (double)y)) - #define sinf(x) ((float)sin((double)x)) - #define ceilf(x) ((float)ceil((double)x)) - #define floorf(x) ((float)floor((double)x)) - #define sqrtf(x) ((float)sqrt((double)x)) - #endif - - #ifndef _vscprintf - #define _vscprintf c89_vscprintf_retro__ - int c89_vscprintf_retro__(const char *format, va_list pargs); - #endif - - #ifndef _strtoui64 - #define _strtoui64(x, y, z) (_atoi64(x)) - #endif - -#endif - -#ifndef PATH_MAX -#define PATH_MAX _MAX_PATH -#endif - -#ifndef SIZE_MAX -#define SIZE_MAX _UI32_MAX -#endif - -#endif -#endif - diff --git a/libretro-common/include/compat/msvc/stdint.h b/libretro-common/include/compat/msvc/stdint.h deleted file mode 100644 index c791176..0000000 --- a/libretro-common/include/compat/msvc/stdint.h +++ /dev/null @@ -1,258 +0,0 @@ -/* ISO C9x compliant stdint.h for Microsoft Visual Studio - * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 - * - * Copyright (c) 2006-2008 Alexander Chemeris - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. The name of the author may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __RARCH_STDINT_H -#define __RARCH_STDINT_H - -#if _MSC_VER && (_MSC_VER < 1600) -/* Pre-MSVC 2010 needs an implementation of stdint.h. */ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when - * compiling for ARM we should wrap include with 'extern "C++" {}' - * or compiler give many errors like this: - * - * error C2733: second C linkage of overloaded function 'wmemchr' not allowed - */ -#ifdef __cplusplus -#if _MSC_VER <= 1200 -extern "C++" { -#else -extern "C" { -#endif -#endif -# include -#ifdef __cplusplus -} -#endif - -/* Define _W64 macros to mark types changing their size, like intptr_t. */ -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -/* 7.18.1 Integer types. */ - -/* 7.18.1.1 Exact-width integer types. */ - -/* Visual Studio 6 and Embedded Visual C++ 4 doesn't - * realize that, e.g. char has the same size as __int8 - * so we give up on __intX for them. - */ -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -/* 7.18.1.2 Minimum-width integer types. */ -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types. */ -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -/* 7.18.1.4 Integer types capable of holding object pointers. */ -#ifdef _WIN64 /* [ */ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else /* _WIN64 ][ */ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif /* _WIN64 ] */ - -/* 7.18.1.5 Greatest-width integer types. */ -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - -/* 7.18.2 Limits of specified-width integer types. */ - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) -/* [ See footnote 220 at page 257 and footnote 221 at page 259. */ - -/* 7.18.2.1 Limits of exact-width integer types. */ -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -/* 7.18.2.2 Limits of minimum-width integer types. */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types. */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding object pointers. */ -#ifdef _WIN64 /* [ */ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else /* _WIN64 ][ */ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif /* _WIN64 ] */ - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ - -#ifdef _WIN64 /* [ */ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else /* _WIN64 ][ */ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif /* _WIN64 ] */ - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX /* [ */ -# ifdef _WIN64 /* [ */ -# define SIZE_MAX _UI64_MAX -# else /* _WIN64 ][ */ -# define SIZE_MAX _UI32_MAX -# endif /* _WIN64 ] */ -#endif /* SIZE_MAX ] */ - -/* WCHAR_MIN and WCHAR_MAX are also defined in */ -#ifndef WCHAR_MIN /* [ */ -# define WCHAR_MIN 0 -#endif /* WCHAR_MIN ] */ -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif /* WCHAR_MAX ] */ - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif /* __STDC_LIMIT_MACROS ] */ - -/* 7.18.4 Limits of other integer types */ - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) -/* [ See footnote 224 at page 260 */ - -/* 7.18.4.1 Macros for minimum-width integer constants */ - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif -/* __STDC_CONSTANT_MACROS ] */ - -#else -/* Sanity for everything else. */ -#include -#endif - -#endif - diff --git a/libretro-common/include/retro_inline.h b/libretro-common/include/retro_inline.h deleted file mode 100644 index ffdaa4a..0000000 --- a/libretro-common/include/retro_inline.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2010-2017 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (retro_inline.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_SDK_INLINE_H -#define __LIBRETRO_SDK_INLINE_H - -#ifndef INLINE - -#if defined(_WIN32) || defined(__INTEL_COMPILER) -#define INLINE __inline -#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L -#define INLINE inline -#elif defined(__GNUC__) -#define INLINE __inline__ -#else -#define INLINE -#endif - -#endif -#endif diff --git a/libretro-common/include/retro_miscellaneous.h b/libretro-common/include/retro_miscellaneous.h deleted file mode 100644 index e526d6e..0000000 --- a/libretro-common/include/retro_miscellaneous.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (C) 2010-2017 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (retro_miscellaneous.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 __RARCH_MISCELLANEOUS_H -#define __RARCH_MISCELLANEOUS_H - -#include -#include -#include - -#if defined(_WIN32) && !defined(_XBOX) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#elif defined(_WIN32) && defined(_XBOX) -#include -#endif - -#if defined(__CELLOS_LV2__) -#include -#endif - -#include - -#ifdef _MSC_VER -#include -#endif - -static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count) -{ - uint32_t i; - for (i = 0; i < count;i++) - a[i] |= b[i]; -} - -static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count) -{ - uint32_t i; - for (i = 0; i < count;i++) - a[i] &= ~b[i]; -} - -static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count) -{ - uint32_t i; - for (i = 0; i < count; i++) - { - if (ptr[i] != 0) - return true; - } - return false; -} - -#ifndef PATH_MAX_LENGTH -#if defined(__CELLOS_LV2__) -#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH -#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)|| defined(WIIU) -#define PATH_MAX_LENGTH 512 -#else -#define PATH_MAX_LENGTH 4096 -#endif -#endif - -#ifndef MAX -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -#define BITS_GET_ELEM(a, i) ((a).data[i]) -#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i]) - -#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7))) -#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7))) -#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1) - -#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15))) -#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15))) -#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1) -#define BIT16_CLEAR_ALL(a) ((a) = 0) - -#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31))) -#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31))) -#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1) -#define BIT32_CLEAR_ALL(a) ((a) = 0) - -#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63))) -#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63))) -#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1) -#define BIT64_CLEAR_ALL(a) ((a) = 0) - -#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31))) -#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31))) -#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1) -#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a)) - -#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit) -#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit) -#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit) -#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a) - -#define BIT256_SET(a, bit) BIT128_SET(a, bit) -#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit) -#define BIT256_GET(a, bit) BIT128_GET(a, bit) -#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a) - -#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit) -#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit) -#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit) -#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a) - -#define BITS_COPY16_PTR(a,bits) \ -{ \ - BIT128_CLEAR_ALL_PTR(a); \ - BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \ -} - -#define BITS_COPY32_PTR(a,bits) \ -{ \ - BIT128_CLEAR_ALL_PTR(a); \ - BITS_GET_ELEM_PTR(a, 0) = (bits); \ -} - -/* Helper macros and struct to keep track of many booleans. */ -/* This struct has 256 bits. */ -typedef struct -{ - uint32_t data[8]; -} retro_bits_t; - -#endif diff --git a/libretro.c b/libretro.c deleted file mode 100644 index a3d2beb..0000000 --- a/libretro.c +++ /dev/null @@ -1,933 +0,0 @@ -#include "copyright" - -#include - -#include "snes9x.h" -#include "soundux.h" -#include "memmap.h" -#include "apu.h" -#include "cheats.h" -#include "display.h" -#include "gfx.h" -#include "cpuexec.h" -#include "spc7110.h" -#include "srtc.h" -#include "sa1.h" - -#ifdef PSP -#include -#include -#endif - -#include -#include - -#ifdef _3DS -void* linearMemAlign(size_t size, size_t alignment); -void linearFree(void* mem); -#endif - -static retro_log_printf_t log_cb = NULL; -static retro_video_refresh_t video_cb = NULL; -static retro_input_poll_t poll_cb = NULL; -static retro_input_state_t input_cb = NULL; -static retro_audio_sample_batch_t audio_batch_cb = NULL; -static retro_environment_t environ_cb = NULL; -struct retro_perf_callback perf_cb; - -char retro_save_directory[PATH_MAX_LENGTH]; -char retro_base_name[PATH_MAX_LENGTH]; -bool overclock_cycles = false; -bool reduce_sprite_flicker = false; -int one_c, slow_one_c, two_c; - -#ifdef _WIN32 - char slash = '\\'; -#else - char slash = '/'; -#endif - -static int32_t samples_per_frame = 0; -static int32_t samplerate = (((SNES_CLOCK_SPEED * 6) / (32 * ONE_APU_CYCLE))); - -#ifdef PERF_TEST -#define RETRO_PERFORMANCE_INIT(name) \ - retro_perf_tick_t current_ticks; \ - static struct retro_perf_counter name = {#name}; \ - if (!name.registered) \ - perf_cb.perf_register(&(name)); \ - current_ticks = name.total - -#define RETRO_PERFORMANCE_START(name) \ - perf_cb.perf_start(&(name)) - -#define RETRO_PERFORMANCE_STOP(name) \ - perf_cb.perf_stop(&(name)); \ - current_ticks = name.total - current_ticks; -#else -#define RETRO_PERFORMANCE_INIT(name) -#define RETRO_PERFORMANCE_START(name) -#define RETRO_PERFORMANCE_STOP(name) -#endif - -void retro_set_environment(retro_environment_t cb) -{ - struct retro_log_callback log; - environ_cb = cb; - - if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) - log_cb = log.log; - else - log_cb = NULL; - - environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf_cb); -} - -void retro_set_video_refresh(retro_video_refresh_t cb) -{ - video_cb = cb; -} - -void retro_set_audio_sample(retro_audio_sample_t cb) -{ - (void) cb; -} - -void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) -{ - audio_batch_cb = cb; -} - -void retro_set_input_poll(retro_input_poll_t cb) -{ - poll_cb = cb; -} - -void retro_set_input_state(retro_input_state_t cb) -{ - input_cb = cb; -} - -void retro_set_controller_port_device(unsigned in_port, unsigned device) -{ - (void) in_port; - (void) device; -} - -unsigned retro_api_version() -{ - return RETRO_API_VERSION; -} - -void S9xDeinitDisplay(void) -{ -#ifdef DS2_DMA - if (GFX.Screen_buffer) - AlignedFree(GFX.Screen, PtrAdj.GFXScreen); -#elif defined(_3DS) - if (GFX.Screen_buffer) - linearFree(GFX.Screen_buffer); -#else - if (GFX.Screen_buffer) - free(GFX.Screen_buffer); -#endif - if (GFX.SubScreen_buffer) - free(GFX.SubScreen_buffer); - if (GFX.ZBuffer_buffer) - free(GFX.ZBuffer_buffer); - if (GFX.SubZBuffer_buffer) - free(GFX.SubZBuffer_buffer); - - GFX.Screen = NULL; - GFX.Screen_buffer = NULL; - GFX.SubScreen = NULL; - GFX.SubScreen_buffer = NULL; - GFX.ZBuffer = NULL; - GFX.ZBuffer_buffer = NULL; - GFX.SubZBuffer = NULL; - GFX.SubZBuffer_buffer = NULL; -} - -void S9xInitDisplay(void) -{ - int32_t h = IMAGE_HEIGHT; - int32_t safety = 32; - - GFX.Pitch = IMAGE_WIDTH * 2; -#ifdef DS2_DMA - GFX.Screen_buffer = (uint8_t *) AlignedMalloc(GFX.Pitch * h + safety, 32, &PtrAdj.GFXScreen); -#elif defined(_3DS) - safety = 0x80; - GFX.Screen_buffer = (uint8_t *) linearMemAlign(GFX.Pitch * h + safety, 0x80); -#else - GFX.Screen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety); -#endif - GFX.SubScreen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety); - GFX.ZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety); - GFX.SubZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety); - - GFX.Screen = GFX.Screen_buffer + safety; - GFX.SubScreen = GFX.SubScreen_buffer + safety; - GFX.ZBuffer = GFX.ZBuffer_buffer + safety; - GFX.SubZBuffer = GFX.SubZBuffer_buffer + safety; - - GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1; -} - -#ifndef _WIN32 -void _makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext) -{ - (void) drive; - - if (dir && *dir) - { - strcpy(path, dir); - strcat(path, "/"); - } - else - *path = 0; - - if (fname) - strcat(path, fname); - - if (ext && *ext) - { - strcat(path, "."); - strcat(path, ext); - } -} - -void _splitpath (const char* path, char* drive, char* dir, char* fname, char* ext) -{ - const char* slash = strrchr(path, '/'); - const char* dot = strrchr(path, '.'); - (void) drive; - - if (!slash) - slash = strrchr((char*)path, '\\'); - - if (dot && slash && dot < slash) - dot = NULL; - - if (!slash) - { - *dir = 0; - strcpy(fname, path); - if (dot) - { - fname[dot - path] = 0; - strcpy(ext, dot + 1); - } - else - *ext = 0; - } - else - { - strcpy(dir, path); - dir[slash - path] = 0; - strcpy(fname, slash + 1); - if (dot) - { - fname[dot - slash - 1] = 0; - strcpy(ext, dot + 1); - } - else - *ext = 0; - } -} -#endif - -const char* S9xGetFilename(const char* in) -{ - static char filename [PATH_MAX + 1]; - char drive [_MAX_DRIVE + 1]; - char dir [_MAX_DIR + 1]; - char fname [_MAX_FNAME + 1]; - char ext [_MAX_EXT + 1]; - _splitpath(Memory.ROMFilename, drive, dir, fname, ext); - _makepath(filename, drive, dir, fname, in); - return filename; -} - -void init_sfc_setting(void) -{ - memset(&Settings, 0, sizeof(Settings)); - Settings.JoystickEnabled = false; - Settings.SoundPlaybackRate = samplerate; - Settings.CyclesPercentage = 100; - - Settings.DisableSoundEcho = false; - Settings.InterpolatedSound = true; - Settings.APUEnabled = true; - - Settings.H_Max = SNES_CYCLES_PER_SCANLINE; - Settings.FrameTimePAL = 20000; - Settings.FrameTimeNTSC = 16667; - Settings.DisableMasterVolume = false; - Settings.Mouse = true; - Settings.SuperScope = true; - Settings.MultiPlayer5 = true; - Settings.ControllerOption = SNES_JOYPAD; -#ifdef USE_BLARGG_APU - Settings.SoundSync = false; -#endif - Settings.ApplyCheats = true; - Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX; -} - -#ifdef USE_BLARGG_APU -static void S9xAudioCallback() -{ - size_t avail; - /* Just pick a big buffer. We won't use it all. */ - static int16_t audio_buf[0x20000]; - - S9xFinalizeSamples(); - avail = S9xGetSampleCount(); - S9xMixSamples(audio_buf, avail); - audio_batch_cb(audio_buf, avail >> 1); -} -#endif - -void retro_init(void) -{ - struct retro_log_callback log; - enum retro_pixel_format rgb565; - bool achievements = true; - - static const struct retro_variable vars[] = - { - { "catsfc_VideoMode", "Video Mode; auto|NTSC|PAL" }, - { "catsfc_overclock_cycles", "Reduce Slowdown (Hack, Unsafe, Restart); disabled|compatible|max" }, - { "catsfc_reduce_sprite_flicker", "Reduce Flickering (Hack, Unsafe); disabled|enabled" }, - { NULL, NULL }, - }; - - if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) - log_cb = log.log; - else - log_cb = NULL; - - /* State that the core supports achievements. */ - environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &achievements); - - rgb565 = RETRO_PIXEL_FORMAT_RGB565; - if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565) && log_cb) - log_cb(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); - - init_sfc_setting(); - S9xInitMemory(); - S9xInitAPU(); - S9xInitDisplay(); - S9xInitGFX(); -#ifdef USE_BLARGG_APU - S9xInitSound(1000, 0); /* just give it a 1 second buffer */ - S9xSetSamplesAvailableCallback(S9xAudioCallback); -#else - S9xInitSound(); -#endif - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); - CPU.SaveStateVersion = 0; -} - -void retro_deinit(void) -{ - if (Settings.SPC7110) - Del7110Gfx(); - - S9xDeinitGFX(); - S9xDeinitDisplay(); - S9xDeinitAPU(); - S9xDeinitMemory(); - -#ifdef PERF_TEST - perf_cb.perf_log(); -#endif -} - -uint32_t S9xReadJoypad(int32_t port) -{ - static const uint32_t snes_lut[] = - { - SNES_B_MASK, - SNES_Y_MASK, - SNES_SELECT_MASK, - SNES_START_MASK, - SNES_UP_MASK, - SNES_DOWN_MASK, - SNES_LEFT_MASK, - SNES_RIGHT_MASK, - SNES_A_MASK, - SNES_X_MASK, - SNES_TL_MASK, - SNES_TR_MASK - }; - - int32_t i; - uint32_t joypad = 0; - - for (i = RETRO_DEVICE_ID_JOYPAD_B; i <= RETRO_DEVICE_ID_JOYPAD_R; i++) - if (input_cb(port, RETRO_DEVICE_JOYPAD, 0, i)) - joypad |= snes_lut[i]; - - return joypad; -} - -static void check_variables(void) -{ - struct retro_variable var; - - var.key = "catsfc_VideoMode"; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - Settings.ForceNTSC = !strcmp(var.value, "NTSC"); - Settings.ForcePAL = !strcmp(var.value, "PAL"); - } - - var.key = "catsfc_overclock_cycles"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "compatible") == 0) - { - overclock_cycles = true; - one_c = 4; - slow_one_c = 5; - two_c = 6; - } - else if (strcmp(var.value, "max") == 0) - { - overclock_cycles = true; - one_c = 3; - slow_one_c = 3; - two_c = 3; - } - else - overclock_cycles = false; - } - - var.key = "catsfc_reduce_sprite_flicker"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "enabled") == 0) - reduce_sprite_flicker = true; - else - reduce_sprite_flicker = false; - } -} - -#ifdef PSP -#define FRAMESKIP -#endif - -static int32_t samples_to_play = 0; -void retro_run(void) -{ - bool updated = false; - int result; - bool okay; -#ifndef USE_BLARGG_APU - static int16_t audio_buf[2048]; -#endif - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) - check_variables(); - -#ifdef NO_VIDEO_OUTPUT - video_cb(NULL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch); - IPPU.RenderThisFrame = false; -#endif - - result = -1; - okay = environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &result); - if (okay) - { - bool audioEnabled = 0 != (result & 2); - bool videoEnabled = 0 != (result & 1); - bool hardDisableAudio = 0 != (result & 8); - IPPU.RenderThisFrame = videoEnabled; -#ifdef USE_BLARGG_APU - S9xSetSoundMute(!audioEnabled || hardDisableAudio); -#endif - Settings.HardDisableAudio = hardDisableAudio; - } - else - { - IPPU.RenderThisFrame = true; -#ifdef USE_BLARGG_APU - S9xSetSoundMute(false); -#endif - Settings.HardDisableAudio = false; - } - - poll_cb(); - - RETRO_PERFORMANCE_INIT(S9xMainLoop_func); - RETRO_PERFORMANCE_START(S9xMainLoop_func); - S9xMainLoop(); - RETRO_PERFORMANCE_STOP(S9xMainLoop_func); - -#ifndef USE_BLARGG_APU - samples_to_play += samples_per_frame; - - if (samples_to_play > 512) - { - S9xMixSamples(audio_buf, samples_to_play * 2); - audio_batch_cb(audio_buf, samples_to_play); - samples_to_play = 0; - } -#else - S9xAudioCallback(); -#endif - -#ifdef NO_VIDEO_OUTPUT - return; -#endif - -#ifdef FRAMESKIP - if (IPPU.RenderThisFrame) - { -#endif - -#ifdef PSP - static unsigned int __attribute__((aligned(16))) d_list[32]; - void* const texture_vram_p = (void*)(0x44200000 - (512 * 512)); /* max VRAM address - frame size */ - sceKernelDcacheWritebackRange(GFX.Screen, GFX.Pitch * IPPU.RenderedScreenHeight); - sceGuStart(GU_DIRECT, d_list); - sceGuCopyImage(GU_PSM_4444, 0, 0, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch >> 1, GFX.Screen, 0, 0, 512, texture_vram_p); - sceGuTexSync(); - sceGuTexImage(0, 512, 512, 512, texture_vram_p); - sceGuTexMode(GU_PSM_5551, 0, 0, GU_FALSE); - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); - sceGuDisable(GU_BLEND); - sceGuFinish(); - video_cb(texture_vram_p, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch); -#else - video_cb(GFX.Screen, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch); -#endif - -#ifdef FRAMESKIP - IPPU.RenderThisFrame = false; - } - else - { - video_cb(NULL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch); - IPPU.RenderThisFrame = true; - } -#endif -} - -bool S9xReadMousePosition(int32_t which1, int32_t* x, int32_t* y, uint32_t* buttons) -{ - (void) which1; - (void) x; - (void) y; - (void) buttons; - return false; -} - -bool S9xReadSuperScopePosition(int32_t* x, int32_t* y, uint32_t* buttons) -{ - (void) x; - (void) y; - (void) buttons; - return true; -} - -bool JustifierOffscreen(void) -{ - return false; -} - -void JustifierButtons(uint32_t* justifiers) -{ - (void) justifiers; -} - -unsigned retro_get_region(void) -{ - return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; -} - -void retro_get_system_info(struct retro_system_info* info) -{ -#ifdef LOAD_FROM_MEMORY_TEST - info->need_fullpath = false; -#else - info->need_fullpath = true; -#endif - info->valid_extensions = "smc|fig|sfc|gd3|gd7|dx2|bsx|swc"; -#ifndef GIT_VERSION -#define GIT_VERSION "" -#endif - info->library_version = "v1.36" GIT_VERSION; -#ifdef USE_BLARGG_APU - info->library_name = "Snes9x 2005 Plus"; -#else - info->library_name = "Snes9x 2005"; -#endif - info->block_extract = false; -} - -void retro_get_system_av_info(struct retro_system_av_info* info) -{ - info->geometry.base_width = 256; - info->geometry.base_height = 224; - info->geometry.max_width = 512; - info->geometry.max_height = 512; - info->geometry.aspect_ratio = 4.0 / 3.0; - - if (!Settings.PAL) - info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_NTSC_VCOUNTER)); - else - info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_PAL_VCOUNTER)); - - info->timing.sample_rate = samplerate; -} - -void retro_reset(void) -{ - CPU.Flags = 0; - S9xReset(); -} - -size_t retro_serialize_size(void) -{ - return sizeof(CPU) + sizeof(ICPU) + sizeof(PPU) + sizeof(DMA) + - 0x10000 + 0x20000 + 0x20000 + 0x8000 + -#ifndef USE_BLARGG_APU - sizeof(APU) + sizeof(IAPU) + 0x10000 + -#else - SPC_SAVE_STATE_BLOCK_SIZE + -#endif - sizeof(SA1) + sizeof(s7r) + sizeof(rtc_f9); -} - -bool retro_serialize(void* data, size_t size) -{ - int32_t i; - uint8_t* buffer = data; - (void) size; -#ifdef LAGFIX - S9xPackStatus(); -#ifndef USE_BLARGG_APU - S9xAPUPackStatus(); -#endif -#endif - S9xUpdateRTC(); - S9xSRTCPreSaveState(); - memcpy(buffer, &CPU, sizeof(CPU)); - buffer += sizeof(CPU); - memcpy(buffer, &ICPU, sizeof(ICPU)); - buffer += sizeof(ICPU); - memcpy(buffer, &PPU, sizeof(PPU)); - buffer += sizeof(PPU); - memcpy(buffer, &DMA, sizeof(DMA)); - buffer += sizeof(DMA); - memcpy(buffer, Memory.VRAM, 0x10000); - buffer += 0x10000; - memcpy(buffer, Memory.RAM, 0x20000); - buffer += 0x20000; - memcpy(buffer, Memory.SRAM, 0x20000); - buffer += 0x20000; - memcpy(buffer, Memory.FillRAM, 0x8000); - buffer += 0x8000; -#ifndef USE_BLARGG_APU - memcpy(buffer, &APU, sizeof(APU)); - buffer += sizeof(APU); - memcpy(buffer, &IAPU, sizeof(IAPU)); - buffer += sizeof(IAPU); - memcpy(buffer, IAPU.RAM, 0x10000); - buffer += 0x10000; -#else - S9xAPUSaveState(buffer); - buffer += SPC_SAVE_STATE_BLOCK_SIZE; -#endif - - SA1.Registers.PC = SA1.PC - SA1.PCBase; - S9xSA1PackStatus(); - - memcpy(buffer, &SA1, sizeof(SA1)); - buffer += sizeof(SA1); - memcpy(buffer, &s7r, sizeof(s7r)); - buffer += sizeof(s7r); - memcpy(buffer, &rtc_f9, sizeof(rtc_f9)); - - return true; -} - -bool retro_unserialize(const void* data, size_t size) -{ - const uint8_t* buffer = data; -#ifndef USE_BLARGG_APU - uint8_t* IAPU_RAM_current = IAPU.RAM; - uintptr_t IAPU_RAM_offset; -#endif - - if (size != retro_serialize_size()) - return false; - - S9xReset(); - memcpy(&CPU, buffer, sizeof(CPU)); - buffer += sizeof(CPU); - memcpy(&ICPU, buffer, sizeof(ICPU)); - buffer += sizeof(ICPU); - memcpy(&PPU, buffer, sizeof(PPU)); - buffer += sizeof(PPU); - memcpy(&DMA, buffer, sizeof(DMA)); - buffer += sizeof(DMA); - memcpy(Memory.VRAM, buffer, 0x10000); - buffer += 0x10000; - memcpy(Memory.RAM, buffer, 0x20000); - buffer += 0x20000; - memcpy(Memory.SRAM, buffer, 0x20000); - buffer += 0x20000; - memcpy(Memory.FillRAM, buffer, 0x8000); - buffer += 0x8000; -#ifndef USE_BLARGG_APU - memcpy(&APU, buffer, sizeof(APU)); - buffer += sizeof(APU); - memcpy(&IAPU, buffer, sizeof(IAPU)); - buffer += sizeof(IAPU); - IAPU_RAM_offset = IAPU_RAM_current - IAPU.RAM; - IAPU.PC += IAPU_RAM_offset; - IAPU.DirectPage += IAPU_RAM_offset; - IAPU.WaitAddress1 += IAPU_RAM_offset; - IAPU.WaitAddress2 += IAPU_RAM_offset; - IAPU.RAM = IAPU_RAM_current; - memcpy(IAPU.RAM, buffer, 0x10000); - buffer += 0x10000; -#else - S9xAPULoadState(buffer); - buffer += SPC_SAVE_STATE_BLOCK_SIZE; -#endif - - memcpy(&SA1, buffer, sizeof(SA1)); - buffer += sizeof(SA1); - memcpy(&s7r, buffer, sizeof(s7r)); - buffer += sizeof(s7r); - memcpy(&rtc_f9, buffer, sizeof(rtc_f9)); - - S9xFixSA1AfterSnapshotLoad(); - FixROMSpeed(); - IPPU.ColorsChanged = true; - IPPU.OBJChanged = true; - CPU.InDMA = false; - S9xFixColourBrightness(); - S9xSA1UnpackStatus(); -#ifndef USE_BLARGG_APU - S9xAPUUnpackStatus(); - S9xFixSoundAfterSnapshotLoad(); -#endif - ICPU.ShiftedPB = ICPU.Registers.PB << 16; - ICPU.ShiftedDB = ICPU.Registers.DB << 16; - S9xSetPCBase(ICPU.ShiftedPB + ICPU.Registers.PC); - S9xUnpackStatus(); - S9xFixCycles(); - S9xReschedule(); - return true; -} - -void retro_cheat_reset(void) -{ - S9xDeleteCheats(); - S9xApplyCheats(); -} - -extern SCheatData Cheat; - -void retro_cheat_set(unsigned index, bool enabled, const char* code) -{ - uint32_t address; - uint8_t val; - - bool sram; - uint8_t bytes[3];/* used only by GoldFinger, ignored for now */ - - if (S9xGameGenieToRaw(code, &address, &val) && S9xProActionReplayToRaw(code, &address, &val) && S9xGoldFingerToRaw(code, &address, &sram, &val, bytes)) - return; /* bad code, ignore */ - if (index > Cheat.num_cheats) - return; /* cheat added in weird order, ignore */ - if (index == Cheat.num_cheats) - Cheat.num_cheats++; - - Cheat.c[index].address = address; - Cheat.c[index].byte = val; - Cheat.c[index].enabled = enabled; - Cheat.c[index].saved = false; /* it'll be saved next time cheats run anyways */ - - Settings.ApplyCheats = true; - S9xApplyCheats(); -} - -static void init_descriptors(void) -{ - struct retro_input_descriptor desc[] = - { - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - - { 0 }, - }; - - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); -} - -bool retro_load_game(const struct retro_game_info* game) -{ - struct retro_system_av_info av_info; - if (!game) - return false; - - CPU.Flags = 0; - init_descriptors(); - check_variables(); - -#ifdef LOAD_FROM_MEMORY_TEST - if (!LoadROM(game)) -#else - if (!LoadROM(game->path)) -#endif - return false; - - Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL : Settings.FrameTimeNTSC); - - retro_get_system_av_info(&av_info); - -#ifdef USE_BLARGG_APU - Settings.SoundPlaybackRate = av_info.timing.sample_rate; -#else - samples_per_frame = av_info.timing.sample_rate / av_info.timing.fps; - S9xSetPlaybackRate(Settings.SoundPlaybackRate); -#endif - return true; -} - -bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info) -{ - (void) game_type; - (void) info; - (void) num_info; - return false; -} - -void retro_unload_game(void) -{ -} - -void* retro_get_memory_data(unsigned type) -{ - uint8_t* data; - - switch(type) - { - case RETRO_MEMORY_SAVE_RAM: - data = Memory.SRAM; - break; - case RETRO_MEMORY_SYSTEM_RAM: - data = Memory.RAM; - break; - case RETRO_MEMORY_VIDEO_RAM: - data = Memory.VRAM; - break; - default: - data = NULL; - break; - } - - return data; -} - -size_t retro_get_memory_size(unsigned type) -{ - uint32_t size; - - switch(type) - { - case RETRO_MEMORY_SAVE_RAM: - size = (uint32_t) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0); - if (size > 0x20000) - size = 0x20000; - break; - case RETRO_MEMORY_RTC: - size = (Settings.SRTC || Settings.SPC7110RTC) ? 20 : 0; - break; - case RETRO_MEMORY_SYSTEM_RAM: - size = 128 * 1024; - break; - case RETRO_MEMORY_VIDEO_RAM: - size = 64 * 1024; - break; - default: - size = 0; - break; - } - - return size; -} diff --git a/libretro.h b/libretro.h deleted file mode 100644 index ed1902b..0000000 --- a/libretro.h +++ /dev/null @@ -1,2149 +0,0 @@ -#include "copyright" - -#ifndef LIBRETRO_H__ -#define LIBRETRO_H__ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __cplusplus -#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) -/* Hack applied for MSVC when compiling in C89 mode - * as it isn't C99-compliant. */ -#define bool unsigned char -#define true 1 -#define false 0 -#else -#include -#endif -#endif - -#ifndef RETRO_CALLCONV -# if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__) -# define RETRO_CALLCONV __attribute__((cdecl)) -# elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64) -# define RETRO_CALLCONV __cdecl -# else -# define RETRO_CALLCONV /* all other platforms only have one calling convention each */ -# endif -#endif - -#ifndef RETRO_API -# if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) -# ifdef RETRO_IMPORT_SYMBOLS -# ifdef __GNUC__ -# define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__)) -# else -# define RETRO_API RETRO_CALLCONV __declspec(dllimport) -# endif -# else -# ifdef __GNUC__ -# define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__)) -# else -# define RETRO_API RETRO_CALLCONV __declspec(dllexport) -# endif -# endif -# else -# if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__CELLOS_LV2__) -# define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default"))) -# else -# define RETRO_API RETRO_CALLCONV -# endif -# endif -#endif - -/* Used for checking API/ABI mismatches that can break libretro - * implementations. - * It is not incremented for compatible changes to the API. - */ -#define RETRO_API_VERSION 1 - -/* - * Libretro's fundamental device abstractions. - * - * Libretro's input system consists of some standardized device types, - * such as a joypad (with/without analog), mouse, keyboard, lightgun - * and a pointer. - * - * The functionality of these devices are fixed, and individual cores - * map their own concept of a controller to libretro's abstractions. - * This makes it possible for frontends to map the abstract types to a - * real input device, and not having to worry about binding input - * correctly to arbitrary controller layouts. - */ - -#define RETRO_DEVICE_TYPE_SHIFT 8 -#define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1) -#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base) - -/* Input disabled. */ -#define RETRO_DEVICE_NONE 0 - -/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo - * controller, but with additional L2/R2/L3/R3 buttons, similar to a - * PS1 DualShock. */ -#define RETRO_DEVICE_JOYPAD 1 - -/* The mouse is a simple mouse, similar to Super Nintendo's mouse. - * X and Y coordinates are reported relatively to last poll (poll callback). - * It is up to the libretro implementation to keep track of where the mouse - * pointer is supposed to be on the screen. - * The frontend must make sure not to interfere with its own hardware - * mouse pointer. - */ -#define RETRO_DEVICE_MOUSE 2 - -/* KEYBOARD device lets one poll for raw key pressed. - * It is poll based, so input callback will return with the current - * pressed state. - * For event/text based keyboard input, see - * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. - */ -#define RETRO_DEVICE_KEYBOARD 3 - -/* Lightgun X/Y coordinates are reported relatively to last poll, - * similar to mouse. */ -#define RETRO_DEVICE_LIGHTGUN 4 - -/* The ANALOG device is an extension to JOYPAD (RetroPad). - * Similar to DualShock it adds two analog sticks. - * This is treated as a separate device type as it returns values in the - * full analog range of [-0x8000, 0x7fff]. Positive X axis is right. - * Positive Y axis is down. - * Only use ANALOG type when polling for analog values of the axes. - */ -#define RETRO_DEVICE_ANALOG 5 - -/* Abstracts the concept of a pointing mechanism, e.g. touch. - * This allows libretro to query in absolute coordinates where on the - * screen a mouse (or something similar) is being placed. - * For a touch centric device, coordinates reported are the coordinates - * of the press. - * - * Coordinates in X and Y are reported as: - * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen, - * and 0x7fff corresponds to the far right/bottom of the screen. - * The "screen" is here defined as area that is passed to the frontend and - * later displayed on the monitor. - * - * The frontend is free to scale/resize this screen as it sees fit, however, - * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the - * game image, etc. - * - * To check if the pointer coordinates are valid (e.g. a touch display - * actually being touched), PRESSED returns 1 or 0. - * - * If using a mouse on a desktop, PRESSED will usually correspond to the - * left mouse button, but this is a frontend decision. - * PRESSED will only return 1 if the pointer is inside the game screen. - * - * For multi-touch, the index variable can be used to successively query - * more presses. - * If index = 0 returns true for _PRESSED, coordinates can be extracted - * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with - * index = 1, and so on. - * Eventually _PRESSED will return false for an index. No further presses - * are registered at this point. */ -#define RETRO_DEVICE_POINTER 6 - -/* Buttons for the RetroPad (JOYPAD). - * The placement of these is equivalent to placements on the - * Super Nintendo controller. - * L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */ -#define RETRO_DEVICE_ID_JOYPAD_B 0 -#define RETRO_DEVICE_ID_JOYPAD_Y 1 -#define RETRO_DEVICE_ID_JOYPAD_SELECT 2 -#define RETRO_DEVICE_ID_JOYPAD_START 3 -#define RETRO_DEVICE_ID_JOYPAD_UP 4 -#define RETRO_DEVICE_ID_JOYPAD_DOWN 5 -#define RETRO_DEVICE_ID_JOYPAD_LEFT 6 -#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7 -#define RETRO_DEVICE_ID_JOYPAD_A 8 -#define RETRO_DEVICE_ID_JOYPAD_X 9 -#define RETRO_DEVICE_ID_JOYPAD_L 10 -#define RETRO_DEVICE_ID_JOYPAD_R 11 -#define RETRO_DEVICE_ID_JOYPAD_L2 12 -#define RETRO_DEVICE_ID_JOYPAD_R2 13 -#define RETRO_DEVICE_ID_JOYPAD_L3 14 -#define RETRO_DEVICE_ID_JOYPAD_R3 15 - -/* Index / Id values for ANALOG device. */ -#define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 -#define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 -#define RETRO_DEVICE_ID_ANALOG_X 0 -#define RETRO_DEVICE_ID_ANALOG_Y 1 - -/* Id values for MOUSE. */ -#define RETRO_DEVICE_ID_MOUSE_X 0 -#define RETRO_DEVICE_ID_MOUSE_Y 1 -#define RETRO_DEVICE_ID_MOUSE_LEFT 2 -#define RETRO_DEVICE_ID_MOUSE_RIGHT 3 -#define RETRO_DEVICE_ID_MOUSE_WHEELUP 4 -#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5 -#define RETRO_DEVICE_ID_MOUSE_MIDDLE 6 -#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP 7 -#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN 8 - -/* Id values for LIGHTGUN types. */ -#define RETRO_DEVICE_ID_LIGHTGUN_X 0 -#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 -#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2 -#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 -#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 -#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 -#define RETRO_DEVICE_ID_LIGHTGUN_START 6 - -/* Id values for POINTER. */ -#define RETRO_DEVICE_ID_POINTER_X 0 -#define RETRO_DEVICE_ID_POINTER_Y 1 -#define RETRO_DEVICE_ID_POINTER_PRESSED 2 - -/* Returned from retro_get_region(). */ -#define RETRO_REGION_NTSC 0 -#define RETRO_REGION_PAL 1 - -/* Id values for LANGUAGE */ -enum retro_language -{ - RETRO_LANGUAGE_ENGLISH = 0, - RETRO_LANGUAGE_JAPANESE = 1, - RETRO_LANGUAGE_FRENCH = 2, - RETRO_LANGUAGE_SPANISH = 3, - RETRO_LANGUAGE_GERMAN = 4, - RETRO_LANGUAGE_ITALIAN = 5, - RETRO_LANGUAGE_DUTCH = 6, - RETRO_LANGUAGE_PORTUGUESE = 7, - RETRO_LANGUAGE_RUSSIAN = 8, - RETRO_LANGUAGE_KOREAN = 9, - RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10, - RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 11, - RETRO_LANGUAGE_ESPERANTO = 12, - RETRO_LANGUAGE_POLISH = 13, - RETRO_LANGUAGE_LAST, - - /* Ensure sizeof(enum) == sizeof(int) */ - RETRO_LANGUAGE_DUMMY = INT_MAX -}; - -/* Passed to retro_get_memory_data/size(). - * If the memory type doesn't apply to the - * implementation NULL/0 can be returned. - */ -#define RETRO_MEMORY_MASK 0xff - -/* Regular save RAM. This RAM is usually found on a game cartridge, - * backed up by a battery. - * If save game data is too complex for a single memory buffer, - * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment - * callback can be used. */ -#define RETRO_MEMORY_SAVE_RAM 0 - -/* Some games have a built-in clock to keep track of time. - * This memory is usually just a couple of bytes to keep track of time. - */ -#define RETRO_MEMORY_RTC 1 - -/* System ram lets a frontend peek into a game systems main RAM. */ -#define RETRO_MEMORY_SYSTEM_RAM 2 - -/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */ -#define RETRO_MEMORY_VIDEO_RAM 3 - -/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */ -enum retro_key -{ - RETROK_UNKNOWN = 0, - RETROK_FIRST = 0, - RETROK_BACKSPACE = 8, - RETROK_TAB = 9, - RETROK_CLEAR = 12, - RETROK_RETURN = 13, - RETROK_PAUSE = 19, - RETROK_ESCAPE = 27, - RETROK_SPACE = 32, - RETROK_EXCLAIM = 33, - RETROK_QUOTEDBL = 34, - RETROK_HASH = 35, - RETROK_DOLLAR = 36, - RETROK_AMPERSAND = 38, - RETROK_QUOTE = 39, - RETROK_LEFTPAREN = 40, - RETROK_RIGHTPAREN = 41, - RETROK_ASTERISK = 42, - RETROK_PLUS = 43, - RETROK_COMMA = 44, - RETROK_MINUS = 45, - RETROK_PERIOD = 46, - RETROK_SLASH = 47, - RETROK_0 = 48, - RETROK_1 = 49, - RETROK_2 = 50, - RETROK_3 = 51, - RETROK_4 = 52, - RETROK_5 = 53, - RETROK_6 = 54, - RETROK_7 = 55, - RETROK_8 = 56, - RETROK_9 = 57, - RETROK_COLON = 58, - RETROK_SEMICOLON = 59, - RETROK_LESS = 60, - RETROK_EQUALS = 61, - RETROK_GREATER = 62, - RETROK_QUESTION = 63, - RETROK_AT = 64, - RETROK_LEFTBRACKET = 91, - RETROK_BACKSLASH = 92, - RETROK_RIGHTBRACKET = 93, - RETROK_CARET = 94, - RETROK_UNDERSCORE = 95, - RETROK_BACKQUOTE = 96, - RETROK_a = 97, - RETROK_b = 98, - RETROK_c = 99, - RETROK_d = 100, - RETROK_e = 101, - RETROK_f = 102, - RETROK_g = 103, - RETROK_h = 104, - RETROK_i = 105, - RETROK_j = 106, - RETROK_k = 107, - RETROK_l = 108, - RETROK_m = 109, - RETROK_n = 110, - RETROK_o = 111, - RETROK_p = 112, - RETROK_q = 113, - RETROK_r = 114, - RETROK_s = 115, - RETROK_t = 116, - RETROK_u = 117, - RETROK_v = 118, - RETROK_w = 119, - RETROK_x = 120, - RETROK_y = 121, - RETROK_z = 122, - RETROK_DELETE = 127, - - RETROK_KP0 = 256, - RETROK_KP1 = 257, - RETROK_KP2 = 258, - RETROK_KP3 = 259, - RETROK_KP4 = 260, - RETROK_KP5 = 261, - RETROK_KP6 = 262, - RETROK_KP7 = 263, - RETROK_KP8 = 264, - RETROK_KP9 = 265, - RETROK_KP_PERIOD = 266, - RETROK_KP_DIVIDE = 267, - RETROK_KP_MULTIPLY = 268, - RETROK_KP_MINUS = 269, - RETROK_KP_PLUS = 270, - RETROK_KP_ENTER = 271, - RETROK_KP_EQUALS = 272, - - RETROK_UP = 273, - RETROK_DOWN = 274, - RETROK_RIGHT = 275, - RETROK_LEFT = 276, - RETROK_INSERT = 277, - RETROK_HOME = 278, - RETROK_END = 279, - RETROK_PAGEUP = 280, - RETROK_PAGEDOWN = 281, - - RETROK_F1 = 282, - RETROK_F2 = 283, - RETROK_F3 = 284, - RETROK_F4 = 285, - RETROK_F5 = 286, - RETROK_F6 = 287, - RETROK_F7 = 288, - RETROK_F8 = 289, - RETROK_F9 = 290, - RETROK_F10 = 291, - RETROK_F11 = 292, - RETROK_F12 = 293, - RETROK_F13 = 294, - RETROK_F14 = 295, - RETROK_F15 = 296, - - RETROK_NUMLOCK = 300, - RETROK_CAPSLOCK = 301, - RETROK_SCROLLOCK = 302, - RETROK_RSHIFT = 303, - RETROK_LSHIFT = 304, - RETROK_RCTRL = 305, - RETROK_LCTRL = 306, - RETROK_RALT = 307, - RETROK_LALT = 308, - RETROK_RMETA = 309, - RETROK_LMETA = 310, - RETROK_LSUPER = 311, - RETROK_RSUPER = 312, - RETROK_MODE = 313, - RETROK_COMPOSE = 314, - - RETROK_HELP = 315, - RETROK_PRINT = 316, - RETROK_SYSREQ = 317, - RETROK_BREAK = 318, - RETROK_MENU = 319, - RETROK_POWER = 320, - RETROK_EURO = 321, - RETROK_UNDO = 322, - - RETROK_LAST, - - RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ -}; - -enum retro_mod -{ - RETROKMOD_NONE = 0x0000, - - RETROKMOD_SHIFT = 0x01, - RETROKMOD_CTRL = 0x02, - RETROKMOD_ALT = 0x04, - RETROKMOD_META = 0x08, - - RETROKMOD_NUMLOCK = 0x10, - RETROKMOD_CAPSLOCK = 0x20, - RETROKMOD_SCROLLOCK = 0x40, - - RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */ -}; - -/* If set, this call is not part of the public libretro API yet. It can - * change or be removed at any time. */ -#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000 -/* Environment callback to be used internally in frontend. */ -#define RETRO_ENVIRONMENT_PRIVATE 0x20000 - -/* Environment commands. */ -#define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- - * Sets screen rotation of graphics. - * Is only implemented if rotation can be accelerated by hardware. - * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, - * 270 degrees counter-clockwise respectively. - */ -#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- - * Boolean value whether or not the implementation should use overscan, - * or crop away overscan. - */ -#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 /* bool * -- - * Boolean value whether or not frontend supports frame duping, - * passing NULL to video frame callback. - */ - - /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), - * and reserved to avoid possible ABI clash. - */ - -#define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * -- - * Sets a message to be displayed in implementation-specific manner - * for a certain amount of 'frames'. - * Should not be used for trivial messages, which should simply be - * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a - * fallback, stderr). - */ -#define RETRO_ENVIRONMENT_SHUTDOWN 7 /* N/A (NULL) -- - * Requests the frontend to shutdown. - * Should only be used if game has a specific - * way to shutdown the game from a menu item or similar. - */ -#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8 - /* const unsigned * -- - * Gives a hint to the frontend how demanding this implementation - * is on a system. E.g. reporting a level of 2 means - * this implementation should run decently on all frontends - * of level 2 and up. - * - * It can be used by the frontend to potentially warn - * about too demanding implementations. - * - * The levels are "floating". - * - * This function can be called on a per-game basis, - * as certain games an implementation can play might be - * particularly demanding. - * If called, it should be called in retro_load_game(). - */ -#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9 - /* const char ** -- - * Returns the "system" directory of the frontend. - * This directory can be used to store system specific - * content such as BIOSes, configuration data, etc. - * The returned value can be NULL. - * If so, no such directory is defined, - * and it's up to the implementation to find a suitable directory. - * - * NOTE: Some cores used this folder also for "save" data such as - * memory cards, etc, for lack of a better place to put it. - * This is now discouraged, and if possible, cores should try to - * use the new GET_SAVE_DIRECTORY. - */ -#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10 - /* const enum retro_pixel_format * -- - * Sets the internal pixel format used by the implementation. - * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555. - * This pixel format however, is deprecated (see enum retro_pixel_format). - * If the call returns false, the frontend does not support this pixel - * format. - * - * This function should be called inside retro_load_game() or - * retro_get_system_av_info(). - */ -#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11 - /* const struct retro_input_descriptor * -- - * Sets an array of retro_input_descriptors. - * It is up to the frontend to present this in a usable way. - * The array is terminated by retro_input_descriptor::description - * being set to NULL. - * This function can be called at any time, but it is recommended - * to call it as early as possible. - */ -#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12 - /* const struct retro_keyboard_callback * -- - * Sets a callback function used to notify core about keyboard events. - */ -#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13 - /* const struct retro_disk_control_callback * -- - * Sets an interface which frontend can use to eject and insert - * disk images. - * This is used for games which consist of multiple images and - * must be manually swapped out by the user (e.g. PSX). - */ -#define RETRO_ENVIRONMENT_SET_HW_RENDER 14 - /* struct retro_hw_render_callback * -- - * Sets an interface to let a libretro core render with - * hardware acceleration. - * Should be called in retro_load_game(). - * If successful, libretro cores will be able to render to a - * frontend-provided framebuffer. - * The size of this framebuffer will be at least as large as - * max_width/max_height provided in get_av_info(). - * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or - * NULL to retro_video_refresh_t. - */ -#define RETRO_ENVIRONMENT_GET_VARIABLE 15 - /* struct retro_variable * -- - * Interface to acquire user-defined information from environment - * that cannot feasibly be supported in a multi-system way. - * 'key' should be set to a key which has already been set by - * SET_VARIABLES. - * 'data' will be set to a value or NULL. - */ -#define RETRO_ENVIRONMENT_SET_VARIABLES 16 - /* const struct retro_variable * -- - * Allows an implementation to signal the environment - * which variables it might want to check for later using - * 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). - * - * 'data' points to an array of retro_variable structs - * terminated by a { NULL, NULL } element. - * retro_variable::key should be namespaced to not collide - * with other implementations' keys. E.g. A core called - * 'foo' should use keys named as 'foo_option'. - * retro_variable::value should contain a human readable - * description of the key as well as a '|' delimited list - * of expected values. - * - * The number of possible options should be very limited, - * i.e. it should be feasible to cycle through options - * without a keyboard. - * - * First entry should be treated as a default. - * - * Example entry: - * { "foo_option", "Speed hack coprocessor X; false|true" } - * - * Text before first ';' is description. This ';' must be - * followed by a space, and followed by a list of possible - * values split up with '|'. - * - * Only strings are operated on. The possible values will - * generally be displayed and stored as-is by the frontend. - */ -#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17 - /* bool * -- - * Result is set to true if some variables are updated by - * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. - * Variables should be queried with GET_VARIABLE. - */ -#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 - /* const bool * -- - * If true, the libretro implementation supports calls to - * retro_load_game() with NULL as argument. - * Used by cores which can run without particular game data. - * This should be called within retro_set_environment() only. - */ -#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19 - /* const char ** -- - * Retrieves the absolute path from where this libretro - * implementation was loaded. - * NULL is returned if the libretro was loaded statically - * (i.e. linked statically to frontend), or if the path cannot be - * determined. - * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can - * be loaded without ugly hacks. - */ - - /* 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_AUDIO_CALLBACK 22 - /* const struct retro_audio_callback * -- - * Sets an interface which is used to notify a libretro core about audio - * being available for writing. - * The callback can be called from any thread, so a core using this must - * have a thread safe audio implementation. - * It is intended for games where audio and video are completely - * asynchronous and audio can be generated on the fly. - * This interface is not recommended for use with emulators which have - * highly synchronous audio. - * - * The callback only notifies about writability; the libretro core still - * has to call the normal audio callbacks - * to write audio. The audio callbacks must be called from within the - * notification callback. - * The amount of audio data to write is up to the implementation. - * Generally, the audio callback will be called continously in a loop. - * - * Due to thread safety guarantees and lack of sync between audio and - * video, a frontend can selectively disallow this interface based on - * internal configuration. A core using this interface must also - * implement the "normal" audio interface. - * - * 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 - * state of rumble motors in controllers. - * A strong and weak motor is supported, and they can be - * controlled indepedently. - */ -#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24 - /* uint64_t * -- - * Gets a bitmask telling which device type are expected to be - * handled properly in a call to retro_input_state_t. - * Devices which are not handled or recognized always return - * 0 in retro_input_state_t. - * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG). - * Should only be called in retro_run(). - */ -#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_sensor_interface * -- - * Gets access to the sensor interface. - * The purpose of this interface is to allow - * setting state related to sensors such as polling rate, - * enabling/disable it entirely, etc. - * Reading sensor state is done via the normal - * input_state_callback API. - */ -#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_camera_callback * -- - * Gets an interface to a video camera driver. - * A libretro core can use this interface to get access to a - * video camera. - * New video frames are delivered in a callback in same - * thread as retro_run(). - * - * GET_CAMERA_INTERFACE should be called in retro_load_game(). - * - * Depending on the camera implementation used, camera frames - * will be delivered as a raw framebuffer, - * or as an OpenGL texture directly. - * - * The core has to tell the frontend here which types of - * buffers can be handled properly. - * An OpenGL texture can only be handled when using a - * libretro GL core (SET_HW_RENDER). - * It is recommended to use a libretro GL core when - * using camera interface. - * - * The camera is not started automatically. The retrieved start/stop - * functions must be used to explicitly - * start and stop the camera driver. - */ -#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27 - /* struct retro_log_callback * -- - * Gets an interface for logging. This is useful for - * logging in a cross-platform way - * as certain platforms cannot use use stderr for logging. - * It also allows the frontend to - * show logging information in a more suitable way. - * If this interface is not used, libretro cores should - * log to stderr as desired. - */ -#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28 - /* struct retro_perf_callback * -- - * Gets an interface for performance counters. This is useful - * for performance logging in a cross-platform way and for detecting - * architecture-specific features, such as SIMD support. - */ -#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29 - /* struct retro_location_callback * -- - * Gets access to the location interface. - * The purpose of this interface is to be able to retrieve - * location-based information from the host device, - * such as current latitude / longitude. - */ -#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */ -#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30 - /* const char ** -- - * Returns the "core assets" directory of the frontend. - * This directory can be used to store specific assets that the - * core relies upon, such as art assets, - * input data, etc etc. - * The returned value can be NULL. - * If so, no such directory is defined, - * and it's up to the implementation to find a suitable directory. - */ -#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 - * 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. - */ -#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32 - /* const struct retro_system_av_info * -- - * Sets a new av_info structure. This can only be called from - * within retro_run(). - * This should *only* be used if the core is completely altering the - * internal resolutions, aspect ratios, timings, sampling rate, etc. - * Calling this can require a full reinitialization of video/audio - * drivers in the frontend, - * - * so it is important to call it very sparingly, and usually only with - * the users explicit consent. - * An eventual driver reinitialize will happen so that video and - * audio callbacks - * happening after this call within the same retro_run() call will - * target the newly initialized driver. - * - * This callback makes it possible to support configurable resolutions - * in games, which can be useful to - * avoid setting the "worst case" in max_width/max_height. - * - * ***HIGHLY RECOMMENDED*** Do not call this callback every time - * resolution changes in an emulator core if it's - * expected to be a temporary change, for the reasons of possible - * driver reinitialization. - * This call is not a free pass for not trying to provide - * correct values in retro_get_system_av_info(). If you need to change - * things like aspect ratio or nominal width/height, - * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant - * of SET_SYSTEM_AV_INFO. - * - * If this returns false, the frontend does not acknowledge a - * changed av_info struct. - */ -#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33 - /* const struct retro_get_proc_address_interface * -- - * Allows a libretro core to announce support for the - * get_proc_address() interface. - * This interface allows for a standard way to extend libretro where - * use of environment calls are too indirect, - * e.g. for cases where the frontend wants to call directly into the core. - * - * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK - * **MUST** be called from within retro_set_environment(). - */ -#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34 - /* const struct retro_subsystem_info * -- - * This environment call introduces the concept of libretro "subsystems". - * A subsystem is a variant of a libretro core which supports - * different kinds of games. - * The purpose of this is to support e.g. emulators which might - * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo. - * It can also be used to pick among subsystems in an explicit way - * if the libretro implementation is a multi-system emulator itself. - * - * Loading a game via a subsystem is done with retro_load_game_special(), - * and this environment call allows a libretro core to expose which - * subsystems are supported for use with retro_load_game_special(). - * A core passes an array of retro_game_special_info which is terminated - * with a zeroed out retro_game_special_info struct. - * - * If a core wants to use this functionality, SET_SUBSYSTEM_INFO - * **MUST** be called from within retro_set_environment(). - */ -#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 - * 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. - * - * 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. - * - * 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, - * libretro should only poll input based on the base input device types. - */ -#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* const struct retro_memory_map * -- - * This environment call lets a libretro core tell the frontend - * about the memory maps this core emulates. - * This can be used to implement, for example, cheats in a core-agnostic way. - * - * Should only be used by emulators; it doesn't make much sense for - * anything else. - * It is recommended to expose all relevant pointers through - * retro_get_memory_* as well. - * - * Can be called from retro_init and retro_load_game. - */ -#define RETRO_ENVIRONMENT_SET_GEOMETRY 37 - /* const struct retro_game_geometry * -- - * This environment call is similar to SET_SYSTEM_AV_INFO for changing - * video parameters, but provides a guarantee that drivers will not be - * reinitialized. - * This can only be called from within retro_run(). - * - * The purpose of this call is to allow a core to alter nominal - * width/heights as well as aspect ratios on-the-fly, which can be - * useful for some emulators to change in run-time. - * - * max_width/max_height arguments are ignored and cannot be changed - * with this call as this could potentially require a reinitialization or a - * non-constant time operation. - * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required. - * - * A frontend must guarantee that this environment call completes in - * constant time. - */ -#define RETRO_ENVIRONMENT_GET_USERNAME 38 - /* const char ** - * Returns the specified username of the frontend, if specified by the user. - * This username can be used as a nickname for a core that has online facilities - * or any other mode where personalization of the user is desirable. - * The returned value can be NULL. - * If this environ callback is used by a core that requires a valid username, - * a default username should be specified by the core. - */ -#define RETRO_ENVIRONMENT_GET_LANGUAGE 39 - /* unsigned * -- - * Returns the specified language of the frontend, if specified by the user. - * It can be used by the core for localization purposes. - */ -#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL) - /* struct retro_framebuffer * -- - * Returns a preallocated framebuffer which the core can use for rendering - * the frame into when not using SET_HW_RENDER. - * The framebuffer returned from this call must not be used - * after the current call to retro_run() returns. - * - * The goal of this call is to allow zero-copy behavior where a core - * can render directly into video memory, avoiding extra bandwidth cost by copying - * memory from core to video memory. - * - * If this call succeeds and the core renders into it, - * the framebuffer pointer and pitch can be passed to retro_video_refresh_t. - * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used, - * the core must pass the exact - * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER; - * i.e. passing a pointer which is offset from the - * buffer is undefined. The width, height and pitch parameters - * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER. - * - * It is possible for a frontend to return a different pixel format - * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend - * needs to perform conversion. - * - * It is still valid for a core to render to a different buffer - * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds. - * - * A frontend must make sure that the pointer obtained from this function is - * writeable (and readable). - */ - -#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. - */ -enum retro_hw_render_interface_type -{ - RETRO_HW_RENDER_INTERFACE_VULKAN = 0, - RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX -}; - -/* Base struct. All retro_hw_render_interface_* types - * contain at least these fields. */ -struct retro_hw_render_interface -{ - enum retro_hw_render_interface_type interface_type; - unsigned interface_version; -}; -#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. - */ - -enum retro_hw_render_context_negotiation_interface_type -{ - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0, - RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX -}; - -/* Base struct. All retro_hw_render_context_negotiation_interface_* types - * contain at least these fields. */ -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. - */ - -#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) -struct retro_memory_descriptor -{ - uint64_t flags; - - /* Pointer to the start of the relevant ROM or RAM chip. - * It's strongly recommended to use 'offset' if possible, rather than - * doing math on the pointer. - * - * If the same byte is mapped my multiple descriptors, their descriptors - * must have the same pointer. - * If 'start' does not point to the first byte in the pointer, put the - * difference in 'offset' instead. - * - * May be NULL if there's nothing usable here (e.g. hardware registers and - * open bus). No flags should be set if the pointer is NULL. - * It's recommended to minimize the number of descriptors if possible, - * but not mandatory. */ - void *ptr; - size_t offset; - - /* This is the location in the emulated address space - * where the mapping starts. */ - size_t start; - - /* Which bits must be same as in 'start' for this mapping to apply. - * The first memory descriptor to claim a certain byte is the one - * that applies. - * A bit which is set in 'start' must also be set in this. - * Can be zero, in which case each byte is assumed mapped exactly once. - * In this case, 'len' must be a power of two. */ - size_t select; - - /* If this is nonzero, the set bits are assumed not connected to the - * memory chip's address pins. */ - size_t disconnect; - - /* This one tells the size of the current memory area. - * If, after start+disconnect are applied, the address is higher than - * this, the highest bit of the address is cleared. - * - * If the address is still too high, the next highest bit is cleared. - * Can be zero, in which case it's assumed to be infinite (as limited - * by 'select' and 'disconnect'). */ - size_t len; - - /* To go from emulated address to physical address, the following - * order applies: - * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */ - - /* The address space name must consist of only a-zA-Z0-9_-, - * should be as short as feasible (maximum length is 8 plus the NUL), - * and may not be any other address space plus one or more 0-9A-F - * at the end. - * However, multiple memory descriptors for the same address space is - * allowed, and the address space name can be empty. NULL is treated - * as empty. - * - * Address space names are case sensitive, but avoid lowercase if possible. - * The same pointer may exist in multiple address spaces. - * - * Examples: - * blank+blank - valid (multiple things may be mapped in the same namespace) - * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace) - * 'A'+'B' - valid (neither is a prefix of each other) - * 'S'+blank - valid ('S' is not in 0-9A-F) - * 'a'+blank - valid ('a' is not in 0-9A-F) - * 'a'+'A' - valid (neither is a prefix of each other) - * 'AR'+blank - valid ('R' is not in 0-9A-F) - * 'ARB'+blank - valid (the B can't be part of the address either, because - * there is no namespace 'AR') - * blank+'B' - not valid, because it's ambigous which address space B1234 - * would refer to. - * The length can't be used for that purpose; the frontend may want - * to append arbitrary data to an address, without a separator. */ - const char *addrspace; - - /* TODO: When finalizing this one, add a description field, which should be - * "WRAM" or something roughly equally long. */ - - /* TODO: When finalizing this one, replace 'select' with 'limit', which tells - * which bits can vary and still refer to the same address (limit = ~select). - * TODO: limit? range? vary? something else? */ - - /* TODO: When finalizing this one, if 'len' is above what 'select' (or - * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len' - * and 'select' != 0, and the mappings don't tell how the system switches the - * banks. */ - - /* TODO: When finalizing this one, fix the 'len' bit removal order. - * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00. - * Algorithm: Take bits highest to lowest, but if it goes above len, clear - * the most recent addition and continue on the next bit. - * TODO: Can the above be optimized? Is "remove the lowest bit set in both - * pointer and 'len'" equivalent? */ - - /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing - * the emulated memory in 32-bit chunks, native endian. But that's nothing - * compared to Darek Mihocka - * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE - * RAM backwards! I'll want to represent both of those, via some flags. - * - * I suspect MAME either didn't think of that idea, or don't want the #ifdef. - * Not sure which, nor do I really care. */ - - /* TODO: Some of those flags are unused and/or don't really make sense. Clean - * them up. */ -}; - -/* The frontend may use the largest value of 'start'+'select' in a - * certain namespace to infer the size of the address space. - * - * If the address space is larger than that, a mapping with .ptr=NULL - * should be at the end of the array, with .select set to all ones for - * as long as the address space is big. - * - * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags): - * SNES WRAM: - * .start=0x7E0000, .len=0x20000 - * (Note that this must be mapped before the ROM in most cases; some of the - * ROM mappers - * try to claim $7E0000, or at least $7E8000.) - * SNES SPC700 RAM: - * .addrspace="S", .len=0x10000 - * SNES WRAM mirrors: - * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000 - * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000 - * SNES WRAM mirrors, alternate equivalent descriptor: - * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF - * (Various similar constructions can be created by combining parts of - * the above two.) - * SNES LoROM (512KB, mirrored a couple of times): - * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024 - * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024 - * SNES HiROM (4MB): - * .flags=CONST, .start=0x400000, .select=0x400000, .len=4*1024*1024 - * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024 - * SNES ExHiROM (8MB): - * .flags=CONST, .offset=0, .start=0xC00000, .select=0xC00000, .len=4*1024*1024 - * .flags=CONST, .offset=4*1024*1024, .start=0x400000, .select=0xC00000, .len=4*1024*1024 - * .flags=CONST, .offset=0x8000, .start=0x808000, .select=0xC08000, .len=4*1024*1024 - * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024 - * Clarify the size of the address space: - * .ptr=NULL, .select=0xFFFFFF - * .len can be implied by .select in many of them, but was included for clarity. - */ - -struct retro_memory_map -{ - const struct retro_memory_descriptor *descriptors; - unsigned num_descriptors; -}; - -struct retro_controller_description -{ - /* Human-readable description of the controller. Even if using a generic - * input device type, this can be set to the particular device type the - * core uses. */ - const char *desc; - - /* Device type passed to retro_set_controller_port_device(). If the device - * type is a sub-class of a generic input device type, use the - * RETRO_DEVICE_SUBCLASS macro to create an ID. - * - * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */ - unsigned id; -}; - -struct retro_controller_info -{ - const struct retro_controller_description *types; - unsigned num_types; -}; - -struct retro_subsystem_memory_info -{ - /* The extension associated with a memory type, e.g. "psram". */ - const char *extension; - - /* The memory type for retro_get_memory(). This should be at - * least 0x100 to avoid conflict with standardized - * libretro memory types. */ - unsigned type; -}; - -struct retro_subsystem_rom_info -{ - /* Describes what the content is (SGB BIOS, GB ROM, etc). */ - const char *desc; - - /* Same definition as retro_get_system_info(). */ - const char *valid_extensions; - - /* Same definition as retro_get_system_info(). */ - bool need_fullpath; - - /* Same definition as retro_get_system_info(). */ - bool block_extract; - - /* This is set if the content is required to load a game. - * If this is set to false, a zeroed-out retro_game_info can be passed. */ - bool required; - - /* Content can have multiple associated persistent - * memory types (retro_get_memory()). */ - const struct retro_subsystem_memory_info *memory; - unsigned num_memory; -}; - -struct retro_subsystem_info -{ - /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */ - const char *desc; - - /* A computer friendly short string identifier for the subsystem type. - * This name must be [a-z]. - * E.g. if desc is "Super GameBoy", this can be "sgb". - * This identifier can be used for command-line interfaces, etc. - */ - const char *ident; - - /* Infos for each content file. The first entry is assumed to be the - * "most significant" content for frontend purposes. - * E.g. with Super GameBoy, the first content should be the GameBoy ROM, - * as it is the most "significant" content to a user. - * If a frontend creates new file paths based on the content used - * (e.g. savestates), it should use the path for the first ROM to do so. */ - const struct retro_subsystem_rom_info *roms; - - /* Number of content files associated with a subsystem. */ - unsigned num_roms; - - /* The type passed to retro_load_game_special(). */ - unsigned id; -}; - -typedef void (RETRO_CALLCONV *retro_proc_address_t)(void); - -/* libretro API extension functions: - * (None here so far). - * - * Get a symbol from a libretro core. - * Cores should only return symbols which are actual - * extensions to the libretro API. - * - * Frontends should not use this to obtain symbols to standard - * libretro entry points (static linking or dlsym). - * - * The symbol name must be equal to the function name, - * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo". - * The returned function pointer must be cast to the corresponding type. - */ -typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym); - -struct retro_get_proc_address_interface -{ - retro_get_proc_address_t get_proc_address; -}; - -enum retro_log_level -{ - RETRO_LOG_DEBUG = 0, - RETRO_LOG_INFO, - RETRO_LOG_WARN, - RETRO_LOG_ERROR, - - RETRO_LOG_DUMMY = INT_MAX -}; - -/* Logging function. Takes log level argument as well. */ -typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level, - const char *fmt, ...); - -struct retro_log_callback -{ - retro_log_printf_t log; -}; - -/* Performance related functions */ - -/* ID values for SIMD CPU features */ -#define RETRO_SIMD_SSE (1 << 0) -#define RETRO_SIMD_SSE2 (1 << 1) -#define RETRO_SIMD_VMX (1 << 2) -#define RETRO_SIMD_VMX128 (1 << 3) -#define RETRO_SIMD_AVX (1 << 4) -#define RETRO_SIMD_NEON (1 << 5) -#define RETRO_SIMD_SSE3 (1 << 6) -#define RETRO_SIMD_SSSE3 (1 << 7) -#define RETRO_SIMD_MMX (1 << 8) -#define RETRO_SIMD_MMXEXT (1 << 9) -#define RETRO_SIMD_SSE4 (1 << 10) -#define RETRO_SIMD_SSE42 (1 << 11) -#define RETRO_SIMD_AVX2 (1 << 12) -#define RETRO_SIMD_VFPU (1 << 13) -#define RETRO_SIMD_PS (1 << 14) -#define RETRO_SIMD_AES (1 << 15) -#define RETRO_SIMD_VFPV3 (1 << 16) -#define RETRO_SIMD_VFPV4 (1 << 17) -#define RETRO_SIMD_POPCNT (1 << 18) -#define RETRO_SIMD_MOVBE (1 << 19) - -typedef uint64_t retro_perf_tick_t; -typedef int64_t retro_time_t; - -struct retro_perf_counter -{ - const char *ident; - retro_perf_tick_t start; - retro_perf_tick_t total; - retro_perf_tick_t call_cnt; - - bool registered; -}; - -/* Returns current time in microseconds. - * Tries to use the most accurate timer available. - */ -typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void); - -/* A simple counter. Usually nanoseconds, but can also be CPU cycles. - * Can be used directly if desired (when creating a more sophisticated - * performance counter system). - * */ -typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void); - -/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */ -typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void); - -/* Asks frontend to log and/or display the state of performance counters. - * Performance counters can always be poked into manually as well. - */ -typedef void (RETRO_CALLCONV *retro_perf_log_t)(void); - -/* Register a performance counter. - * ident field must be set with a discrete value and other values in - * retro_perf_counter must be 0. - * Registering can be called multiple times. To avoid calling to - * frontend redundantly, you can check registered field first. */ -typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter); - -/* Starts a registered counter. */ -typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter); - -/* Stops a registered counter. */ -typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter); - -/* For convenience it can be useful to wrap register, start and stop in macros. - * E.g.: - * #ifdef LOG_PERFORMANCE - * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name)) - * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name)) - * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name)) - * #else - * ... Blank macros ... - * #endif - * - * These can then be used mid-functions around code snippets. - * - * extern struct retro_perf_callback perf_cb; * Somewhere in the core. - * - * void do_some_heavy_work(void) - * { - * RETRO_PERFORMANCE_INIT(cb, work_1; - * RETRO_PERFORMANCE_START(cb, work_1); - * heavy_work_1(); - * RETRO_PERFORMANCE_STOP(cb, work_1); - * - * RETRO_PERFORMANCE_INIT(cb, work_2); - * RETRO_PERFORMANCE_START(cb, work_2); - * heavy_work_2(); - * RETRO_PERFORMANCE_STOP(cb, work_2); - * } - * - * void retro_deinit(void) - * { - * perf_cb.perf_log(); * Log all perf counters here for example. - * } - */ - -struct retro_perf_callback -{ - retro_perf_get_time_usec_t get_time_usec; - retro_get_cpu_features_t get_cpu_features; - - retro_perf_get_counter_t get_perf_counter; - retro_perf_register_t perf_register; - retro_perf_start_t perf_start; - retro_perf_stop_t perf_stop; - retro_perf_log_t perf_log; -}; - -/* FIXME: Document the sensor API and work out behavior. - * It will be marked as experimental until then. - */ -enum retro_sensor_action -{ - RETRO_SENSOR_ACCELEROMETER_ENABLE = 0, - RETRO_SENSOR_ACCELEROMETER_DISABLE, - - RETRO_SENSOR_DUMMY = INT_MAX -}; - -/* Id values for SENSOR types. */ -#define RETRO_SENSOR_ACCELEROMETER_X 0 -#define RETRO_SENSOR_ACCELEROMETER_Y 1 -#define RETRO_SENSOR_ACCELEROMETER_Z 2 - -typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port, - enum retro_sensor_action action, unsigned rate); - -typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id); - -struct retro_sensor_interface -{ - retro_set_sensor_state_t set_sensor_state; - retro_sensor_get_input_t get_sensor_input; -}; - -enum retro_camera_buffer -{ - RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0, - RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER, - - RETRO_CAMERA_BUFFER_DUMMY = INT_MAX -}; - -/* Starts the camera driver. Can only be called in retro_run(). */ -typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void); - -/* Stops the camera driver. Can only be called in retro_run(). */ -typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void); - -/* Callback which signals when the camera driver is initialized - * and/or deinitialized. - * retro_camera_start_t can be called in initialized callback. - */ -typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void); - -/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer. - * Width, height and pitch are similar to retro_video_refresh_t. - * First pixel is top-left origin. - */ -typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, - unsigned width, unsigned height, size_t pitch); - -/* A callback for when OpenGL textures are used. - * - * texture_id is a texture owned by camera driver. - * Its state or content should be considered immutable, except for things like - * texture filtering and clamping. - * - * texture_target is the texture target for the GL texture. - * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly - * more depending on extensions. - * - * affine points to a packed 3x3 column-major matrix used to apply an affine - * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0)) - * After transform, normalized texture coord (0, 0) should be bottom-left - * and (1, 1) should be top-right (or (width, height) for RECTANGLE). - * - * GL-specific typedefs are avoided here to avoid relying on gl.h in - * the API definition. - */ -typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id, - unsigned texture_target, const float *affine); - -struct retro_camera_callback -{ - /* Set by libretro core. - * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER). - */ - uint64_t caps; - - /* Desired resolution for camera. Is only used as a hint. */ - unsigned width; - unsigned height; - - /* Set by frontend. */ - retro_camera_start_t start; - retro_camera_stop_t stop; - - /* Set by libretro core if raw framebuffer callbacks will be used. */ - retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer; - - /* Set by libretro core if OpenGL texture callbacks will be used. */ - retro_camera_frame_opengl_texture_t frame_opengl_texture; - - /* Set by libretro core. Called after camera driver is initialized and - * ready to be started. - * Can be NULL, in which this callback is not called. - */ - retro_camera_lifetime_status_t initialized; - - /* Set by libretro core. Called right before camera driver is - * deinitialized. - * Can be NULL, in which this callback is not called. - */ - retro_camera_lifetime_status_t deinitialized; -}; - -/* Sets the interval of time and/or distance at which to update/poll - * location-based data. - * - * To ensure compatibility with all location-based implementations, - * values for both interval_ms and interval_distance should be provided. - * - * interval_ms is the interval expressed in milliseconds. - * interval_distance is the distance interval expressed in meters. - */ -typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms, - unsigned interval_distance); - -/* Start location services. The device will start listening for changes to the - * current location at regular intervals (which are defined with - * retro_location_set_interval_t). */ -typedef bool (RETRO_CALLCONV *retro_location_start_t)(void); - -/* Stop location services. The device will stop listening for changes - * to the current location. */ -typedef void (RETRO_CALLCONV *retro_location_stop_t)(void); - -/* Get the position of the current location. Will set parameters to - * 0 if no new location update has happened since the last time. */ -typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon, - double *horiz_accuracy, double *vert_accuracy); - -/* Callback which signals when the location driver is initialized - * and/or deinitialized. - * retro_location_start_t can be called in initialized callback. - */ -typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void); - -struct retro_location_callback -{ - retro_location_start_t start; - retro_location_stop_t stop; - retro_location_get_position_t get_position; - retro_location_set_interval_t set_interval; - - retro_location_lifetime_status_t initialized; - retro_location_lifetime_status_t deinitialized; -}; - -enum retro_rumble_effect -{ - RETRO_RUMBLE_STRONG = 0, - RETRO_RUMBLE_WEAK = 1, - - RETRO_RUMBLE_DUMMY = INT_MAX -}; - -/* Sets rumble state for joypad plugged in port 'port'. - * Rumble effects are controlled independently, - * and setting e.g. strong rumble does not override weak rumble. - * Strength has a range of [0, 0xffff]. - * - * Returns true if rumble state request was honored. - * Calling this before first retro_run() is likely to return false. */ -typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port, - enum retro_rumble_effect effect, uint16_t strength); - -struct retro_rumble_interface -{ - retro_set_rumble_state_t set_rumble_state; -}; - -/* Notifies libretro that audio data should be written. */ -typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void); - -/* True: Audio driver in frontend is active, and callback is - * expected to be called regularily. - * False: Audio driver in frontend is paused or inactive. - * Audio callback will not be called until set_state has been - * called with true. - * Initial state is false (inactive). - */ -typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled); - -struct retro_audio_callback -{ - retro_audio_callback_t callback; - retro_audio_set_state_callback_t set_state; -}; - -/* Notifies a libretro core of time spent since last invocation - * of retro_run() in microseconds. - * - * It will be called right before retro_run() every frame. - * The frontend can tamper with timing to support cases like - * fast-forward, slow-motion and framestepping. - * - * In those scenarios the reference frame time value will be used. */ -typedef int64_t retro_usec_t; -typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec); -struct retro_frame_time_callback -{ - retro_frame_time_callback_t callback; - /* Represents the time of one frame. It is computed as - * 1000000 / fps, but the implementation will resolve the - * rounding to ensure that framestepping, etc is exact. */ - retro_usec_t reference; -}; - -/* Pass this to retro_video_refresh_t if rendering to hardware. - * Passing NULL to retro_video_refresh_t is still a frame dupe as normal. - * */ -#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1) - -/* Invalidates the current HW context. - * Any GL state is lost, and must not be deinitialized explicitly. - * If explicit deinitialization is desired by the libretro core, - * it should implement context_destroy callback. - * If called, all GPU resources must be reinitialized. - * Usually called when frontend reinits video driver. - * Also called first time video driver is initialized, - * allowing libretro core to initialize resources. - */ -typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void); - -/* Gets current framebuffer which is to be rendered to. - * Could change every frame potentially. - */ -typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void); - -/* Get a symbol from HW context. */ -typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym); - -enum retro_hw_context_type -{ - RETRO_HW_CONTEXT_NONE = 0, - /* OpenGL 2.x. Driver can choose to use latest compatibility context. */ - RETRO_HW_CONTEXT_OPENGL = 1, - /* OpenGL ES 2.0. */ - RETRO_HW_CONTEXT_OPENGLES2 = 2, - /* Modern desktop core GL context. Use version_major/ - * version_minor fields to set GL version. */ - RETRO_HW_CONTEXT_OPENGL_CORE = 3, - /* OpenGL ES 3.0 */ - RETRO_HW_CONTEXT_OPENGLES3 = 4, - /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3, - * use the corresponding enums directly. */ - RETRO_HW_CONTEXT_OPENGLES_VERSION = 5, - - /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */ - RETRO_HW_CONTEXT_VULKAN = 6, - - RETRO_HW_CONTEXT_DUMMY = INT_MAX -}; - -struct retro_hw_render_callback -{ - /* Which API to use. Set by libretro core. */ - enum retro_hw_context_type context_type; - - /* Called when a context has been created or when it has been reset. - * An OpenGL context is only valid after context_reset() has been called. - * - * When context_reset is called, OpenGL resources in the libretro - * implementation are guaranteed to be invalid. - * - * It is possible that context_reset is called multiple times during an - * application lifecycle. - * If context_reset is called without any notification (context_destroy), - * the OpenGL context was lost and resources should just be recreated - * without any attempt to "free" old resources. - */ - retro_hw_context_reset_t context_reset; - - /* Set by frontend. - * TODO: This is rather obsolete. The frontend should not - * be providing preallocated framebuffers. */ - retro_hw_get_current_framebuffer_t get_current_framebuffer; - - /* Set by frontend. */ - retro_hw_get_proc_address_t get_proc_address; - - /* Set if render buffers should have depth component attached. - * TODO: Obsolete. */ - bool depth; - - /* Set if stencil buffers should be attached. - * TODO: Obsolete. */ - bool stencil; - - /* If depth and stencil are true, a packed 24/8 buffer will be added. - * Only attaching stencil is invalid and will be ignored. */ - - /* Use conventional bottom-left origin convention. If false, - * standard libretro top-left origin semantics are used. - * TODO: Move to GL specific interface. */ - bool bottom_left_origin; - - /* Major version number for core GL context or GLES 3.1+. */ - unsigned version_major; - - /* Minor version number for core GL context or GLES 3.1+. */ - unsigned version_minor; - - /* If this is true, the frontend will go very far to avoid - * resetting context in scenarios like toggling fullscreen, etc. - * TODO: Obsolete? Maybe frontend should just always assume this ... - */ - bool cache_context; - - /* The reset callback might still be called in extreme situations - * such as if the context is lost beyond recovery. - * - * For optimal stability, set this to false, and allow context to be - * reset at any time. - */ - - /* A callback to be called before the context is destroyed in a - * controlled way by the frontend. */ - retro_hw_context_reset_t context_destroy; - - /* OpenGL resources can be deinitialized cleanly at this step. - * context_destroy can be set to NULL, in which resources will - * just be destroyed without any notification. - * - * Even when context_destroy is non-NULL, it is possible that - * context_reset is called without any destroy notification. - * This happens if context is lost by external factors (such as - * notified by GL_ARB_robustness). - * - * In this case, the context is assumed to be already dead, - * and the libretro implementation must not try to free any OpenGL - * resources in the subsequent context_reset. - */ - - /* Creates a debug context. */ - bool debug_context; -}; - -/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. - * Called by the frontend in response to keyboard events. - * down is set if the key is being pressed, or false if it is being released. - * keycode is the RETROK value of the char. - * character is the text character of the pressed key. (UTF-32). - * key_modifiers is a set of RETROKMOD values or'ed together. - * - * The pressed/keycode state can be indepedent of the character. - * It is also possible that multiple characters are generated from a - * single keypress. - * Keycode events should be treated separately from character events. - * However, when possible, the frontend should try to synchronize these. - * If only a character is posted, keycode should be RETROK_UNKNOWN. - * - * Similarily if only a keycode event is generated with no corresponding - * character, character should be 0. - */ -typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode, - uint32_t character, uint16_t key_modifiers); - -struct retro_keyboard_callback -{ - retro_keyboard_event_t callback; -}; - -/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE. - * Should be set for implementations which can swap out multiple disk - * images in runtime. - * - * If the implementation can do this automatically, it should strive to do so. - * However, there are cases where the user must manually do so. - * - * Overview: To swap a disk image, eject the disk image with - * set_eject_state(true). - * Set the disk index with set_image_index(index). Insert the disk again - * with set_eject_state(false). - */ - -/* If ejected is true, "ejects" the virtual disk tray. - * When ejected, the disk image index can be set. - */ -typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected); - -/* Gets current eject state. The initial state is 'not ejected'. */ -typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void); - -/* Gets current disk index. First disk is index 0. - * If return value is >= get_num_images(), no disk is currently inserted. - */ -typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void); - -/* Sets image index. Can only be called when disk is ejected. - * The implementation supports setting "no disk" by using an - * index >= get_num_images(). - */ -typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index); - -/* Gets total number of images which are available to use. */ -typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void); - -struct retro_game_info; - -/* Replaces the disk image associated with index. - * Arguments to pass in info have same requirements as retro_load_game(). - * Virtual disk tray must be ejected when calling this. - * - * Replacing a disk image with info = NULL will remove the disk image - * from the internal list. - * As a result, calls to get_image_index() can change. - * - * E.g. replace_image_index(1, NULL), and previous get_image_index() - * returned 4 before. - * Index 1 will be removed, and the new index is 3. - */ -typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index, - const struct retro_game_info *info); - -/* Adds a new valid index (get_num_images()) to the internal disk list. - * This will increment subsequent return values from get_num_images() by 1. - * This image index cannot be used until a disk image has been set - * with replace_image_index. */ -typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void); - -struct retro_disk_control_callback -{ - retro_set_eject_state_t set_eject_state; - retro_get_eject_state_t get_eject_state; - - retro_get_image_index_t get_image_index; - retro_set_image_index_t set_image_index; - retro_get_num_images_t get_num_images; - - retro_replace_image_index_t replace_image_index; - retro_add_image_index_t add_image_index; -}; - -enum retro_pixel_format -{ - /* 0RGB1555, native endian. - * 0 bit must be set to 0. - * This pixel format is default for compatibility concerns only. - * If a 15/16-bit pixel format is desired, consider using RGB565. */ - RETRO_PIXEL_FORMAT_0RGB1555 = 0, - - /* XRGB8888, native endian. - * X bits are ignored. */ - RETRO_PIXEL_FORMAT_XRGB8888 = 1, - - /* RGB565, native endian. - * This pixel format is the recommended format to use if a 15/16-bit - * format is desired as it is the pixel format that is typically - * available on a wide range of low-power devices. - * - * It is also natively supported in APIs like OpenGL ES. */ - RETRO_PIXEL_FORMAT_RGB565 = 2, - - /* Ensure sizeof() == sizeof(int). */ - RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX -}; - -struct retro_message -{ - const char *msg; /* Message to be displayed. */ - unsigned frames; /* Duration in frames of message. */ -}; - -/* Describes how the libretro implementation maps a libretro input bind - * to its internal input system through a human readable string. - * This string can be used to better let a user configure input. */ -struct retro_input_descriptor -{ - /* Associates given parameters with a description. */ - unsigned port; - unsigned device; - unsigned index; - unsigned id; - - /* Human readable description for parameters. - * The pointer must remain valid until - * retro_unload_game() is called. */ - const char *description; -}; - -struct retro_system_info -{ - /* All pointers are owned by libretro implementation, and pointers must - * remain valid until retro_deinit() is called. */ - - const char *library_name; /* Descriptive name of library. Should not - * contain any version numbers, etc. */ - const char *library_version; /* Descriptive version of core. */ - - const char *valid_extensions; /* A string listing probably content - * extensions the core will be able to - * load, separated with pipe. - * I.e. "bin|rom|iso". - * 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. - * - * If false, ::data and ::size are guaranteed to be valid, but ::path - * might not be valid. - * - * 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. */ - bool need_fullpath; - - /* If true, the frontend is not allowed to extract any archives before - * loading the real content. - * Necessary for certain libretro implementations that load games - * from zipped archives. */ - bool block_extract; -}; - -struct retro_game_geometry -{ - unsigned base_width; /* Nominal video width of game. */ - unsigned base_height; /* Nominal video height of game. */ - unsigned max_width; /* Maximum possible width of game. */ - unsigned max_height; /* Maximum possible height of game. */ - - float aspect_ratio; /* Nominal aspect ratio of game. If - * aspect_ratio is <= 0.0, an aspect ratio - * of base_width / base_height is assumed. - * A frontend could override this setting, - * if desired. */ -}; - -struct retro_system_timing -{ - double fps; /* FPS of video content. */ - double sample_rate; /* Sampling rate of audio. */ -}; - -struct retro_system_av_info -{ - struct retro_game_geometry geometry; - struct retro_system_timing timing; -}; - -struct retro_variable -{ - /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. - * If NULL, obtains the complete environment string if more - * complex parsing is necessary. - * The environment string is formatted as key-value pairs - * delimited by semicolons as so: - * "key1=value1;key2=value2;..." - */ - const char *key; - - /* Value to be obtained. If key does not exist, it is set to NULL. */ - const char *value; -}; - -struct retro_game_info -{ - const char *path; /* Path to game, UTF-8 encoded. - * Usually used as a reference. - * May be NULL if rom was loaded from stdin - * or similar. - * retro_system_info::need_fullpath guaranteed - * that this path is valid. */ - const void *data; /* Memory buffer of loaded game. Will be NULL - * if need_fullpath was set. */ - size_t size; /* Size of memory buffer. */ - const char *meta; /* String of implementation specific meta-data. */ -}; - -#define RETRO_MEMORY_ACCESS_WRITE (1 << 0) - /* The core will write to the buffer provided by retro_framebuffer::data. */ -#define RETRO_MEMORY_ACCESS_READ (1 << 1) - /* The core will read from retro_framebuffer::data. */ -#define RETRO_MEMORY_TYPE_CACHED (1 << 0) - /* The memory in data is cached. - * If not cached, random writes and/or reading from the buffer is expected to be very slow. */ -struct retro_framebuffer -{ - void *data; /* The framebuffer which the core can render into. - Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. - The initial contents of data are unspecified. */ - unsigned width; /* The framebuffer width used by the core. Set by core. */ - unsigned height; /* The framebuffer height used by the core. Set by core. */ - size_t pitch; /* The number of bytes between the beginning of a scanline, - and beginning of the next scanline. - Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ - enum retro_pixel_format format; /* The pixel format the core must use to render into data. - This format could differ from the format used in - SET_PIXEL_FORMAT. - Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ - - unsigned access_flags; /* How the core will access the memory in the framebuffer. - RETRO_MEMORY_ACCESS_* flags. - Set by core. */ - unsigned memory_flags; /* Flags telling core how the memory has been mapped. - RETRO_MEMORY_TYPE_* flags. - Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ -}; - -/* Callbacks */ - -/* Environment callback. Gives implementations a way of performing - * uncommon tasks. Extensible. */ -typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data); - -/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian - * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT). - * - * Width and height specify dimensions of buffer. - * Pitch specifices length in bytes between two lines in buffer. - * - * For performance reasons, it is highly recommended to have a frame - * that is packed in memory, i.e. pitch == width * byte_per_pixel. - * Certain graphic APIs, such as OpenGL ES, do not like textures - * that are not packed in memory. - */ -typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width, - unsigned height, size_t pitch); - -/* Renders a single audio frame. Should only be used if implementation - * generates a single sample at a time. - * Format is signed 16-bit native endian. - */ -typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right); - -/* Renders multiple audio frames in one go. - * - * One frame is defined as a sample of left and right channels, interleaved. - * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. - * Only one of the audio callbacks must ever be used. - */ -typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data, - size_t frames); - -/* Polls input. */ -typedef void (RETRO_CALLCONV *retro_input_poll_t)(void); - -/* Queries for input for player 'port'. device will be masked with - * RETRO_DEVICE_MASK. - * - * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that - * have been set with retro_set_controller_port_device() - * will still use the higher level RETRO_DEVICE_JOYPAD to request input. - */ -typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device, - unsigned index, unsigned id); - -/* Sets callbacks. retro_set_environment() is guaranteed to be called - * before retro_init(). - * - * The rest of the set_* functions are guaranteed to have been called - * before the first call to retro_run() is made. */ -RETRO_API void retro_set_environment(retro_environment_t); -RETRO_API void retro_set_video_refresh(retro_video_refresh_t); -RETRO_API void retro_set_audio_sample(retro_audio_sample_t); -RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t); -RETRO_API void retro_set_input_poll(retro_input_poll_t); -RETRO_API void retro_set_input_state(retro_input_state_t); - -/* Library global initialization/deinitialization. */ -RETRO_API void retro_init(void); -RETRO_API void retro_deinit(void); - -/* Must return RETRO_API_VERSION. Used to validate ABI compatibility - * when the API is revised. */ -RETRO_API unsigned retro_api_version(void); - -/* Gets statically known system info. Pointers provided in *info - * must be statically allocated. - * Can be called at any time, even before retro_init(). */ -RETRO_API void retro_get_system_info(struct retro_system_info *info); - -/* Gets information about system audio/video timings and geometry. - * Can be called only after retro_load_game() has successfully completed. - * NOTE: The implementation of this function might not initialize every - * variable if needed. - * E.g. geom.aspect_ratio might not be initialized if core doesn't - * desire a particular aspect ratio. */ -RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info); - -/* Sets device to be used for player 'port'. - * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all - * available ports. - * Setting a particular device type is not a guarantee that libretro cores - * 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. */ -RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device); - -/* Resets the current game. */ -RETRO_API void retro_reset(void); - -/* Runs the game for one video frame. - * During retro_run(), input_poll callback must be called at least once. - * - * If a frame is not rendered for reasons where a game "dropped" a frame, - * this still counts as a frame, and retro_run() should explicitly dupe - * a frame if GET_CAN_DUPE returns true. - * In this case, the video callback can take a NULL argument for data. - */ -RETRO_API void retro_run(void); - -/* Returns the amount of data the implementation requires to serialize - * internal state (save states). - * Between calls to retro_load_game() and retro_unload_game(), the - * returned size is never allowed to be larger than a previous returned - * value, to ensure that the frontend can allocate a save state buffer once. - */ -RETRO_API size_t retro_serialize_size(void); - -/* Serializes internal state. If failed, or size is lower than - * retro_serialize_size(), it should return false, true otherwise. */ -RETRO_API bool retro_serialize(void *data, size_t size); -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. */ -RETRO_API bool retro_load_game(const struct retro_game_info *game); - -/* Loads a "special" kind of game. Should not be used, - * except in extreme cases. */ -RETRO_API bool retro_load_game_special( - unsigned game_type, - const struct retro_game_info *info, size_t num_info -); - -/* Unloads a currently loaded game. */ -RETRO_API void retro_unload_game(void); - -/* Gets region of game. */ -RETRO_API unsigned retro_get_region(void); - -/* Gets region of memory. */ -RETRO_API void *retro_get_memory_data(unsigned id); -RETRO_API size_t retro_get_memory_size(unsigned id); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/link.T b/link.T deleted file mode 100644 index 9e82b5d..0000000 --- a/link.T +++ /dev/null @@ -1,4 +0,0 @@ -{ - global: retro_*; - local: *; -}; diff --git a/shell/audio/alsa/sound_output.c b/shell/audio/alsa/sound_output.c new file mode 100644 index 0000000..5173bb6 --- /dev/null +++ b/shell/audio/alsa/sound_output.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "sound_output.h" + +static snd_pcm_t *handle; + +uint32_t Audio_Init() +{ + snd_pcm_hw_params_t *params; + uint32_t val; + int32_t dir = -1; + snd_pcm_uframes_t frames; + + /* Open PCM device for playback. */ + int32_t rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + + if (rc < 0) + rc = snd_pcm_open(&handle, "plughw:0,0,0", SND_PCM_STREAM_PLAYBACK, 0); + + if (rc < 0) + rc = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0); + + if (rc < 0) + rc = snd_pcm_open(&handle, "plughw:1,0,0", SND_PCM_STREAM_PLAYBACK, 0); + + if (rc < 0) + rc = snd_pcm_open(&handle, "plughw:1,0", SND_PCM_STREAM_PLAYBACK, 0); + + if (rc < 0) + { + fprintf(stderr, "unable to open PCM device: %s\n", snd_strerror(rc)); + return 1; + } + + /* Allocate a hardware parameters object. */ + snd_pcm_hw_params_alloca(¶ms); + + /* Fill it in with default values. */ + rc = snd_pcm_hw_params_any(handle, params); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc)); + return 1; + } + + /* Set the desired hardware parameters. */ + + /* Interleaved mode */ + rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc)); + return 1; + } + + /* Signed 16-bit little-endian format */ + rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc)); + return 1; + } + + /* Two channels (stereo) */ + rc = snd_pcm_hw_params_set_channels(handle, params, 2); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc)); + return 1; + } + + val = SOUND_OUTPUT_FREQUENCY; + rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc)); + return 1; + } + + /* Set period size to settings.aica.BufferSize frames. */ + frames = SOUND_SAMPLES_SIZE; + rc = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc)); + return 1; + } + frames *= 4; + rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &frames); + if (rc < 0) + { + fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc)); + return 1; + } + + /* Write the parameters to the driver */ + rc = snd_pcm_hw_params(handle, params); + if (rc < 0) + { + fprintf(stderr, "Unable to set hw parameters: %s\n", snd_strerror(rc)); + return 1; + } + + return 0; +} + +void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size) +{ + uint32_t i; + long ret, len; + + if (!handle) return; + + len = buffer_size; + + ret = snd_pcm_writei(handle, buffer, len); + while(ret != len) + { + if (ret < 0) + { + snd_pcm_prepare( handle ); + } + else + { + len -= ret; + } + ret = snd_pcm_writei(handle, buffer, len); + } +} + +void Audio_Close() +{ + if (handle) + { + snd_pcm_drain(handle); + snd_pcm_close(handle); + } +} diff --git a/shell/audio/oss/sound_output.c b/shell/audio/oss/sound_output.c new file mode 100644 index 0000000..2d32b1f --- /dev/null +++ b/shell/audio/oss/sound_output.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +#include "sound_output.h" + +static int32_t oss_audio_fd = -1; + +uint32_t Audio_Init() +{ + uint32_t channels = 2; + uint32_t format = AFMT_S16_LE; + uint32_t tmp = SOUND_OUTPUT_FREQUENCY; + int32_t err_ret; + + oss_audio_fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK); + if (oss_audio_fd < 0) + { + printf("Couldn't open /dev/dsp.\n"); + return 1; + } + + err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_SPEED,&tmp); + if (err_ret == -1) + { + printf("Could not set sound frequency\n"); + return 1; + } + err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_CHANNELS, &channels); + if (err_ret == -1) + { + printf("Could not set channels\n"); + return 1; + } + err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_SETFMT, &format); + if (err_ret == -1) + { + printf("Could not set sound format\n"); + return 1; + } + return 0; +} + +void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size) +{ + write(oss_audio_fd, buffer, buffer_size * 4 ); +} + +void Audio_Close() +{ + if (oss_audio_fd >= 0) + { + close(oss_audio_fd); + oss_audio_fd = -1; + } +} diff --git a/shell/audio/portaudio/sound_output.c b/shell/audio/portaudio/sound_output.c new file mode 100644 index 0000000..226db5c --- /dev/null +++ b/shell/audio/portaudio/sound_output.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "shared.h" + +static PaStream *apu_stream; + +uint32_t Audio_Init() +{ + Pa_Initialize(); + + PaStreamParameters outputParameters; + + outputParameters.device = Pa_GetDefaultOutputDevice(); + + if (outputParameters.device == paNoDevice) + { + printf("No sound output\n"); + return 1; + } + + outputParameters.channelCount = 2; + outputParameters.sampleFormat = paInt16; + outputParameters.hostApiSpecificStreamInfo = NULL; + + Pa_OpenStream( &apu_stream, NULL, &outputParameters, SOUND_OUTPUT_FREQUENCY, SOUND_SAMPLES_SIZE, paNoFlag, NULL, NULL); + Pa_StartStream( apu_stream ); + + return 0; +} + +void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size) +{ + Pa_WriteStream( apu_stream, buffer, buffer_size); +} + +void Audio_Close() +{ + //Pa_Close(); +} diff --git a/shell/audio/sdl/sound_output.c b/shell/audio/sdl/sound_output.c new file mode 100644 index 0000000..f14bb1d --- /dev/null +++ b/shell/audio/sdl/sound_output.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include + +#include "sound_output.h" + +static int32_t BUFFSIZE; +static uint8_t *buffer; +static uint32_t buf_read_pos = 0; +static uint32_t buf_write_pos = 0; +static int32_t buffered_bytes = 0; + +static int32_t sdl_read_buffer(uint8_t* data, int32_t len) +{ + if (buffered_bytes >= len) + { + if(buf_read_pos + len <= BUFFSIZE ) + { + memcpy(data, buffer + buf_read_pos, len); + } + else + { + int32_t tail = BUFFSIZE - buf_read_pos; + memcpy(data, buffer + buf_read_pos, tail); + memcpy(data + tail, buffer, len - tail); + } + buf_read_pos = (buf_read_pos + len) % BUFFSIZE; + buffered_bytes -= len; + } + + return len; +} + + +static void sdl_write_buffer(uint8_t* data, int32_t len) +{ + for(uint32_t i = 0; i < len; i += 4) + { + if(buffered_bytes == BUFFSIZE) return; // just drop samples + *(int32_t*)((char*)(buffer + buf_write_pos)) = *(int32_t*)((char*)(data + i)); + //memcpy(buffer + buf_write_pos, data + i, 4); + buf_write_pos = (buf_write_pos + 4) % BUFFSIZE; + buffered_bytes += 4; + } +} + +void sdl_callback(void *unused, uint8_t *stream, int32_t len) +{ + sdl_read_buffer((uint8_t *)stream, len); +} +uint32_t Audio_Init() +{ + SDL_AudioSpec aspec, obtained; + + BUFFSIZE = (SOUND_SAMPLES_SIZE * 2 * 2) * 4; + buffer = (uint8_t *) malloc(BUFFSIZE); + + /* Add some silence to the buffer */ + buffered_bytes = 0; + buf_read_pos = 0; + buf_write_pos = 0; + + aspec.format = AUDIO_S16SYS; + aspec.freq = SOUND_OUTPUT_FREQUENCY; + aspec.channels = 2; + aspec.samples = SOUND_SAMPLES_SIZE; + aspec.callback = (sdl_callback); + aspec.userdata = NULL; + + /* initialize the SDL Audio system */ + if (SDL_InitSubSystem (SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE)) + { + printf("SDL: Initializing of SDL Audio failed: %s.\n", SDL_GetError()); + return 1; + } + + /* Open the audio device and start playing sound! */ + if(SDL_OpenAudio(&aspec, &obtained) < 0) + { + printf("SDL: Unable to open audio: %s\n", SDL_GetError()); + return 1; + } + + SDL_PauseAudio(0); + + return 0; +} + +void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size) +{ + SDL_LockAudio(); + sdl_write_buffer(buffer, buffer_size * 4); + SDL_UnlockAudio(); +} + +void Audio_Close() +{ + SDL_PauseAudio(1); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + buffer = NULL; +} diff --git a/shell/audio/sound_output.h b/shell/audio/sound_output.h new file mode 100644 index 0000000..ba8a318 --- /dev/null +++ b/shell/audio/sound_output.h @@ -0,0 +1,10 @@ +#ifndef SOUND_OUTPUT_H +#define SOUND_OUTPUT_H + +#include "shared.h" + +extern uint32_t Audio_Init(); +extern void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size); +extern void Audio_Close(); + +#endif diff --git a/shell/emu/core.c b/shell/emu/core.c new file mode 100644 index 0000000..2edc457 --- /dev/null +++ b/shell/emu/core.c @@ -0,0 +1,435 @@ +// Author: skogaby +// Lots of examples were followed using other emulators found on github + +#include +#include +#include +#include + +#include "main.h" +#include "snes9x.h" +#include "soundux.h" +#include "memmap.h" +#include "apu.h" +#include "apu_blargg.h" +#include "cheats.h" +#include "display.h" +#include "gfx.h" +#include "cpuexec.h" +#include "spc7110.h" +#include "srtc.h" +#include "sa1.h" +#include "scaler.h" + +#include "shared.h" +#include "menu.h" +#include "video_blit.h" +#include "input.h" +#include "sound_output.h" + +char GameName_emu[512]; + +bool overclock_cycles = false; +bool reduce_sprite_flicker = true; +int one_c, slow_one_c, two_c; + +static int32_t samples_to_play = 0; +static int32_t samples_per_frame = 0; +static int32_t samplerate = (((SNES_CLOCK_SPEED * 6) / (32 * ONE_APU_CYCLE))); + +#ifdef USE_BLARGG_APU +static void S9xAudioCallback() +{ + size_t avail; + /* Just pick a big buffer. We won't use it all. */ + static int16_t audio_buf[0x20000]; + + S9xFinalizeSamples(); + avail = S9xGetSampleCount(); + S9xMixSamples(audio_buf, avail); + Audio_Write(audio_buf, avail >> 1); +} +#endif + +size_t retro_serialize_size(void) +{ + return sizeof(CPU) + sizeof(ICPU) + sizeof(PPU) + sizeof(DMA) + + 0x10000 + 0x20000 + 0x20000 + 0x8000 + +#ifndef USE_BLARGG_APU + sizeof(APU) + sizeof(IAPU) + 0x10000 + +#else + SPC_SAVE_STATE_BLOCK_SIZE + +#endif + sizeof(SA1) + sizeof(s7r) + sizeof(rtc_f9); +} + +void RTC_Save(char* path, uint_fast8_t state) +{ + FILE* savefp; + + /* If RTC is disabled then don't bother saving any RTC info */ + if (!Settings.SRTC) return; + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + if (Settings.SPC7110RTC) + { + fread(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + S9xUpdateRTC(); + } + else + { + fread(&rtc, sizeof(uint8_t), sizeof(rtc), savefp); + fclose(savefp); + S9xSRTCPostLoadState(); + } + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + if (Settings.SPC7110RTC) + { + fwrite(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + S9xUpdateRTC(); + } + else + { + S9xSRTCPreSaveState(); + fwrite(&rtc, sizeof(uint8_t), sizeof(rtc), savefp); + fclose(savefp); + } + } + } +} + +void SRAM_Save(char* path, uint_fast8_t state) +{ + FILE* savefp; + + /* If SRAM is not used then don't bother saving any SRAM file */ + if (Memory.SRAMMask == 0) return; + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + fread(Memory.SRAM, sizeof(uint8_t), Memory.SRAMMask, savefp); + fclose(savefp); + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + fwrite(Memory.SRAM, sizeof(uint8_t), Memory.SRAMMask, savefp); + fclose(savefp); + } + } +} + +void SaveState(char* path, uint_fast8_t state) +{ +#ifndef USE_BLARGG_APU + uint8_t* IAPU_RAM_current = IAPU.RAM; + uintptr_t IAPU_RAM_offset; +#endif + char* buffer; + FILE* savefp; + +#ifndef USE_BLARGG_APU + buffer = malloc(sizeof(APU) + sizeof(IAPU) + 0x10000); +#else + buffer = malloc(SPC_SAVE_STATE_BLOCK_SIZE); +#endif + + if (state == 1) + { + savefp = fopen(path, "rb"); + if (savefp) + { + S9xReset(); + + fread(&CPU, sizeof(uint8_t), sizeof(CPU), savefp); + fread(&ICPU, sizeof(uint8_t), sizeof(ICPU), savefp); + fread(&PPU, sizeof(uint8_t), sizeof(PPU), savefp); + fread(&DMA, sizeof(uint8_t), sizeof(DMA), savefp); + + fread(Memory.VRAM, sizeof(uint8_t), 0x10000, savefp); + fread(Memory.RAM, sizeof(uint8_t), 0x20000, savefp); + fread(Memory.SRAM, sizeof(uint8_t), 0x20000, savefp); + fread(Memory.FillRAM, sizeof(uint8_t), 0x8000, savefp); + + #ifndef USE_BLARGG_APU + fread(&APU, sizeof(uint8_t), sizeof(APU), savefp); + fread(&IAPU, sizeof(uint8_t), sizeof(IAPU), savefp); + IAPU_RAM_offset = IAPU_RAM_current - IAPU.RAM; + IAPU.PC += IAPU_RAM_offset; + IAPU.DirectPage += IAPU_RAM_offset; + IAPU.WaitAddress1 += IAPU_RAM_offset; + IAPU.WaitAddress2 += IAPU_RAM_offset; + IAPU.RAM = IAPU_RAM_current; + fread(IAPU.RAM, sizeof(uint8_t), 0x10000, savefp); + #else + S9xAPULoadState(buffer); + fread(buffer, sizeof(uint8_t), SPC_SAVE_STATE_BLOCK_SIZE, savefp); + #endif + + SA1.Registers.PC = SA1.PC - SA1.PCBase; + S9xSA1PackStatus(); + fread(&SA1, sizeof(uint8_t), sizeof(SA1), savefp); + fread(&s7r, sizeof(uint8_t), sizeof(s7r), savefp); + fread(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + + S9xFixSA1AfterSnapshotLoad(); + FixROMSpeed(); + IPPU.ColorsChanged = true; + IPPU.OBJChanged = true; + CPU.InDMA = false; + S9xFixColourBrightness(); + S9xSA1UnpackStatus(); + #ifndef USE_BLARGG_APU + S9xAPUUnpackStatus(); + S9xFixSoundAfterSnapshotLoad(); + #endif + ICPU.ShiftedPB = ICPU.Registers.PB << 16; + ICPU.ShiftedDB = ICPU.Registers.DB << 16; + S9xSetPCBase(ICPU.ShiftedPB + ICPU.Registers.PC); + S9xUnpackStatus(); + S9xFixCycles(); + S9xReschedule(); + } + } + else + { + savefp = fopen(path, "wb"); + if (savefp) + { + #ifdef LAGFIX + S9xPackStatus(); + #ifndef USE_BLARGG_APU + S9xAPUPackStatus(); + #endif + #endif + + S9xUpdateRTC(); + S9xSRTCPreSaveState(); + fwrite(&CPU, sizeof(uint8_t), sizeof(CPU), savefp); + fwrite(&ICPU, sizeof(uint8_t), sizeof(ICPU), savefp); + fwrite(&PPU, sizeof(uint8_t), sizeof(PPU), savefp); + fwrite(&DMA, sizeof(uint8_t), sizeof(DMA), savefp); + + fwrite(Memory.VRAM, sizeof(uint8_t), 0x10000, savefp); + fwrite(Memory.RAM, sizeof(uint8_t), 0x20000, savefp); + fwrite(Memory.SRAM, sizeof(uint8_t), 0x20000, savefp); + fwrite(Memory.FillRAM, sizeof(uint8_t), 0x8000, savefp); + + #ifndef USE_BLARGG_APU + fwrite(&APU, sizeof(uint8_t), sizeof(APU), savefp); + fwrite(&IAPU, sizeof(uint8_t), sizeof(IAPU), savefp); + fwrite(IAPU.RAM, sizeof(uint8_t), 0x10000, savefp); + #else + S9xAPUSaveState(buffer); + fwrite(buffer, sizeof(uint8_t), SPC_SAVE_STATE_BLOCK_SIZE, savefp); + #endif + + SA1.Registers.PC = SA1.PC - SA1.PCBase; + S9xSA1PackStatus(); + fwrite(&SA1, sizeof(uint8_t), sizeof(SA1), savefp); + fwrite(&s7r, sizeof(uint8_t), sizeof(s7r), savefp); + fwrite(&rtc_f9, sizeof(uint8_t), sizeof(rtc_f9), savefp); + fclose(savefp); + } + } + + if (buffer) free(buffer); +} + +void Emulation_Run (void) +{ +#ifndef USE_BLARGG_APU + static int16_t audio_buf[2048]; +#endif + IPPU.RenderThisFrame = true; +#ifdef USE_BLARGG_APU + S9xSetSoundMute(false); +#endif + Settings.HardDisableAudio = false; + + S9xMainLoop(); + +#ifndef USE_BLARGG_APU + samples_to_play += samples_per_frame; + + if (samples_to_play > 512) + { + S9xMixSamples(audio_buf, samples_to_play * 2); + Audio_Write(audio_buf, samples_to_play); + samples_to_play = 0; + } +#else + S9xAudioCallback(); +#endif + + +#ifdef FRAMESKIP + if (IPPU.RenderThisFrame) + { +#endif + Update_Video_Ingame(); +#ifdef FRAMESKIP + IPPU.RenderThisFrame = false; + } + else + { + IPPU.RenderThisFrame = true; + } +#endif +} + + +bool Load_Game_Memory(char* game_path) +{ + uint64_t fps; + CPU.Flags = 0; + + if (!LoadROM(game_path)) + return false; + + Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL : Settings.FrameTimeNTSC); + + if (!Settings.PAL) + fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_NTSC_VCOUNTER)); + else + fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_PAL_VCOUNTER)); + + samplerate = SOUND_OUTPUT_FREQUENCY; + Settings.SoundPlaybackRate = samplerate; + +#ifndef USE_BLARGG_APU + samples_per_frame = samplerate / fps; + S9xSetPlaybackRate(Settings.SoundPlaybackRate); +#endif + return true; +} + + +void init_sfc_setting(void) +{ + memset(&Settings, 0, sizeof(Settings)); + Settings.JoystickEnabled = false; + Settings.SoundPlaybackRate = samplerate; + Settings.CyclesPercentage = 100; + + Settings.DisableSoundEcho = false; + Settings.InterpolatedSound = true; + Settings.APUEnabled = true; + + Settings.H_Max = SNES_CYCLES_PER_SCANLINE; + Settings.FrameTimePAL = 20000; + Settings.FrameTimeNTSC = 16667; + Settings.DisableMasterVolume = false; + Settings.Mouse = true; + Settings.SuperScope = true; + Settings.MultiPlayer5 = true; + Settings.ControllerOption = SNES_JOYPAD; +#ifdef USE_BLARGG_APU + Settings.SoundSync = false; +#endif + Settings.ApplyCheats = true; + Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX; +} + +void Init_SFC(void) +{ + init_sfc_setting(); + S9xInitMemory(); + S9xInitAPU(); + S9xInitDisplay(); + S9xInitGFX(); +#ifdef USE_BLARGG_APU + S9xInitSound(1000, 0); /* just give it a 1 second buffer */ + S9xSetSamplesAvailableCallback(S9xAudioCallback); +#else + S9xInitSound(); +#endif + CPU.SaveStateVersion = 0; +} + +void Deinit_SFC(void) +{ + if (Settings.SPC7110) + Del7110Gfx(); + + S9xDeinitGFX(); + S9xDeinitDisplay(); + S9xDeinitAPU(); + S9xDeinitMemory(); +} + + + +/* Main entrypoint of the emulator */ +int main(int argc, char* argv[]) +{ + int isloaded; + + printf("Starting Snes9x2005\n"); + + if (argc < 2) + { + printf("Specify a ROM to load in memory\n"); + return 0; + } + + snprintf(GameName_emu, sizeof(GameName_emu), "%s", basename(argv[1])); + Init_Video(); + + overclock_cycles = true; + one_c = 4; + slow_one_c = 5; + two_c = 6; + reduce_sprite_flicker = true; + + Audio_Init(); + Init_SFC(); + + isloaded = Load_Game_Memory(argv[1]); + if (!isloaded) + { + printf("Could not load ROM in memory\n"); + return 0; + } + + Init_Configuration(); + + // get the game ready + while (!exit_snes) + { + switch(emulator_state) + { + case 0: + Emulation_Run(); + break; + case 1: + Menu(); + break; + } + } + + Deinit_SFC(); + Audio_Close(); + Video_Close(); + + return 0; +} diff --git a/shell/emu/main.h b/shell/emu/main.h new file mode 100644 index 0000000..43688c3 --- /dev/null +++ b/shell/emu/main.h @@ -0,0 +1,9 @@ +#ifndef MAIN_H +#define MAIN_H + +int ResumeEmulation; +// utility functions that the core requires us to implement +extern const char* S9xGetFilename(const char* extension); +extern const char* S9xGetDirectory(uint32_t dirtype); + +#endif diff --git a/shell/headers/boolean.h b/shell/headers/boolean.h new file mode 100644 index 0000000..2c18ef7 --- /dev/null +++ b/shell/headers/boolean.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (boolean.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_SDK_BOOLEAN_H +#define __LIBRETRO_SDK_BOOLEAN_H + +#ifndef __cplusplus + +#if defined(_MSC_VER) && !defined(SN_TARGET_PS3) +/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */ +#define bool unsigned char +#define true 1 +#define false 0 +#else +#include +#endif + +#endif + +#endif diff --git a/shell/headers/retro_inline.h b/shell/headers/retro_inline.h new file mode 100644 index 0000000..ffdaa4a --- /dev/null +++ b/shell/headers/retro_inline.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_inline.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_SDK_INLINE_H +#define __LIBRETRO_SDK_INLINE_H + +#ifndef INLINE + +#if defined(_WIN32) || defined(__INTEL_COMPILER) +#define INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L +#define INLINE inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +#endif +#endif diff --git a/shell/headers/shared.h b/shell/headers/shared.h new file mode 100644 index 0000000..a44f60e --- /dev/null +++ b/shell/headers/shared.h @@ -0,0 +1,31 @@ +#ifndef SHARED_H +#define SHARED_H + +#define SOUND_OUTPUT_FREQUENCY 44100 +#define SOUND_SAMPLES_SIZE 1024 + +/* +#if defined(BITTBOY) +#define SOUND_OUTPUT_FREQUENCY 22050 +#define SOUND_SAMPLES_SIZE 1024 +#elif defined(RS97) +#define SOUND_OUTPUT_FREQUENCY 22050 +#define SOUND_SAMPLES_SIZE 1024 +#elif defined(ARCADEMINI) +#define SOUND_OUTPUT_FREQUENCY 22050 +#define SOUND_SAMPLES_SIZE 1024 +#elif defined(RETROSTONE_1) +#define SOUND_OUTPUT_FREQUENCY 48000 +#define SOUND_SAMPLES_SIZE 2048 +#elif defined(RETROSTONE_2) +#define SOUND_OUTPUT_FREQUENCY 48000 +#define SOUND_SAMPLES_SIZE 2048 +#elif defined(ZIPIT) +#define SOUND_OUTPUT_FREQUENCY 44100 +#define SOUND_SAMPLES_SIZE 1024 +#else +#define SOUND_OUTPUT_FREQUENCY 48000 +#define SOUND_SAMPLES_SIZE 2048 +#endif +*/ +#endif diff --git a/shell/input/input.h b/shell/input/input.h new file mode 100644 index 0000000..a1a89c1 --- /dev/null +++ b/shell/input/input.h @@ -0,0 +1,6 @@ +#ifndef INPUT_H +#define INPUT_H +#include +uint32_t S9xReadJoypad(int32_t port); +extern uint8_t exit_snes; +#endif diff --git a/shell/input/sdl/input.c b/shell/input/sdl/input.c new file mode 100644 index 0000000..357f7d1 --- /dev/null +++ b/shell/input/sdl/input.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include "main.h" +#include "snes9x.h" +#include "soundux.h" +#include "memmap.h" +#include "apu.h" +#include "cheats.h" +#include "display.h" +#include "gfx.h" +#include "cpuexec.h" +#include "spc7110.h" +#include "srtc.h" +#include "sa1.h" +#include "scaler.h" + +#include "menu.h" +#include "config.h" + +uint8_t *keystate; +uint8_t exit_snes = 0; +extern uint32_t emulator_state; + +#define CASE(realkey, key) \ + if (keystate[realkey]) \ + joypad |= key; \ + else \ + joypad &= ~key; \ + +uint32_t S9xReadJoypad(int32_t port) +{ + SDL_Event event; + static const uint32_t snes_lut[] = + { + SNES_B_MASK, + SNES_Y_MASK, + SNES_SELECT_MASK, + SNES_START_MASK, + SNES_UP_MASK, + SNES_DOWN_MASK, + SNES_LEFT_MASK, + SNES_RIGHT_MASK, + SNES_A_MASK, + SNES_X_MASK, + SNES_TL_MASK, + SNES_TR_MASK + }; + + int32_t i; + uint32_t joypad = 0; + + keystate = SDL_GetKeyState(NULL); + + SDL_PollEvent(&event); + + CASE(SDLK_RETURN, SNES_START_MASK); + CASE(SDLK_ESCAPE, SNES_SELECT_MASK); + CASE(SDLK_LCTRL, SNES_A_MASK); + CASE(SDLK_LALT, SNES_B_MASK); + CASE(SDLK_LSHIFT, SNES_X_MASK); + CASE(SDLK_SPACE, SNES_Y_MASK); + CASE(SDLK_TAB, SNES_TL_MASK); + CASE(SDLK_BACKSPACE, SNES_TR_MASK); + CASE(SDLK_UP, SNES_UP_MASK); + CASE(SDLK_LEFT, SNES_LEFT_MASK); + CASE(SDLK_RIGHT, SNES_RIGHT_MASK); + CASE(SDLK_DOWN, SNES_DOWN_MASK); + + if (keystate[SDLK_END]) emulator_state = 1; + + return joypad; +} diff --git a/shell/menu/config.h b/shell/menu/config.h new file mode 100644 index 0000000..9b71fc2 --- /dev/null +++ b/shell/menu/config.h @@ -0,0 +1,11 @@ +#ifndef CONFIG_H__ +#define CONFIG_H__ + +typedef struct { + int32_t fullscreen; + /* For input remapping */ + uint32_t config_buttons[6][19]; +} t_config; +extern t_config option; + +#endif diff --git a/shell/menu/font_drawing.c b/shell/menu/font_drawing.c new file mode 100644 index 0000000..c1c97b9 --- /dev/null +++ b/shell/menu/font_drawing.c @@ -0,0 +1,131 @@ +#include +#include +#include + +#include "video_blit.h" +#include "font_drawing.h" +#include "font_menudata.h" + +extern int32_t screen_width; +//#define setPixel(buffer, x,y,c) + +static inline void setPixel(uint16_t* restrict buffer, uint32_t x, uint32_t y, uint16_t c) +{ + if (x < HOST_WIDTH_RESOLUTION && y < HOST_HEIGHT_RESOLUTION) + { + *((uint16_t* restrict)buffer + ((x) + (y) * HOST_WIDTH_RESOLUTION)) = c; + } +} + +static int32_t isOutlinePixel(uint8_t* charfont, uint32_t x, uint32_t y) +{ + uint32_t xis0 = !x, xis7 = x == 7, yis0 = !y, yis7 = y == 7; + + if(xis0) + { + if (yis0) + { + return !(*charfont & 0x80) && ((*charfont & 0x40) || (charfont[1] & 0x80) || (charfont[1] & 0x40)); + } + else if (yis7) + { + return !(charfont[7] & 0x80) && ((charfont[7] & 0x40) || (charfont[6] & 0x80) || (charfont[6] & 0x40)); + } + else + { + return !(charfont[y] & 0x80) && ( + (charfont[y - 1] & 0x80) || (charfont[y - 1] & 0x40) || + (charfont[y] & 0x40) || + (charfont[y + 1] & 0x80) || (charfont[y + 1] & 0x40)); + } + } + else if (xis7) + { + if (yis0) + { + return !(*charfont & 0x01) && ((*charfont & 0x02) || (charfont[1] & 0x01) || (charfont[1] & 0x02)); + } + else if (yis7) + { + return !(charfont[7] & 0x01) && ((charfont[7] & 0x02) || (charfont[6] & 0x01) || (charfont[6] & 0x02)); + } + else + { + return !(charfont[y] & 0x01) && ( + (charfont[y - 1] & 0x01) || (charfont[y - 1] & 0x02) || + (charfont[y] & 0x02) || + (charfont[y + 1] & 0x01) || (charfont[y + 1] & 0x02)); + } + } + else + { + uint32_t b = 1 << (7 - x); + if (yis0) + { + return !(*charfont & b) && ( + (*charfont & (b << 1)) || (*charfont & (b >> 1)) || + (charfont[1] & (b << 1)) || (charfont[1] & b) || (charfont[1] & (b >> 1))); + } + else if (yis7) + { + return !(charfont[7] & b) && ( + (charfont[7] & (b << 1)) || (charfont[7] & (b >> 1)) || + (charfont[6] & (b << 1)) || (charfont[6] & b) || (charfont[6] & (b >> 1))); + } + else + { + return !(charfont[y] & b) && ( + (charfont[y] & (b << 1)) || (charfont[y] & (b >> 1)) || + (charfont[y - 1] & (b << 1)) || (charfont[y - 1] & b) || (charfont[y - 1] & (b >> 1)) || + (charfont[y + 1] & (b << 1)) || (charfont[y + 1] & b) || (charfont[y + 1] & (b >> 1))); + } + } +} + +static void drawChar(uint16_t* restrict buffer, uint32_t *x, uint32_t *y, uint32_t margin, char ch, uint16_t fc, uint16_t olc) +{ + uint32_t i, j; + uint8_t *charSprite; + if (ch == '\n') + { + *x = margin; + *y += 8; + } + else if(*y < (HOST_HEIGHT_RESOLUTION-1)) + { + charSprite = ch * 8 + n2DLib_font; + // Draw charSprite as monochrome 8*8 image using given color + for(i = 0; i < 8; i++) + { + for(j = 7; j; j--) + { + if((charSprite[i] >> j) & 1) + { + setPixel(buffer, *x + (7 - j), *y + i, fc); + } + else if(isOutlinePixel(charSprite, 7 - j, i)) + { + setPixel(buffer, *x + (7 - j), *y + i, olc); + } + } + } + *x += 8; + } +} + +static void drawString(uint16_t* restrict buffer, uint32_t *x, uint32_t *y, uint32_t _x, const char *str, uint16_t fc, uint16_t olc) +{ + uint32_t i; + size_t size_font; + + size_font = strnlen(str, (HOST_WIDTH_RESOLUTION/8)) + 1; + for(i = 0; i < size_font; i++) + drawChar(buffer, x, y, _x, str[i], fc, olc); +} + +void print_string(const char *s, const uint16_t fg_color, const uint16_t bg_color, uint32_t x, uint32_t y, uint16_t* restrict buffer) +{ + if (!s) return; + + drawString(buffer, &x, &y, 0, s, fg_color, bg_color); +} diff --git a/shell/menu/font_drawing.h b/shell/menu/font_drawing.h new file mode 100644 index 0000000..e18ea04 --- /dev/null +++ b/shell/menu/font_drawing.h @@ -0,0 +1,13 @@ +#ifndef FONT_DRAWING_H +#define FONT_DRAWING_H + +#include +#include + +#define TextWhite 65535 +#define TextRed ((255>>3)<<11) + ((0>>2)<<5) + (0>>3) +#define TextBlue ((0>>3)<<11) + ((0>>2)<<5) + (255>>3) + +void print_string(const char *s, const uint16_t fg_color, const uint16_t bg_color, uint32_t x, uint32_t y, uint16_t* restrict buffer); + +#endif diff --git a/shell/menu/font_menudata.h b/shell/menu/font_menudata.h new file mode 100644 index 0000000..f5a8cbc --- /dev/null +++ b/shell/menu/font_menudata.h @@ -0,0 +1,135 @@ +#ifndef n2DLIB_FONT +#define n2DLIB_FONT + +static uint8_t n2DLib_font[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 000 (.) */ + 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, /* Char 001 (.) */ + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, /* Char 002 (.) */ + 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, /* Char 003 (.) */ + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, /* Char 004 (.) */ + 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C, /* Char 005 (.) */ + 0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, /* Char 006 (.) */ + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, /* Char 007 (.) */ + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, /* Char 008 (.) */ + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, /* Char 009 (.) */ + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, /* Char 010 (.) */ + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, /* Char 011 (.) */ + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, /* Char 012 (.) */ + 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, /* Char 013 (.) */ + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, /* Char 014 (.) */ + 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, /* Char 015 (.) */ + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, /* Char 016 (.) */ + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, /* Char 017 (.) */ + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, /* Char 018 (.) */ + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, /* Char 019 (.) */ + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, /* Char 020 (.) */ + 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, /* Char 021 (.) */ + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, /* Char 022 (.) */ + 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, /* Char 023 (.) */ + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, /* Char 024 (.) */ + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, /* Char 025 (.) */ + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, /* Char 026 (<=)*/ + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, /* Char 027 (.) */ + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, /* Char 028 (.) */ + 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, /* Char 029 (.) */ + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, /* Char 030 (.) */ + 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, /* Char 031 (.) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 032 ( ) */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, /* Char 033 (!) */ + 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 034 (") */ + 0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, /* Char 035 (#) */ + 0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00, /* Char 036 ($) */ + 0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00, /* Char 037 (%) */ + 0x70, 0x88, 0x50, 0x20, 0x54, 0x88, 0x74, 0x00, /* Char 038 (&) */ + 0x60, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 039 (') */ + 0x20, 0x40, 0x80, 0x80, 0x80, 0x40, 0x20, 0x00, /* Char 040 (() */ + 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, /* Char 041 () */ + 0x00, 0x20, 0xA8, 0x70, 0x70, 0xA8, 0x20, 0x00, /* Char 042 (*) */ + 0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, /* Char 043 (+) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x40, /* Char 044 (,) */ + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, /* Char 045 (-) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, /* Char 046 (.) */ + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, /* Char 047 (/) */ + 0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70, 0x00, /* Char 048 (0) */ + 0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00, /* Char 049 (1) */ + 0x70, 0x88, 0x08, 0x10, 0x20, 0x40, 0xF8, 0x00, /* Char 050 (2) */ + 0x70, 0x88, 0x08, 0x10, 0x08, 0x88, 0x70, 0x00, /* Char 051 (3) */ + 0x08, 0x18, 0x28, 0x48, 0xFC, 0x08, 0x08, 0x00, /* Char 052 (4) */ + 0xF8, 0x80, 0x80, 0xF0, 0x08, 0x88, 0x70, 0x00, /* Char 053 (5) */ + 0x20, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70, 0x00, /* Char 054 (6) */ + 0xF8, 0x08, 0x10, 0x20, 0x40, 0x40, 0x40, 0x00, /* Char 055 (7) */ + 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, /* Char 056 (8) */ + 0x70, 0x88, 0x88, 0x78, 0x08, 0x08, 0x70, 0x00, /* Char 057 (9) */ + 0x00, 0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00, /* Char 058 (:) */ + 0x00, 0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x20, /* Char 059 (;) */ + 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00, /* Char 060 (<) */ + 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, /* Char 061 (=) */ + 0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00, /* Char 062 (>) */ + 0x78, 0x84, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, /* Char 063 (?) */ + 0x70, 0x88, 0x88, 0xA8, 0xB8, 0x80, 0x78, 0x00, /* Char 064 (@) */ + 0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, /* Char 065 (A) */ + 0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0, 0x00, /* Char 066 (B) */ + 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00, /* Char 067 (C) */ + 0xF0, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF0, 0x00, /* Char 068 (D) */ + 0xF8, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF8, 0x00, /* Char 069 (E) */ + 0xF8, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00, /* Char 070 (F) */ + 0x70, 0x88, 0x80, 0x80, 0x98, 0x88, 0x78, 0x00, /* Char 071 (G) */ + 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, /* Char 072 (H) */ + 0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00, /* Char 073 (I) */ + 0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00, /* Char 074 (J) */ + 0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, /* Char 075 (K) */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, /* Char 076 (L) */ + 0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00, /* Char 077 (M) */ + 0x84, 0xC4, 0xA4, 0x94, 0x8C, 0x84, 0x84, 0x00, /* Char 078 (N) */ + 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, /* Char 079 (O) */ + 0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, /* Char 080 (P) */ + 0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68, 0x00, /* Char 081 (Q) */ + 0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00, /* Char 082 (R) */ + 0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00, /* Char 083 (S) */ + 0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, /* Char 084 (T) */ + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, /* Char 085 (U) */ + 0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00, /* Char 086 (V) */ + 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0x6C, 0x00, /* Char 087 (W) */ + 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, /* Char 088 (X) */ + 0x88, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x00, /* Char 089 (Y) */ + 0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, /* Char 090 (Z) */ + 0xE0, 0x80, 0x80, 0x80, 0x80, 0x80, 0xE0, 0x00, /* Char 091 ([) */ + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, /* Char 092 (\) */ + 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0xE0, 0x00, /* Char 093 (]) */ + 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 094 (^) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, /* Char 095 (_) */ + 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 096 (`) */ + 0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x74, 0x00, /* Char 097 (a) */ + 0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00, /* Char 098 (b) */ + 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, /* Char 099 (c) */ + 0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00, /* Char 100 (d) */ + 0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, /* Char 101 (e) */ + 0x30, 0x48, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x00, /* Char 102 (f) */ + 0x00, 0x00, 0x34, 0x48, 0x48, 0x38, 0x08, 0x30, /* Char 103 (g) */ + 0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, /* Char 104 (h) */ + 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, /* Char 105 (i) */ + 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x90, 0x60, /* Char 106 (j) */ + 0x80, 0x80, 0x88, 0x90, 0xA0, 0xD0, 0x88, 0x00, /* Char 107 (k) */ + 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00, /* Char 108 (l) */ + 0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00, /* Char 109 (m) */ + 0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, /* Char 110 (n) */ + 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, /* Char 111 (o) */ + 0x00, 0x00, 0xB0, 0xC8, 0xC8, 0xB0, 0x80, 0x80, /* Char 112 (p) */ + 0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x08, /* Char 113 (q) */ + 0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00, /* Char 114 (r) */ + 0x00, 0x00, 0x78, 0x80, 0x70, 0x08, 0xF0, 0x00, /* Char 115 (s) */ + 0x40, 0x40, 0xE0, 0x40, 0x40, 0x50, 0x20, 0x00, /* Char 116 (t) */ + 0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, /* Char 117 (u) */ + 0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, /* Char 118 (v) */ + 0x00, 0x00, 0x82, 0x82, 0x92, 0x92, 0x6C, 0x00, /* Char 119 (w) */ + 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, /* Char 120 (x) */ + 0x00, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x70, /* Char 121 (y) */ + 0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, /* Char 122 (z) */ + 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10, 0x00, /* Char 123 ({) */ + 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, /* Char 124 (|) */ + 0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40, 0x00, /* Char 125 (}) */ + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Char 126 (~) */ + 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00 /* Char 127 (.) */ +}; +#endif diff --git a/shell/menu/menu.c b/shell/menu/menu.c new file mode 100644 index 0000000..70096bf --- /dev/null +++ b/shell/menu/menu.c @@ -0,0 +1,597 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scaler.h" +#include "font_drawing.h" +#include "sound_output.h" +#include "video_blit.h" +#include "config.h" +#include "menu.h" + +t_config option; +uint32_t emulator_state = 0; + +extern uint8_t exit_snes; + +static char home_path[256], save_path[256], sram_path[256], conf_path[256], rtc_path[256]; +static uint32_t controls_chosen = 0; + +extern SDL_Surface *sdl_screen; +extern char GameName_emu[512]; + +extern void SRAM_file(char* path, uint_fast8_t state); +extern void RTC_Save(char* path, uint_fast8_t state); +extern void SaveState(char* path, uint_fast8_t state); +extern void SRAM_Save(char* path, uint_fast8_t state); + +static uint8_t selectpressed = 0; +static uint8_t save_slot = 0; +static const int8_t upscalers_available = 2 +#ifdef SCALE2X_UPSCALER ++1 +#endif +; + +static void SaveState_Menu(uint_fast8_t load_mode, uint_fast8_t slot) +{ + char tmp[512]; + snprintf(tmp, sizeof(tmp), "%s/%s_%d.sts", save_path, GameName_emu, slot); + SaveState(tmp,load_mode); +} + +static void SRAM_Menu(uint_fast8_t load_mode) +{ + char tmp[512]; + snprintf(tmp, sizeof(tmp), "%s/%s.srm", sram_path, GameName_emu); + SRAM_Save(tmp,load_mode); +} + +static void RTC_Menu(uint_fast8_t load_mode) +{ + char tmp[512]; + snprintf(tmp, sizeof(tmp), "%s/%s.rtc", rtc_path, GameName_emu); + RTC_Save(tmp,load_mode); +} + +static void config_load() +{ + uint_fast8_t i; + char config_path[512]; + FILE* fp; + snprintf(config_path, sizeof(config_path), "%s/%s.cfg", conf_path, GameName_emu); + + fp = fopen(config_path, "rb"); + if (fp) + { + fread(&option, sizeof(option), sizeof(int8_t), fp); + fclose(fp); + } + else + { + /* Default mapping for Horizontal */ + option.config_buttons[0][0] = 273; + option.config_buttons[0][1] = 275; + option.config_buttons[0][2] = 274; + option.config_buttons[0][3] = 276; + + option.config_buttons[0][4] = 306; + option.config_buttons[0][5] = 308; + option.config_buttons[0][6] = 304; + option.config_buttons[0][7] = 32; + + option.config_buttons[0][8] = 9; + option.config_buttons[0][9] = 8; + + option.config_buttons[0][10] = 13; + option.config_buttons[0][11] = 27; + + option.fullscreen = 1; + } +} + +static void config_save() +{ + FILE* fp; + char config_path[512]; + snprintf(config_path, sizeof(config_path), "%s/%s.cfg", conf_path, GameName_emu); + + fp = fopen(config_path, "wb"); + if (fp) + { + fwrite(&option, sizeof(option), sizeof(int8_t), fp); + fclose(fp); + } +} + +static const char* Return_Text_Button(uint32_t button) +{ + switch(button) + { + /* UP button */ + case 273: + return "DPAD UP"; + break; + /* DOWN button */ + case 274: + return "DPAD DOWN"; + break; + /* LEFT button */ + case 276: + return "DPAD LEFT"; + break; + /* RIGHT button */ + case 275: + return "DPAD RIGHT"; + break; + /* A button */ + case 306: + return "A button"; + break; + /* B button */ + case 308: + return "B button"; + break; + /* X button */ + case 304: + return "X button"; + break; + /* Y button */ + case 32: + return "Y button"; + break; + /* L button */ + case 9: + return "L button"; + break; + /* R button */ + case 8: + return "R button"; + break; + /* Power button */ + case 279: + return "L2 button"; + break; + /* Brightness */ + case 51: + return "R2 button"; + break; + /* Volume - */ + case 38: + return "Volume -"; + break; + /* Volume + */ + case 233: + return "Volume +"; + break; + /* Start */ + case 13: + return "Start button"; + break; + /* Select */ + case 1: + return "Select button"; + break; + default: + return "Unknown key"; + break; + case 0: + return "..."; + break; + } +} + +static void Input_Remapping() +{ + SDL_Event Event; + char text[50]; + uint32_t pressed = 0; + int32_t currentselection = 1; + int32_t exit_input = 0; + uint32_t exit_map = 0; + + while(!exit_input) + { + pressed = 0; + SDL_FillRect( backbuffer, NULL, 0 ); + + while (SDL_PollEvent(&Event)) + { + if (Event.type == SDL_KEYDOWN) + { + switch(Event.key.keysym.sym) + { + case SDLK_UP: + currentselection--; + if (currentselection < 1) + { + if (currentselection > 9) currentselection = 12; + else currentselection = 9; + } + break; + case SDLK_DOWN: + currentselection++; + if (currentselection == 10) + { + currentselection = 1; + } + break; + case SDLK_LCTRL: + case SDLK_RETURN: + pressed = 1; + break; + case SDLK_ESCAPE: + option.config_buttons[controls_chosen][currentselection - 1] = 0; + break; + case SDLK_LALT: + exit_input = 1; + break; + case SDLK_LEFT: + if (currentselection > 9) currentselection -= 9; + break; + case SDLK_RIGHT: + if (currentselection < 10) currentselection += 9; + break; + case SDLK_BACKSPACE: + controls_chosen = 1; + break; + case SDLK_TAB: + controls_chosen = 0; + break; + default: + break; + } + } + } + + if (pressed) + { + SDL_Delay(1); + switch(currentselection) + { + default: + exit_map = 0; + while( !exit_map ) + { + SDL_FillRect( backbuffer, NULL, 0 ); + print_string("Please press button for mapping", TextWhite, TextBlue, 37, 108, backbuffer->pixels); + bitmap_scale(0,0,320,240,sdl_screen->w,sdl_screen->h,320,0,(uint16_t* restrict)backbuffer->pixels,(uint16_t* restrict)sdl_screen->pixels); + + while (SDL_PollEvent(&Event)) + { + if (Event.type == SDL_KEYDOWN) + { + if (Event.key.keysym.sym != SDLK_RCTRL) + { + option.config_buttons[controls_chosen][currentselection - 1] = Event.key.keysym.sym; + exit_map = 1; + } + } + } + SDL_Flip(sdl_screen); + } + break; + } + } + + if (currentselection > 12) currentselection = 12; + + if (controls_chosen == 0) print_string("Player 1", TextWhite, 0, 100, 10, backbuffer->pixels); + else print_string("Player 2", TextWhite, 0, 100, 10, backbuffer->pixels); + + print_string("Press [A] to map to a button", TextWhite, TextBlue, 50, 210, backbuffer->pixels); + print_string("Press [B] to Exit", TextWhite, TextBlue, 85, 225, backbuffer->pixels); + + snprintf(text, sizeof(text), "UP : %d\n", (option.config_buttons[controls_chosen][0])); + if (currentselection == 1) print_string(text, TextRed, 0, 5, 25+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 25+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "DOWN : %d\n", (option.config_buttons[controls_chosen][1])); + if (currentselection == 2) print_string(text, TextRed, 0, 5, 45+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 45+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "LEFT : %d\n", (option.config_buttons[controls_chosen][2])); + if (currentselection == 3) print_string(text, TextRed, 0, 5, 65+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 65+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "RIGHT : %d\n", (option.config_buttons[controls_chosen][3])); + if (currentselection == 4) print_string(text, TextRed, 0, 5, 85+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 85+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "A : %d\n", (option.config_buttons[controls_chosen][4])); + if (currentselection == 5) print_string(text, TextRed, 0, 5, 105+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 105+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "B : %d\n", (option.config_buttons[controls_chosen][5])); + if (currentselection == 6) print_string(text, TextRed, 0, 5, 125+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 125+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "X : %d\n", (option.config_buttons[controls_chosen][6])); + if (currentselection == 7) print_string(text, TextRed, 0, 5, 145+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 145+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "Y : %d\n", (option.config_buttons[controls_chosen][7])); + if (currentselection == 8) print_string(text, TextRed, 0, 5, 165+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 165+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "L : %d\n", (option.config_buttons[controls_chosen][8])); + if (currentselection == 9) print_string(text, TextRed, 0, 5, 185+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 185+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "R : %d\n", (option.config_buttons[controls_chosen][9])); + if (currentselection == 10) print_string(text, TextRed, 0, 165, 25+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 165, 25+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "START : %d\n", (option.config_buttons[controls_chosen][10])); + if (currentselection == 11) print_string(text, TextRed, 0, 165, 45+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 165, 45+2, backbuffer->pixels); + + snprintf(text, sizeof(text), "SELECT : %d\n", (option.config_buttons[controls_chosen][11])); + if (currentselection == 12) print_string(text, TextRed, 0, 165, 65+2, backbuffer->pixels); + else print_string(text, TextWhite, 0, 165, 65+2, backbuffer->pixels); + + bitmap_scale(0,0,320,240,sdl_screen->w,sdl_screen->h,320,0,(uint16_t* restrict)backbuffer->pixels,(uint16_t* restrict)sdl_screen->pixels); + SDL_Flip(sdl_screen); + } + + config_save(); +} + +void Menu() +{ + char text[50]; + int16_t pressed = 0; + int16_t currentselection = 1; + SDL_Rect dstRect; + SDL_Event Event; + + Set_Video_Menu(); + + /* Save sram settings each time we bring up the menu */ + SRAM_Menu(0); + RTC_Menu(0); + + while (((currentselection != 1) && (currentselection != 6)) || (!pressed)) + { + pressed = 0; + + SDL_FillRect( backbuffer, NULL, 0 ); + + print_string("SNESEmu - Built on " __DATE__, TextWhite, 0, 5, 15, backbuffer->pixels); + + if (currentselection == 1) print_string("Continue", TextRed, 0, 5, 45, backbuffer->pixels); + else print_string("Continue", TextWhite, 0, 5, 45, backbuffer->pixels); + + snprintf(text, sizeof(text), "Load State %d", save_slot); + + if (currentselection == 2) print_string(text, TextRed, 0, 5, 65, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 65, backbuffer->pixels); + + snprintf(text, sizeof(text), "Save State %d", save_slot); + + if (currentselection == 3) print_string(text, TextRed, 0, 5, 85, backbuffer->pixels); + else print_string(text, TextWhite, 0, 5, 85, backbuffer->pixels); + + if (currentselection == 4) + { + switch(option.fullscreen) + { + case 0: + print_string("Scaling : Native", TextRed, 0, 5, 105, backbuffer->pixels); + break; + case 1: + print_string("Scaling : Stretched", TextRed, 0, 5, 105, backbuffer->pixels); + break; + case 2: + print_string("Scaling : Bilinear", TextRed, 0, 5, 105, backbuffer->pixels); + break; + case 3: + print_string("Scaling : EPX/Scale2x", TextRed, 0, 5, 105, backbuffer->pixels); + break; + } + } + else + { + switch(option.fullscreen) + { + case 0: + print_string("Scaling : Native", TextWhite, 0, 5, 105, backbuffer->pixels); + break; + case 1: + print_string("Scaling : Stretched", TextWhite, 0, 5, 105, backbuffer->pixels); + break; + case 2: + print_string("Scaling : Bilinear", TextWhite, 0, 5, 105, backbuffer->pixels); + break; + case 3: + print_string("Scaling : EPX/Scale2x", TextWhite, 0, 5, 105, backbuffer->pixels); + break; + } + } + + if (currentselection == 5) print_string("Input remapping", TextRed, 0, 5, 125, backbuffer->pixels); + else print_string("Input remapping", TextWhite, 0, 5, 125, backbuffer->pixels); + + if (currentselection == 6) print_string("Quit", TextRed, 0, 5, 145, backbuffer->pixels); + else print_string("Quit", TextWhite, 0, 5, 145, backbuffer->pixels); + + print_string("Libretro Fork by gameblabla", TextWhite, 0, 5, 205, backbuffer->pixels); + print_string("Credits: Snes9x dev team, libretro", TextWhite, 0, 5, 225, backbuffer->pixels); + + while (SDL_PollEvent(&Event)) + { + if (Event.type == SDL_KEYDOWN) + { + switch(Event.key.keysym.sym) + { + case SDLK_UP: + currentselection--; + if (currentselection == 0) + currentselection = 6; + break; + case SDLK_DOWN: + currentselection++; + if (currentselection == 7) + currentselection = 1; + break; + case SDLK_END: + case SDLK_RCTRL: + case SDLK_LALT: + pressed = 1; + currentselection = 1; + break; + case SDLK_LCTRL: + case SDLK_RETURN: + pressed = 1; + break; + case SDLK_LEFT: + switch(currentselection) + { + case 2: + case 3: + if (save_slot > 0) save_slot--; + break; + case 4: + option.fullscreen--; + if (option.fullscreen < 0) + option.fullscreen = upscalers_available; + break; + } + break; + case SDLK_RIGHT: + switch(currentselection) + { + case 2: + case 3: + save_slot++; + if (save_slot == 10) + save_slot = 9; + break; + case 4: + option.fullscreen++; + if (option.fullscreen > upscalers_available) + option.fullscreen = 0; + break; + } + break; + default: + break; + } + } + else if (Event.type == SDL_QUIT) + { + currentselection = 6; + pressed = 1; + } + } + + if (pressed) + { + switch(currentselection) + { + case 5: + Input_Remapping(); + break; + case 4 : + option.fullscreen++; + if (option.fullscreen > upscalers_available) + option.fullscreen = 0; + break; + case 2 : + SaveState_Menu(1, save_slot); + currentselection = 1; + break; + case 3 : + SaveState_Menu(0, save_slot); + currentselection = 1; + break; + default: + break; + } + } + + bitmap_scale(0,0,320,240,sdl_screen->w,sdl_screen->h,320,0,(uint16_t* restrict)backbuffer->pixels,(uint16_t* restrict)sdl_screen->pixels); + SDL_Flip(sdl_screen); + } + + SDL_FillRect(sdl_screen, NULL, 0); + SDL_Flip(sdl_screen); + #ifdef SDL_TRIPLEBUF + SDL_FillRect(sdl_screen, NULL, 0); + SDL_Flip(sdl_screen); + #endif + + if (currentselection == 6) + { + exit_snes = 1; + } + + /* Switch back to emulator core */ + emulator_state = 0; + Set_Video_InGame(); +} + +static void Cleanup(void) +{ +#ifdef SCALE2X_UPSCALER + if (scale2x_buf) SDL_FreeSurface(scale2x_buf); +#endif + if (sdl_screen) SDL_FreeSurface(sdl_screen); + if (backbuffer) SDL_FreeSurface(backbuffer); + + // Deinitialize audio and video output + Audio_Close(); + + SDL_Quit(); +} + +void Init_Configuration() +{ + snprintf(home_path, sizeof(home_path), "%s/.snesemu", getenv("HOME")); + + snprintf(conf_path, sizeof(conf_path), "%s/conf", home_path); + snprintf(save_path, sizeof(save_path), "%s/sstates", home_path); + snprintf(sram_path, sizeof(sram_path), "%s/sram", home_path); + snprintf(rtc_path, sizeof(sram_path), "%s/rtc", home_path); + + /* We check first if folder does not exist. + * Let's only try to create it if so in order to decrease boot times. + * */ + + if (access( home_path, F_OK ) == -1) + { + mkdir(home_path, 0755); + } + + if (access( save_path, F_OK ) == -1) + { + mkdir(save_path, 0755); + } + + if (access( conf_path, F_OK ) == -1) + { + mkdir(conf_path, 0755); + } + + if (access( sram_path, F_OK ) == -1) + { + mkdir(sram_path, 0755); + } + + if (access( rtc_path, F_OK ) == -1) + { + mkdir(rtc_path, 0755); + } + + /* Load sram file if it exists */ + SRAM_Menu(1); + RTC_Menu(1); + + config_load(); +} diff --git a/shell/menu/menu.h b/shell/menu/menu.h new file mode 100644 index 0000000..8b81ac3 --- /dev/null +++ b/shell/menu/menu.h @@ -0,0 +1,18 @@ +#ifndef MENU_H +#define MENU_H + +#include + +#ifndef PATH_MAX +#define PATH_MAX 2048 +#endif + +#define RGB565(r,g,b) ((r << 8) | (g << 3) | (b >> 3)) + +extern uint32_t emulator_state; +extern uint32_t done; + +extern void Menu(void); +extern void Init_Configuration(void); + +#endif diff --git a/shell/other/compatibility_layer.c b/shell/other/compatibility_layer.c new file mode 100644 index 0000000..fea850b --- /dev/null +++ b/shell/other/compatibility_layer.c @@ -0,0 +1,185 @@ +#include +#include +#include "main.h" +#include "snes9x.h" +#include "soundux.h" +#include "memmap.h" +#include "apu.h" +#include "cheats.h" +#include "display.h" +#include "gfx.h" +#include "cpuexec.h" +#include "spc7110.h" +#include "srtc.h" +#include "sa1.h" +#include "scaler.h" + +const char* S9xGetFilename(const char* in) +{ + static char filename [PATH_MAX + 1]; + char drive [_MAX_DRIVE + 1]; + char dir [_MAX_DIR + 1]; + char fname [_MAX_FNAME + 1]; + char ext [_MAX_EXT + 1]; + _splitpath(Memory.ROMFilename, drive, dir, fname, ext); + _makepath(filename, drive, dir, fname, in); + return filename; +} + +void S9xMessage(int a, int b, const char* msg) +{ + //printf("%s\n", msg); +} + +const char* S9xGetDirectory(uint32_t dirtype) { return NULL; } + +void S9xDeinitDisplay(void) +{ +#ifdef DS2_DMA + if (GFX.Screen_buffer) + AlignedFree(GFX.Screen, PtrAdj.GFXScreen); +#elif defined(_3DS) + if (GFX.Screen_buffer) + linearFree(GFX.Screen_buffer); +#else + if (GFX.Screen_buffer) + free(GFX.Screen_buffer); +#endif + if (GFX.SubScreen_buffer) + free(GFX.SubScreen_buffer); + if (GFX.ZBuffer_buffer) + free(GFX.ZBuffer_buffer); + if (GFX.SubZBuffer_buffer) + free(GFX.SubZBuffer_buffer); + + GFX.Screen = NULL; + GFX.Screen_buffer = NULL; + GFX.SubScreen = NULL; + GFX.SubScreen_buffer = NULL; + GFX.ZBuffer = NULL; + GFX.ZBuffer_buffer = NULL; + GFX.SubZBuffer = NULL; + GFX.SubZBuffer_buffer = NULL; +} + +void S9xInitDisplay(void) +{ + int32_t h = IMAGE_HEIGHT; + int32_t safety = 32; + + GFX.Pitch = IMAGE_WIDTH * 2; +#ifdef DS2_DMA + GFX.Screen_buffer = (uint8_t *) AlignedMalloc(GFX.Pitch * h + safety, 32, &PtrAdj.GFXScreen); +#elif defined(_3DS) + safety = 0x80; + GFX.Screen_buffer = (uint8_t *) linearMemAlign(GFX.Pitch * h + safety, 0x80); +#else + GFX.Screen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety); +#endif + GFX.SubScreen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety); + GFX.ZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety); + GFX.SubZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety); + + GFX.Screen = GFX.Screen_buffer + safety; + GFX.SubScreen = GFX.SubScreen_buffer + safety; + GFX.ZBuffer = GFX.ZBuffer_buffer + safety; + GFX.SubZBuffer = GFX.SubZBuffer_buffer + safety; + + GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1; +} + +void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext) +{ + char *slash = strrchr ((char *) path, SLASH_CHAR); + char *dot = strrchr ((char *) path, '.'); + + *drive = '\0'; + + if (dot && slash && dot < slash) + { + dot = 0; + } + + if (!slash) + { + *dir = '\0'; + strcpy (fname, path); + + if (dot) + { + fname[dot - path] = '\0'; + strcpy (ext, dot + 1); + } + else + { + *ext = '\0'; + } + } + else + { + strcpy (dir, path); + dir[slash - path] = '\0'; + strcpy (fname, slash + 1); + + if (dot) + { + fname[(dot - slash) - 1] = '\0'; + strcpy (ext, dot + 1); + } + else + { + *ext = '\0'; + } + } + + return; +} + +void _makepath (char *path, const char *drive, const char *dir, const char *fname,const char *ext) +{ + if (dir && *dir) + { + strcpy (path, dir); + strcat (path, "/"); + } + else + *path = '\0'; + + strcat (path, fname); + + if (ext && *ext) + { + strcat (path, "."); + strcat (path, ext); + } + + return; +} + + +bool S9xReadMousePosition(int32_t which1, int32_t* x, int32_t* y, uint32_t* buttons) +{ + (void) which1; + (void) x; + (void) y; + (void) buttons; + return false; +} + +bool S9xReadSuperScopePosition(int32_t* x, int32_t* y, uint32_t* buttons) +{ + (void) x; + (void) y; + (void) buttons; + return true; +} + +bool JustifierOffscreen(void) +{ + return false; +} + +void JustifierButtons(uint32_t* justifiers) +{ + (void) justifiers; +} diff --git a/shell/scalers/scaler.c b/shell/scalers/scaler.c new file mode 100644 index 0000000..3aeea05 --- /dev/null +++ b/shell/scalers/scaler.c @@ -0,0 +1,139 @@ +#include +#include +#include "scaler.h" + +#define AVERAGE(z, x) ((((z) & 0xF7DEF7DE) >> 1) + (((x) & 0xF7DEF7DE) >> 1)) +#define AVERAGEHI(AB) ((((AB) & 0xF7DE0000) >> 1) + (((AB) & 0xF7DE) << 15)) +#define AVERAGELO(CD) ((((CD) & 0xF7DE) >> 1) + (((CD) & 0xF7DE0000) >> 17)) + +// Support math +#define Half(A) (((A) >> 1) & 0x7BEF) +#define Quarter(A) (((A) >> 2) & 0x39E7) +// Error correction expressions to piece back the lower bits together +#define RestHalf(A) ((A) & 0x0821) +#define RestQuarter(A) ((A) & 0x1863) + +// Error correction expressions for quarters of pixels +#define Corr1_3(A, B) Quarter(RestQuarter(A) + (RestHalf(B) << 1) + RestQuarter(B)) +#define Corr3_1(A, B) Quarter((RestHalf(A) << 1) + RestQuarter(A) + RestQuarter(B)) + +// Error correction expressions for halves +#define Corr1_1(A, B) ((A) & (B) & 0x0821) + +// Quarters +#define Weight1_3(A, B) (Quarter(A) + Half(B) + Quarter(B) + Corr1_3(A, B)) +#define Weight3_1(A, B) (Half(A) + Quarter(A) + Quarter(B) + Corr3_1(A, B)) + +// Halves +#define Weight1_1(A, B) (Half(A) + Half(B) + Corr1_1(A, B)) + + +void upscale_256x240_to_320x240_bilinearish(uint32_t* restrict dst, uint32_t* restrict src, uint_fast16_t width, uint_fast16_t height) +{ + uint16_t* Src16 = (uint16_t*) src; + uint16_t* Dst16 = (uint16_t*) dst; + // There are 64 blocks of 4 pixels horizontally, and 239 of 1 vertically. + // Each block of 4x1 becomes 5x1. + uint32_t BlockX, BlockY; + uint16_t* BlockSrc; + uint16_t* BlockDst; + for (BlockY = 0; BlockY < height; BlockY++) + { + BlockSrc = Src16 + BlockY * 512 * 1; + BlockDst = Dst16 + BlockY * 320 * 1; + for (BlockX = 0; BlockX < 64; BlockX++) + { + /* Horizontally: + * Before(4): + * (a)(b)(c)(d) + * After(5): + * (a)(abbb)(bc)(cccd)(d) + */ + + // -- Row 1 -- + uint16_t _1 = *(BlockSrc ); + *(BlockDst ) = _1; + uint16_t _2 = *(BlockSrc + 1); + *(BlockDst + 1) = Weight1_3( _1, _2); + uint16_t _3 = *(BlockSrc + 2); + *(BlockDst + 2) = Weight1_1( _2, _3); + uint16_t _4 = *(BlockSrc + 3); + *(BlockDst + 3) = Weight3_1( _3, _4); + *(BlockDst + 4) = _4; + + BlockSrc += 4; + BlockDst += 5; + } + } +} + +void upscale_256xXXX_to_320x240(uint32_t* restrict dst, uint32_t* restrict src, uint_fast16_t width, uint_fast16_t height) +{ + uint_fast16_t midh = 240; + uint_fast16_t Eh = 0; + uint_fast16_t source = 0; + uint_fast16_t dh = 0; + uint_fast8_t y, x; + + for (y = 0; y < 240; y++) + { + source = dh * width; + + for (x = 0; x < 320/10; x++) + { + register uint32_t ab, cd, ef, gh; + + __builtin_prefetch(dst + 4, 1); + __builtin_prefetch(src + source + 4, 0); + + ab = src[source] & 0xF7DEF7DE; + cd = src[source + 1] & 0xF7DEF7DE; + ef = src[source + 2] & 0xF7DEF7DE; + gh = src[source + 3] & 0xF7DEF7DE; + + if(Eh >= midh) + { + ab = AVERAGE(ab, src[source + width/2]) & 0xF7DEF7DE; // to prevent overflow + cd = AVERAGE(cd, src[source + width/2 + 1]) & 0xF7DEF7DE; // to prevent overflow + ef = AVERAGE(ef, src[source + width/2 + 2]) & 0xF7DEF7DE; // to prevent overflow + gh = AVERAGE(gh, src[source + width/2 + 3]) & 0xF7DEF7DE; // to prevent overflow + } + + *dst++ = ab; + *dst++ = ((ab >> 17) + ((cd & 0xFFFF) >> 1)) + (cd << 16); + *dst++ = (cd >> 16) + (ef << 16); + *dst++ = (ef >> 16) + (((ef & 0xFFFF0000) >> 1) + ((gh & 0xFFFF) << 15)); + *dst++ = gh; + + source += 4; + + } + Eh += height; if(Eh >= 240) { Eh -= 240; dh++; } + } +} + + +/* alekmaul's scaler taken from mame4all */ +void bitmap_scale(uint32_t startx, uint32_t starty, uint32_t viswidth, uint32_t visheight, uint32_t newwidth, uint32_t newheight,uint32_t pitchsrc,uint32_t pitchdest, uint16_t* restrict src, uint16_t* restrict dst) +{ + uint32_t W,H,ix,iy,x,y; + x=startx<<16; + y=starty<<16; + W=newwidth; + H=newheight; + ix=(viswidth<<16)/W; + iy=(visheight<<16)/H; + + do + { + uint16_t* restrict buffer_mem=&src[(y>>16)*pitchsrc]; + W=newwidth; x=startx<<16; + do + { + *dst++=buffer_mem[x>>16]; + x+=ix; + } while (--W); + dst+=pitchdest; + y+=iy; + } while (--H); +} diff --git a/shell/scalers/scaler.h b/shell/scalers/scaler.h new file mode 100644 index 0000000..f220800 --- /dev/null +++ b/shell/scalers/scaler.h @@ -0,0 +1,11 @@ +#ifndef SCALER_H +#define SCALER_H + +#include + +/* Generic */ +extern void bitmap_scale(uint32_t startx, uint32_t starty, uint32_t viswidth, uint32_t visheight, uint32_t newwidth, uint32_t newheight,uint32_t pitchsrc,uint32_t pitchdest, uint16_t* restrict src, uint16_t* restrict dst); +extern void upscale_256xXXX_to_320x240(uint32_t* restrict dst, uint32_t* restrict src, uint_fast16_t width, uint_fast16_t height); +extern void upscale_256x240_to_320x240_bilinearish(uint32_t* restrict dst, uint32_t* restrict src, uint_fast16_t width, uint_fast16_t height); + +#endif diff --git a/shell/video/retrostone/video_blit.c b/shell/video/retrostone/video_blit.c new file mode 100644 index 0000000..be84dd1 --- /dev/null +++ b/shell/video/retrostone/video_blit.c @@ -0,0 +1,155 @@ +/* Cygne + * + * Copyright notice for this file: + * Copyright (C) 2002 Dox dox@space.pl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "mednafen.h" +#include "mempatcher.h" +#include "wswan/gfx.h" +#include "wswan/wswan-memory.h" +#include "wswan/sound.h" +#include "wswan/interrupt.h" +#include "wswan/v30mz.h" +#include "wswan/rtc.h" +#include "wswan/gfx.h" +#include "wswan/eeprom.h" + +#include "video_blit.h" +#include "scaler.h" +#include "config.h" + +SDL_Surface *sdl_screen, *backbuffer, *wswan_vs, *wswan_vs_rot; + +uint32_t width_of_surface; +uint32_t* Draw_to_Virtual_Screen; + +void Init_Video() +{ + SDL_Init( SDL_INIT_VIDEO ); + + SDL_ShowCursor(0); + + sdl_screen = SDL_SetVideoMode(0, 0, 16, SDL_HWSURFACE); + + backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, 0,0,0,0); + + wswan_vs = SDL_CreateRGBSurface(SDL_SWSURFACE, INTERNAL_WSWAN_WIDTH, INTERNAL_WSWAN_HEIGHT, 16, 0,0,0,0); + + wswan_vs_rot = SDL_CreateRGBSurface(SDL_SWSURFACE, INTERNAL_WSWAN_HEIGHT, INTERNAL_WSWAN_WIDTH, 16, 0,0,0,0); + + Set_Video_InGame(); +} + +void Set_Video_Menu() +{ + if (sdl_screen->w != HOST_WIDTH_RESOLUTION) + { + memcpy(wswan_vs->pixels, sdl_screen->pixels, (INTERNAL_WSWAN_WIDTH * INTERNAL_WSWAN_HEIGHT)*2); + sdl_screen = SDL_SetVideoMode(HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, SDL_HWSURFACE); + } +} + +void Set_Video_InGame() +{ + if (sdl_screen->w != HOST_WIDTH_RESOLUTION) sdl_screen = SDL_SetVideoMode(HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, SDL_HWSURFACE); + Draw_to_Virtual_Screen = wswan_vs->pixels; + width_of_surface = INTERNAL_WSWAN_WIDTH; +} + +void Video_Close() +{ + if (sdl_screen) SDL_FreeSurface(sdl_screen); + if (backbuffer) SDL_FreeSurface(backbuffer); + if (wswan_vs) SDL_FreeSurface(wswan_vs); + if (wswan_vs_rot) SDL_FreeSurface(wswan_vs_rot); + SDL_Quit(); +} + +void Update_Video_Menu() +{ + SDL_Flip(sdl_screen); +} + +static void rotate_90_ccw(uint16_t* restrict dst, uint16_t* restrict src) +{ + int32_t h = 224, w = 144; + src += w * h - 1; + for (int32_t col = w - 1; col >= 0; --col) + { + uint16_t *outcol = dst + col; + for(int32_t row = 0; row < h; ++row, outcol += w) + { + *outcol = *src--; + } + } +} + +void Update_Video_Ingame() +{ + uint32_t internal_width, internal_height, keep_aspect_width, keep_aspect_height; + uint16_t* restrict source_graph; + + if ((Wswan_IsVertical() == 1 && option.orientation_settings != 2) || option.orientation_settings == 1) + { + rotate_90_ccw((uint16_t* restrict)wswan_vs_rot->pixels, (uint16_t* restrict)wswan_vs->pixels); + internal_width = INTERNAL_WSWAN_HEIGHT; + internal_height = INTERNAL_WSWAN_WIDTH; + source_graph = (uint16_t* restrict)wswan_vs_rot->pixels; + keep_aspect_width = ((HOST_HEIGHT_RESOLUTION / INTERNAL_WSWAN_HEIGHT) * INTERNAL_WSWAN_WIDTH) / 2; + if (keep_aspect_width > HOST_WIDTH_RESOLUTION) keep_aspect_width -= HOST_WIDTH_RESOLUTION/2; + keep_aspect_height = HOST_HEIGHT_RESOLUTION; + } + else + { + internal_width = INTERNAL_WSWAN_WIDTH; + internal_height = INTERNAL_WSWAN_HEIGHT; + source_graph = (uint16_t* restrict)wswan_vs->pixels; + keep_aspect_width = HOST_WIDTH_RESOLUTION; + keep_aspect_height = ((HOST_WIDTH_RESOLUTION / INTERNAL_WSWAN_WIDTH) * INTERNAL_WSWAN_HEIGHT); + if (keep_aspect_height > HOST_HEIGHT_RESOLUTION) keep_aspect_height -= HOST_HEIGHT_RESOLUTION/4; + } + + if (SDL_LockSurface(sdl_screen) == 0) + { + switch(option.fullscreen) + { + // Fullscreen + case 0: + bitmap_scale(0,0,internal_width,internal_height,internal_width*2,internal_height*2,internal_width, HOST_WIDTH_RESOLUTION - (internal_width*2),(uint16_t* restrict)source_graph,(uint16_t* restrict)sdl_screen->pixels+(HOST_WIDTH_RESOLUTION-(internal_width*2))/2+(HOST_HEIGHT_RESOLUTION-(internal_height*2))/2*HOST_WIDTH_RESOLUTION); + break; + // Fullscreen + case 1: + bitmap_scale(0, 0, internal_width, internal_height, HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, internal_width, 0, (uint16_t* restrict)source_graph, (uint16_t* restrict)sdl_screen->pixels); + break; + case 2: + bitmap_scale(0,0,internal_width,internal_height,keep_aspect_width,keep_aspect_height,internal_width, HOST_WIDTH_RESOLUTION - keep_aspect_width,(uint16_t* restrict)source_graph,(uint16_t* restrict)sdl_screen->pixels+(HOST_WIDTH_RESOLUTION-keep_aspect_width)/2+(HOST_HEIGHT_RESOLUTION-keep_aspect_height)/2*HOST_WIDTH_RESOLUTION); + break; + // Hqx + case 3: + break; + } + SDL_UnlockSurface(sdl_screen); + } + SDL_Flip(sdl_screen); +} diff --git a/shell/video/retrostone/video_blit.h b/shell/video/retrostone/video_blit.h new file mode 100644 index 0000000..8e1c81c --- /dev/null +++ b/shell/video/retrostone/video_blit.h @@ -0,0 +1,24 @@ +#ifndef VIDEO_BLIT_H +#define VIDEO_BLIT_H + +#include + +#define HOST_WIDTH_RESOLUTION (sdl_screen->w) +#define HOST_HEIGHT_RESOLUTION (sdl_screen->h) + +#define INTERNAL_WSWAN_WIDTH 224 +#define INTERNAL_WSWAN_HEIGHT 144 + +extern SDL_Surface *screen, *wswan_vs, *backbuffer; + +extern uint32_t width_of_surface; +extern uint32_t* Draw_to_Virtual_Screen; + +void Init_Video(); +void Set_Video_Menu(); +void Set_Video_InGame(); +void Close_Video(); +void Update_Video_Menu(); +void Update_Video_Ingame(); + +#endif diff --git a/shell/video/sdl/video_blit.c b/shell/video/sdl/video_blit.c new file mode 100644 index 0000000..9778039 --- /dev/null +++ b/shell/video/sdl/video_blit.c @@ -0,0 +1,132 @@ +/* Cygne + * + * Copyright notice for this file: + * Copyright (C) 2002 Dox dox@space.pl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "snes9x.h" +#include "soundux.h" +#include "memmap.h" +#include "apu.h" +#include "cheats.h" +#include "display.h" +#include "gfx.h" +#include "cpuexec.h" +#include "spc7110.h" +#include "srtc.h" +#include "sa1.h" +#include "scaler.h" + +#include "video_blit.h" +#include "scaler.h" +#include "config.h" + + +SDL_Surface *sdl_screen, *backbuffer; + +uint32_t width_of_surface; +uint32_t* Draw_to_Virtual_Screen; + +void Init_Video() +{ + SDL_Init( SDL_INIT_VIDEO ); + + SDL_ShowCursor(0); + + sdl_screen = SDL_SetVideoMode(HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, SDL_HWSURFACE); + + backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, 0,0,0,0); + + Set_Video_InGame(); +} + +void Set_Video_Menu() +{ + /*if (sdl_screen->w != HOST_WIDTH_RESOLUTION) + { + sdl_screen = SDL_SetVideoMode(HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, SDL_HWSURFACE); + }*/ +} + +void Set_Video_InGame() +{ + /*switch(option.fullscreen) + { + // Native + #ifdef SUPPORT_NATIVE_RESOLUTION + case 0: + if (sdl_screen->w != INTERNAL_WSWAN_WIDTH) sdl_screen = SDL_SetVideoMode(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, 16, SDL_HWSURFACE); + Draw_to_Virtual_Screen = sdl_screen->pixels; + width_of_surface = sdl_screen->w; + break; + #endif + default: + if (sdl_screen->w != HOST_WIDTH_RESOLUTION) sdl_screen = SDL_SetVideoMode(HOST_WIDTH_RESOLUTION, HOST_HEIGHT_RESOLUTION, 16, SDL_HWSURFACE); + Draw_to_Virtual_Screen = wswan_vs->pixels; + width_of_surface = INTERNAL_WSWAN_WIDTH; + break; + }*/ +} + +void Video_Close() +{ + if (sdl_screen) SDL_FreeSurface(sdl_screen); + if (backbuffer) SDL_FreeSurface(backbuffer); + SDL_Quit(); +} + +void Update_Video_Menu() +{ + SDL_Flip(sdl_screen); +} + +void Update_Video_Ingame() +{ + uint32_t *s, *d; + uint32_t h, w; + uint8_t PAL = !!(Memory.FillRAM[0x2133] & 4); + + SDL_LockSurface(sdl_screen); + + switch(option.fullscreen) + { + case 0: + s = (uint32_t*) GFX.Screen; + d = (uint32_t*) sdl_screen->pixels + ((sdl_screen->w - IPPU.RenderedScreenWidth)/4 + (sdl_screen->h - IPPU.RenderedScreenHeight) * 160) - (PAL ? 0 : 4*320); + for(uint8_t y = 0; y < IPPU.RenderedScreenHeight; y++, s += IPPU.RenderedScreenWidth, d += sdl_screen->w/2) memmove(d, s, IPPU.RenderedScreenWidth * 2); + + break; + case 1: + upscale_256xXXX_to_320x240((uint32_t*) sdl_screen->pixels, (uint32_t*) GFX.Screen, SNES_WIDTH, PAL ? 240 : 224); + break; + case 2: + if (IPPU.RenderedScreenHeight == 240) upscale_256x240_to_320x240_bilinearish((uint32_t*) sdl_screen->pixels, (uint32_t*) GFX.Screen, SNES_WIDTH, 239); + else upscale_256x240_to_320x240_bilinearish((uint32_t*) sdl_screen->pixels + (160*8), (uint32_t*) GFX.Screen, SNES_WIDTH, 224); + break; + } + //bitmap_scale(0, 0, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, sdl_screen->w, sdl_screen->h, SNES_WIDTH*2, 0, GFX.Screen, sdl_screen->pixels); + + SDL_UnlockSurface(sdl_screen); + SDL_Flip(sdl_screen); +} diff --git a/shell/video/sdl/video_blit.h b/shell/video/sdl/video_blit.h new file mode 100644 index 0000000..ea28ba9 --- /dev/null +++ b/shell/video/sdl/video_blit.h @@ -0,0 +1,24 @@ +#ifndef VIDEO_BLIT_H +#define VIDEO_BLIT_H + +#include + +#define HOST_WIDTH_RESOLUTION 320 +#define HOST_HEIGHT_RESOLUTION 240 + +#define INTERNAL_SNES_WIDTH_NTSC 256 +#define INTERNAL_SNES_HEIGHT_NTSC 224 + +extern SDL_Surface *screen, *backbuffer; + +extern uint32_t width_of_surface; +extern uint32_t* Draw_to_Virtual_Screen; + +void Init_Video(); +void Set_Video_Menu(); +void Set_Video_InGame(); +void Video_Close(); +void Update_Video_Menu(); +void Update_Video_Ingame(); + +#endif diff --git a/source/dsp1.c b/source/dsp1.c index f8a0713..5d8204c 100644 --- a/source/dsp1.c +++ b/source/dsp1.c @@ -3,8 +3,8 @@ #include "snes9x.h" #include "dsp1.h" #include "memmap.h" -#include "dsp1emu.c" -#include "dsp2emu.c" +#include "dsp1emu.h" +#include "dsp2emu.h" void (*SetDSP)(uint8_t, uint16_t) = &DSP1SetByte; uint8_t(*GetDSP)(uint16_t) = &DSP1GetByte; @@ -723,7 +723,7 @@ typedef struct SDSP4 DSP4; -#include "dsp4emu.c" +#include "dsp4emu.h" bool DSP4_init = false; diff --git a/source/dsp1emu.c b/source/dsp1emu.c deleted file mode 100644 index e7c3f7d..0000000 --- a/source/dsp1emu.c +++ /dev/null @@ -1,1127 +0,0 @@ -#include "../copyright" - -#include -#include -#include -#include -#include - -const uint16_t DSP1ROM[1024] = -{ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, - 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, - 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, - 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, - 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, - 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, - 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, - 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, - 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, - 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, - 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, - 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, - 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, - 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, - 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, - 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, - 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, - 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, - 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, - 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, - 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, - 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, - 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, - 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, - 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, - 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, - 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, - 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, - 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, - 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, - 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, - 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, - 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, - 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, - 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, - 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, - 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, - 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, - 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, - 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, - 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, - 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, - 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, - 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, - 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, - 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, - 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, - 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, - 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, - 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, - 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, - 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, - 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, - 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, - 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, - 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, - 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, - 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, - 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, - 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, - 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, - 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, - 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, - 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, - 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, - 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, - 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, - 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, - 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, - 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, - 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, - 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, - 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, - 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, - 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, - 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, - 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, - 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, - 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, - 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, - 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, - 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, - 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, - 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, - 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, - 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, - 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, - 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, - 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, - 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, - 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, - 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, - 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, - 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff -}; - -/***************************************************************************\ -* DSP1 code * -\***************************************************************************/ - -int16_t Op00Multiplicand; -int16_t Op00Multiplier; -int16_t Op00Result; - -void DSPOp00(void) -{ - Op00Result = Op00Multiplicand * Op00Multiplier >> 15; -} - -int16_t Op20Multiplicand; -int16_t Op20Multiplier; -int16_t Op20Result; - -void DSPOp20(void) -{ - Op20Result = Op20Multiplicand * Op20Multiplier >> 15; - Op20Result++; -} - -int16_t Op10Coefficient; -int16_t Op10Exponent; -int16_t Op10CoefficientR; -int16_t Op10ExponentR; - -void DSP1_Inverse(int16_t Coefficient, int16_t Exponent, int16_t* iCoefficient, int16_t* iExponent) -{ - /* Step One: Division by Zero */ - if (Coefficient == 0x0000) - { - *iCoefficient = 0x7fff; - *iExponent = 0x002f; - } - else - { - int16_t Sign = 1; - - /* Step Two: Remove Sign */ - if (Coefficient < 0) - { - if (Coefficient < -32767) - Coefficient = -32767; - Coefficient = -Coefficient; - Sign = -1; - } - - /* Step Three: Normalize */ - while (Coefficient < 0x4000) - { - Coefficient <<= 1; - Exponent--; - } - - /* Step Four: Special Case */ - if (Coefficient == 0x4000) - { - if (Sign == 1) - *iCoefficient = 0x7fff; - else - { - *iCoefficient = -0x4000; - Exponent--; - } - } - else - { - /* Step Five: Initial Guess */ - int16_t i = DSP1ROM[((Coefficient - 0x4000) >> 7) + 0x0065]; - - /* Step Six: Iterate "estimated" Newton's Method */ - i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; - i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; - - *iCoefficient = i * Sign; - } - - *iExponent = 1 - Exponent; - } -} - -void DSPOp10(void) -{ - DSP1_Inverse(Op10Coefficient, Op10Exponent, &Op10CoefficientR, &Op10ExponentR); -} - -int16_t Op04Angle; -int16_t Op04Radius; -int16_t Op04Sin; -int16_t Op04Cos; - -const int16_t DSP1_MulTable[256] = -{ - 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, - 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, - 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, - 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, - 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, - 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, - 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, - 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, - 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, - 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, - 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, - 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, - 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, - 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, - 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, - 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, - 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, - 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, - 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, - 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, - 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, - 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, - 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, - 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, - 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, - 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, - 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, - 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, - 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, - 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, - 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, - 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321 -}; - -const int16_t DSP1_SinTable[256] = -{ - 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, - 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, - 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, - 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, - 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, - 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, - 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, - 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, - 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, - 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, - 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, - 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, - 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, - 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, - 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, - 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, - -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, - -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, - -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, - -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, - -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, - -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, - -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, - -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, - -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, - -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, - -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, - -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, - -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, - -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, - -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, - -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 -}; - -int16_t DSP1_Sin(int16_t Angle) -{ - int32_t S; - - if (Angle < 0) - { - if (Angle == -32768) - return 0; - return -DSP1_Sin(-Angle); - } - S = DSP1_SinTable[Angle >> 8] + (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[0x40 + (Angle >> 8)] >> 15); - if (S > 32767) - S = 32767; - return (int16_t) S; -} - -int16_t DSP1_Cos(int16_t Angle) -{ - int32_t S; - - if (Angle < 0) - { - if (Angle == -32768) - return -32768; - Angle = -Angle; - } - S = DSP1_SinTable[0x40 + (Angle >> 8)] - (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[Angle >> 8] >> 15); - if (S < -32768) - S = -32767; - return (int16_t) S; -} - -void DSP1_Normalize(int16_t m, int16_t* Coefficient, int16_t* Exponent) -{ - int16_t i = 0x4000; - int16_t e = 0; - - if (m < 0) - { - while ((m & i) && i) - { - i >>= 1; - e++; - } - } - else - { - while (!(m & i) && i) - { - i >>= 1; - e++; - } - } - - if (e > 0) - *Coefficient = m * DSP1ROM[0x21 + e] << 1; - else - *Coefficient = m; - - *Exponent -= e; -} - -void DSP1_NormalizeDouble(int32_t Product, int16_t* Coefficient, int16_t* Exponent) -{ - int16_t n = Product & 0x7fff; - int16_t m = Product >> 15; - int16_t i = 0x4000; - int16_t e = 0; - - if (m < 0) - { - while ((m & i) && i) - { - i >>= 1; - e++; - } - } - else - { - while (!(m & i) && i) - { - i >>= 1; - e++; - } - } - - if (e > 0) - { - *Coefficient = m * DSP1ROM[0x0021 + e] << 1; - - if (e < 15) - *Coefficient += n * DSP1ROM[0x0040 - e] >> 15; - else - { - i = 0x4000; - - if (m < 0) - { - while ((n & i) && i) - { - i >>= 1; - e++; - } - } - else - { - while (!(n & i) && i) - { - i >>= 1; - e++; - } - } - - if (e > 15) - *Coefficient = n * DSP1ROM[0x0012 + e] << 1; - else - *Coefficient += n; - } - } - else - *Coefficient = m; - - *Exponent = e; -} - -int16_t DSP1_Truncate(int16_t C, int16_t E) -{ - if (E > 0) - { - if (C > 0) - return 32767; - else if (C < 0) - return -32767; - } - else if (E < 0) - return C * DSP1ROM[0x0031 + E] >> 15; - return C; -} - -void DSPOp04(void) -{ - Op04Sin = DSP1_Sin(Op04Angle) * Op04Radius >> 15; - Op04Cos = DSP1_Cos(Op04Angle) * Op04Radius >> 15; -} - -int16_t Op0CA; -int16_t Op0CX1; -int16_t Op0CY1; -int16_t Op0CX2; -int16_t Op0CY2; - -void DSPOp0C(void) -{ - Op0CX2 = (Op0CY1 * DSP1_Sin(Op0CA) >> 15) + (Op0CX1 * DSP1_Cos(Op0CA) >> 15); - Op0CY2 = (Op0CY1 * DSP1_Cos(Op0CA) >> 15) - (Op0CX1 * DSP1_Sin(Op0CA) >> 15); -} - -int16_t CentreX; -int16_t CentreY; -int16_t VOffset; - -int16_t VPlane_C; -int16_t VPlane_E; - -/* Azimuth and Zenith angles */ -int16_t SinAas; -int16_t CosAas; -int16_t SinAzs; -int16_t CosAzs; - -/* Clipped Zenith angle */ -int16_t SinAZS; -int16_t CosAZS; -int16_t SecAZS_C1; -int16_t SecAZS_E1; -int16_t SecAZS_C2; -int16_t SecAZS_E2; - -int16_t Nx, Ny, Nz; -int16_t Gx, Gy, Gz; -int16_t C_Les, E_Les, G_Les; - -const int16_t MaxAZS_Exp[16] = -{ - 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, - 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 -}; - -void DSP1_Parameter(int16_t Fx, int16_t Fy, int16_t Fz, int16_t Lfe, int16_t Les, int16_t Aas, int16_t Azs, int16_t* Vof, int16_t* Vva, int16_t* Cx, int16_t* Cy) -{ - int16_t CSec, C, E, MaxAZS, Aux; - int16_t LfeNx, LfeNy, LfeNz; - int16_t LesNx, LesNy, LesNz; - int16_t CentreZ; - - /* Copy Zenith angle for clipping */ - int16_t AZS = Azs; - - /* Store Sine and Cosine of Azimuth and Zenith angle */ - SinAas = DSP1_Sin(Aas); - CosAas = DSP1_Cos(Aas); - SinAzs = DSP1_Sin(Azs); - CosAzs = DSP1_Cos(Azs); - - Nx = SinAzs * -SinAas >> 15; - Ny = SinAzs * CosAas >> 15; - Nz = CosAzs * 0x7fff >> 15; - - LfeNx = Lfe * Nx >> 15; - LfeNy = Lfe * Ny >> 15; - LfeNz = Lfe * Nz >> 15; - - /* Center of Projection */ - CentreX = Fx + LfeNx; - CentreY = Fy + LfeNy; - CentreZ = Fz + LfeNz; - - LesNx = Les * Nx >> 15; - LesNy = Les * Ny >> 15; - LesNz = Les * Nz >> 15; - - Gx = CentreX - LesNx; - Gy = CentreY - LesNy; - Gz = CentreZ - LesNz; - - E_Les=0; - DSP1_Normalize(Les, &C_Les, &E_Les); - G_Les = Les; - - E = 0; - DSP1_Normalize(CentreZ, &C, &E); - - VPlane_C = C; - VPlane_E = E; - - /* Determine clip boundary and clip Zenith angle if necessary */ - MaxAZS = MaxAZS_Exp[-E]; - - if (AZS < 0) - { - MaxAZS = -MaxAZS; - if (AZS < MaxAZS + 1) - AZS = MaxAZS + 1; - } - else if (AZS > MaxAZS) - AZS = MaxAZS; - - /* Store Sine and Cosine of clipped Zenith angle */ - SinAZS = DSP1_Sin(AZS); - CosAZS = DSP1_Cos(AZS); - - DSP1_Inverse(CosAZS, 0, &SecAZS_C1, &SecAZS_E1); - DSP1_Normalize(C * SecAZS_C1 >> 15, &C, &E); - E += SecAZS_E1; - - C = DSP1_Truncate(C, E) * SinAZS >> 15; - - CentreX += C * SinAas >> 15; - CentreY -= C * CosAas >> 15; - - *Cx = CentreX; - *Cy = CentreY; - - /* Raster number of imaginary center and horizontal line */ - *Vof = 0; - - if ((Azs != AZS) || (Azs == MaxAZS)) - { - if (Azs == -32768) - Azs = -32767; - C = Azs - MaxAZS; - if (C >= 0) - C--; - Aux = ~(C << 2); - - C = Aux * DSP1ROM[0x0328] >> 15; - C = (C * Aux >> 15) + DSP1ROM[0x0327]; - *Vof -= (C * Aux >> 15) * Les >> 15; - - C = Aux * Aux >> 15; - Aux = (C * DSP1ROM[0x0324] >> 15) + DSP1ROM[0x0325]; - CosAZS += (C * Aux >> 15) * CosAZS >> 15; - } - - VOffset = Les * CosAZS >> 15; - - DSP1_Inverse(SinAZS, 0, &CSec, &E); - DSP1_Normalize(VOffset, &C, &E); - DSP1_Normalize(C * CSec >> 15, &C, &E); - - if (C == -32768) - { - C >>= 1; - E++; - } - - *Vva = DSP1_Truncate(-C, E); - - /* Store Secant of clipped Zenith angle */ - DSP1_Inverse(CosAZS, 0, &SecAZS_C2, &SecAZS_E2); -} - -void DSP1_Raster(int16_t Vs, int16_t* An, int16_t* Bn, int16_t* Cn, int16_t* Dn) -{ - int16_t C, E, C1, E1; - - DSP1_Inverse((Vs * SinAzs >> 15) + VOffset, 7, &C, &E); - E += VPlane_E; - - C1 = C * VPlane_C >> 15; - E1 = E + SecAZS_E2; - - DSP1_Normalize(C1, &C, &E); - - C = DSP1_Truncate(C, E); - - *An = C * CosAas >> 15; - *Cn = C * SinAas >> 15; - - DSP1_Normalize(C1 * SecAZS_C2 >> 15, &C, &E1); - - C = DSP1_Truncate(C, E1); - - *Bn = C * -SinAas >> 15; - *Dn = C * CosAas >> 15; -} - -int16_t Op02FX; -int16_t Op02FY; -int16_t Op02FZ; -int16_t Op02LFE; -int16_t Op02LES; -int16_t Op02AAS; -int16_t Op02AZS; -int16_t Op02VOF; -int16_t Op02VVA; -int16_t Op02CX; -int16_t Op02CY; - -void DSPOp02(void) -{ - DSP1_Parameter(Op02FX, Op02FY, Op02FZ, Op02LFE, Op02LES, Op02AAS, Op02AZS, &Op02VOF, &Op02VVA, &Op02CX, &Op02CY); -} - -int16_t Op0AVS; -int16_t Op0AA; -int16_t Op0AB; -int16_t Op0AC; -int16_t Op0AD; - -void DSPOp0A(void) -{ - DSP1_Raster(Op0AVS, &Op0AA, &Op0AB, &Op0AC, &Op0AD); - Op0AVS++; -} - -int16_t DSP1_ShiftR(int16_t C, int16_t E) -{ - return C * DSP1ROM[0x0031 + E] >> 15; -} - -void DSP1_Project(int16_t X, int16_t Y, int16_t Z, int16_t *H, int16_t *V, int16_t *M) -{ - int32_t aux, aux4; - int16_t E, E2, E3, E4, E5, refE, E6, E7; - int16_t C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; - int16_t Px, Py, Pz; - - E4 = E3 = E2 = E = E5 = 0; - - DSP1_NormalizeDouble((int32_t) X - Gx, &Px, &E4); - DSP1_NormalizeDouble((int32_t) Y - Gy, &Py, &E); - DSP1_NormalizeDouble((int32_t) Z - Gz, &Pz, &E3); - Px>>=1; - E4--; /* to avoid overflows when calculating the scalar products */ - Py>>=1; - E--; - Pz>>=1; - E3--; - - refE = MIN(E, E3); - refE = MIN(refE, E4); - - Px = DSP1_ShiftR(Px, E4 - refE); /* normalize them to the same exponent */ - Py = DSP1_ShiftR(Py, E - refE); - Pz = DSP1_ShiftR(Pz, E3 - refE); - - C11 = -(Px * Nx >> 15); - C8 = -(Py * Ny >> 15); - C9 = -(Pz * Nz >> 15); - C12 = C11 + C8 + C9; /* this cannot overflow! */ - - aux4 = C12; /* de-normalization with 32-bit arithmetic */ - refE = 16 - refE; /* refE can be up to 3 */ - if (refE >= 0) - aux4 <<= refE; - else - aux4 >>= -refE; - if (aux4 == -1) - aux4 = 0; /* why? */ - aux4>>=1; - - aux = ((int16_t) G_Les) + aux4; /* Les - the scalar product of P with the normal vector of the screen */ - DSP1_NormalizeDouble(aux, &C10, &E2); - E2 = 15 - E2; - - DSP1_Inverse(C10, 0, &C4, &E4); - C2 = C4 * C_Les >> 15; /* scale factor */ - - /* H */ - E7 = 0; - C16 = (Px * (CosAas * 0x7fff >> 15) >> 15); - C20 = (Py * (SinAas * 0x7fff >> 15) >> 15); - C17 = C16 + C20; /* scalar product of P with the normalized horizontal vector of the screen... */ - - C18 = C17 * C2 >> 15; /* ... multiplied by the scale factor */ - DSP1_Normalize(C18, &C19, &E7); - *H = DSP1_Truncate(C19, E_Les - E2 + refE + E7); - - /* V */ - E6 = 0; - C21 = Px * (CosAzs * -SinAas >> 15) >> 15; - C22 = Py * (CosAzs * CosAas >> 15) >> 15; - C23 = Pz * (-SinAzs * 0x7fff >> 15) >> 15; - C24 = C21 + C22 + C23; /* scalar product of P with the normalized vertical vector of the screen... */ - - C26 = C24 * C2 >> 15; /* ... multiplied by the scale factor */ - DSP1_Normalize(C26, &C25, &E6); - *V = DSP1_Truncate(C25, E_Les - E2 + refE + E6); - - /* M */ - DSP1_Normalize(C2, &C6, &E4); - *M = DSP1_Truncate(C6, E4 + E_Les - E2 - 7); /* M is the scale factor divided by 2^7 */ -} - -int16_t Op06X; -int16_t Op06Y; -int16_t Op06Z; -int16_t Op06H; -int16_t Op06V; -int16_t Op06M; - -void DSPOp06(void) -{ - DSP1_Project(Op06X, Op06Y, Op06Z, &Op06H, &Op06V, &Op06M); -} - -int16_t matrixC[3][3]; -int16_t matrixB[3][3]; -int16_t matrixA[3][3]; - -int16_t Op01m; -int16_t Op01Zr; -int16_t Op01Xr; -int16_t Op01Yr; -int16_t Op11m; -int16_t Op11Zr; -int16_t Op11Xr; -int16_t Op11Yr; -int16_t Op21m; -int16_t Op21Zr; -int16_t Op21Xr; -int16_t Op21Yr; - -void DSPOp01(void) -{ - int16_t SinAz = DSP1_Sin(Op01Zr); - int16_t CosAz = DSP1_Cos(Op01Zr); - int16_t SinAy = DSP1_Sin(Op01Yr); - int16_t CosAy = DSP1_Cos(Op01Yr); - int16_t SinAx = DSP1_Sin(Op01Xr); - int16_t CosAx = DSP1_Cos(Op01Xr); - - Op01m >>= 1; - - matrixA[0][0] = (Op01m * CosAz >> 15) * CosAy >> 15; - matrixA[0][1] = -((Op01m * SinAz >> 15) * CosAy >> 15); - matrixA[0][2] = Op01m * SinAy >> 15; - - matrixA[1][0] = ((Op01m * SinAz >> 15) * CosAx >> 15) + (((Op01m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixA[1][1] = ((Op01m * CosAz >> 15) * CosAx >> 15) - (((Op01m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixA[1][2] = -((Op01m * SinAx >> 15) * CosAy >> 15); - - matrixA[2][0] = ((Op01m * SinAz >> 15) * SinAx >> 15) - (((Op01m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixA[2][1] = ((Op01m * CosAz >> 15) * SinAx >> 15) + (((Op01m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixA[2][2] = (Op01m * CosAx >> 15) * CosAy >> 15; -} - -void DSPOp11(void) -{ - int16_t SinAz = DSP1_Sin(Op11Zr); - int16_t CosAz = DSP1_Cos(Op11Zr); - int16_t SinAy = DSP1_Sin(Op11Yr); - int16_t CosAy = DSP1_Cos(Op11Yr); - int16_t SinAx = DSP1_Sin(Op11Xr); - int16_t CosAx = DSP1_Cos(Op11Xr); - - Op11m >>= 1; - - matrixB[0][0] = (Op11m * CosAz >> 15) * CosAy >> 15; - matrixB[0][1] = -((Op11m * SinAz >> 15) * CosAy >> 15); - matrixB[0][2] = Op11m * SinAy >> 15; - - matrixB[1][0] = ((Op11m * SinAz >> 15) * CosAx >> 15) + (((Op11m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixB[1][1] = ((Op11m * CosAz >> 15) * CosAx >> 15) - (((Op11m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixB[1][2] = -((Op11m * SinAx >> 15) * CosAy >> 15); - - matrixB[2][0] = ((Op11m * SinAz >> 15) * SinAx >> 15) - (((Op11m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixB[2][1] = ((Op11m * CosAz >> 15) * SinAx >> 15) + (((Op11m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixB[2][2] = (Op11m * CosAx >> 15) * CosAy >> 15; -} - -void DSPOp21(void) -{ - int16_t SinAz = DSP1_Sin(Op21Zr); - int16_t CosAz = DSP1_Cos(Op21Zr); - int16_t SinAy = DSP1_Sin(Op21Yr); - int16_t CosAy = DSP1_Cos(Op21Yr); - int16_t SinAx = DSP1_Sin(Op21Xr); - int16_t CosAx = DSP1_Cos(Op21Xr); - - Op21m >>= 1; - - matrixC[0][0] = (Op21m * CosAz >> 15) * CosAy >> 15; - matrixC[0][1] = -((Op21m * SinAz >> 15) * CosAy >> 15); - matrixC[0][2] = Op21m * SinAy >> 15; - - matrixC[1][0] = ((Op21m * SinAz >> 15) * CosAx >> 15) + (((Op21m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixC[1][1] = ((Op21m * CosAz >> 15) * CosAx >> 15) - (((Op21m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); - matrixC[1][2] = -((Op21m * SinAx >> 15) * CosAy >> 15); - - matrixC[2][0] = ((Op21m * SinAz >> 15) * SinAx >> 15) - (((Op21m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixC[2][1] = ((Op21m * CosAz >> 15) * SinAx >> 15) + (((Op21m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); - matrixC[2][2] = (Op21m * CosAx >> 15) * CosAy >> 15; -} - -int16_t Op0DX; -int16_t Op0DY; -int16_t Op0DZ; -int16_t Op0DF; -int16_t Op0DL; -int16_t Op0DU; -int16_t Op1DX; -int16_t Op1DY; -int16_t Op1DZ; -int16_t Op1DF; -int16_t Op1DL; -int16_t Op1DU; -int16_t Op2DX; -int16_t Op2DY; -int16_t Op2DZ; -int16_t Op2DF; -int16_t Op2DL; -int16_t Op2DU; - -void DSPOp0D(void) -{ - Op0DF = (Op0DX * matrixA[0][0] >> 15) + (Op0DY * matrixA[0][1] >> 15) + (Op0DZ * matrixA[0][2] >> 15); - Op0DL = (Op0DX * matrixA[1][0] >> 15) + (Op0DY * matrixA[1][1] >> 15) + (Op0DZ * matrixA[1][2] >> 15); - Op0DU = (Op0DX * matrixA[2][0] >> 15) + (Op0DY * matrixA[2][1] >> 15) + (Op0DZ * matrixA[2][2] >> 15); -} - -void DSPOp1D(void) -{ - Op1DF = (Op1DX * matrixB[0][0] >> 15) + (Op1DY * matrixB[0][1] >> 15) + (Op1DZ * matrixB[0][2] >> 15); - Op1DL = (Op1DX * matrixB[1][0] >> 15) + (Op1DY * matrixB[1][1] >> 15) + (Op1DZ * matrixB[1][2] >> 15); - Op1DU = (Op1DX * matrixB[2][0] >> 15) + (Op1DY * matrixB[2][1] >> 15) + (Op1DZ * matrixB[2][2] >> 15); -} - -void DSPOp2D(void) -{ - Op2DF = (Op2DX * matrixC[0][0] >> 15) + (Op2DY * matrixC[0][1] >> 15) + (Op2DZ * matrixC[0][2] >> 15); - Op2DL = (Op2DX * matrixC[1][0] >> 15) + (Op2DY * matrixC[1][1] >> 15) + (Op2DZ * matrixC[1][2] >> 15); - Op2DU = (Op2DX * matrixC[2][0] >> 15) + (Op2DY * matrixC[2][1] >> 15) + (Op2DZ * matrixC[2][2] >> 15); -} - -int16_t Op03F; -int16_t Op03L; -int16_t Op03U; -int16_t Op03X; -int16_t Op03Y; -int16_t Op03Z; -int16_t Op13F; -int16_t Op13L; -int16_t Op13U; -int16_t Op13X; -int16_t Op13Y; -int16_t Op13Z; -int16_t Op23F; -int16_t Op23L; -int16_t Op23U; -int16_t Op23X; -int16_t Op23Y; -int16_t Op23Z; - -void DSPOp03(void) -{ - Op03X = (Op03F * matrixA[0][0] >> 15) + (Op03L * matrixA[1][0] >> 15) + (Op03U * matrixA[2][0] >> 15); - Op03Y = (Op03F * matrixA[0][1] >> 15) + (Op03L * matrixA[1][1] >> 15) + (Op03U * matrixA[2][1] >> 15); - Op03Z = (Op03F * matrixA[0][2] >> 15) + (Op03L * matrixA[1][2] >> 15) + (Op03U * matrixA[2][2] >> 15); -} - -void DSPOp13(void) -{ - Op13X = (Op13F * matrixB[0][0] >> 15) + (Op13L * matrixB[1][0] >> 15) + (Op13U * matrixB[2][0] >> 15); - Op13Y = (Op13F * matrixB[0][1] >> 15) + (Op13L * matrixB[1][1] >> 15) + (Op13U * matrixB[2][1] >> 15); - Op13Z = (Op13F * matrixB[0][2] >> 15) + (Op13L * matrixB[1][2] >> 15) + (Op13U * matrixB[2][2] >> 15); -} - -void DSPOp23(void) -{ - Op23X = (Op23F * matrixC[0][0] >> 15) + (Op23L * matrixC[1][0] >> 15) + (Op23U * matrixC[2][0] >> 15); - Op23Y = (Op23F * matrixC[0][1] >> 15) + (Op23L * matrixC[1][1] >> 15) + (Op23U * matrixC[2][1] >> 15); - Op23Z = (Op23F * matrixC[0][2] >> 15) + (Op23L * matrixC[1][2] >> 15) + (Op23U * matrixC[2][2] >> 15); -} - -int16_t Op14Zr; -int16_t Op14Xr; -int16_t Op14Yr; -int16_t Op14U; -int16_t Op14F; -int16_t Op14L; -int16_t Op14Zrr; -int16_t Op14Xrr; -int16_t Op14Yrr; - -void DSPOp14(void) -{ - int16_t CSec, ESec, CTan, CSin, C, E; - - DSP1_Inverse(DSP1_Cos(Op14Xr), 0, &CSec, &ESec); - - /* Rotation Around Z */ - DSP1_NormalizeDouble(Op14U * DSP1_Cos(Op14Yr) - Op14F * DSP1_Sin(Op14Yr), &C, &E); - - E = ESec - E; - - DSP1_Normalize(C * CSec >> 15, &C, &E); - - Op14Zrr = Op14Zr + DSP1_Truncate(C, E); - - /* Rotation Around X */ - Op14Xrr = Op14Xr + (Op14U * DSP1_Sin(Op14Yr) >> 15) + (Op14F * DSP1_Cos(Op14Yr) >> 15); - - /* Rotation Around Y */ - DSP1_NormalizeDouble(Op14U * DSP1_Cos(Op14Yr) + Op14F * DSP1_Sin(Op14Yr), &C, &E); - - E = ESec - E; - - DSP1_Normalize(DSP1_Sin(Op14Xr), &CSin, &E); - - CTan = CSec * CSin >> 15; - - DSP1_Normalize(-(C * CTan >> 15), &C, &E); - - Op14Yrr = Op14Yr + DSP1_Truncate(C, E) + Op14L; -} - -void DSP1_Target(int16_t H, int16_t V, int16_t* X, int16_t* Y) -{ - int16_t C, E, C1, E1; - - DSP1_Inverse((V * SinAzs >> 15) + VOffset, 8, &C, &E); - E += VPlane_E; - - C1 = C * VPlane_C >> 15; - E1 = E + SecAZS_E1; - - H <<= 8; - - DSP1_Normalize(C1, &C, &E); - - C = DSP1_Truncate(C, E) * H >> 15; - - *X = CentreX + (C * CosAas >> 15); - *Y = CentreY - (C * SinAas >> 15); - - V <<= 8; - - DSP1_Normalize(C1 * SecAZS_C1 >> 15, &C, &E1); - - C = DSP1_Truncate(C, E1) * V >> 15; - - *X += C * -SinAas >> 15; - *Y += C * CosAas >> 15; -} - -int16_t Op0EH; -int16_t Op0EV; -int16_t Op0EX; -int16_t Op0EY; - -void DSPOp0E(void) -{ - DSP1_Target(Op0EH, Op0EV, &Op0EX, &Op0EY); -} - -int16_t Op0BX; -int16_t Op0BY; -int16_t Op0BZ; -int16_t Op0BS; -int16_t Op1BX; -int16_t Op1BY; -int16_t Op1BZ; -int16_t Op1BS; -int16_t Op2BX; -int16_t Op2BY; -int16_t Op2BZ; -int16_t Op2BS; - -void DSPOp0B(void) -{ - Op0BS = (Op0BX * matrixA[0][0] + Op0BY * matrixA[0][1] + Op0BZ * matrixA[0][2]) >> 15; -} - -void DSPOp1B(void) -{ - Op1BS = (Op1BX * matrixB[0][0] + Op1BY * matrixB[0][1] + Op1BZ * matrixB[0][2]) >> 15; -} - -void DSPOp2B(void) -{ - Op2BS = (Op2BX * matrixC[0][0] + Op2BY * matrixC[0][1] + Op2BZ * matrixC[0][2]) >> 15; -} - -int16_t Op08X, Op08Y, Op08Z, Op08Ll, Op08Lh; - -void DSPOp08(void) -{ - int32_t Op08Size = (Op08X * Op08X + Op08Y * Op08Y + Op08Z * Op08Z) << 1; - Op08Ll = Op08Size & 0xffff; - Op08Lh = (Op08Size >> 16) & 0xffff; -} - -int16_t Op18X, Op18Y, Op18Z, Op18R, Op18D; - -void DSPOp18(void) -{ - Op18D = (Op18X * Op18X + Op18Y * Op18Y + Op18Z * Op18Z - Op18R * Op18R) >> 15; -} - -int16_t Op38X, Op38Y, Op38Z, Op38R, Op38D; - -void DSPOp38(void) -{ - Op38D = (Op38X * Op38X + Op38Y * Op38Y + Op38Z * Op38Z - Op38R * Op38R) >> 15; - Op38D++; -} - -int16_t Op28X; -int16_t Op28Y; -int16_t Op28Z; -int16_t Op28R; - -void DSPOp28(void) -{ - int32_t Radius = Op28X * Op28X + Op28Y * Op28Y + Op28Z * Op28Z; - - if (Radius == 0) - Op28R = 0; - else - { - int16_t C, E, Pos, Node1, Node2; - DSP1_NormalizeDouble(Radius, &C, &E); - if (E & 1) - C = C * 0x4000 >> 15; - - Pos = C * 0x0040 >> 15; - - Node1 = DSP1ROM[0x00d5 + Pos]; - Node2 = DSP1ROM[0x00d6 + Pos]; - - Op28R = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; - Op28R >>= (E >> 1); - } -} - -int16_t Op1CX, Op1CY, Op1CZ; -int16_t Op1CXBR, Op1CYBR, Op1CZBR, Op1CXAR, Op1CYAR, Op1CZAR; -int16_t Op1CX1; -int16_t Op1CY1; -int16_t Op1CZ1; -int16_t Op1CX2; -int16_t Op1CY2; -int16_t Op1CZ2; - -void DSPOp1C(void) -{ - /* Rotate Around Op1CZ1 */ - Op1CX1 = (Op1CYBR * DSP1_Sin(Op1CZ) >> 15) + (Op1CXBR * DSP1_Cos(Op1CZ) >> 15); - Op1CY1 = (Op1CYBR * DSP1_Cos(Op1CZ) >> 15) - (Op1CXBR * DSP1_Sin(Op1CZ) >> 15); - Op1CXBR = Op1CX1; - Op1CYBR = Op1CY1; - - /* Rotate Around Op1CY1 */ - Op1CZ1 = (Op1CXBR * DSP1_Sin(Op1CY) >> 15) + (Op1CZBR * DSP1_Cos(Op1CY) >> 15); - Op1CX1 = (Op1CXBR * DSP1_Cos(Op1CY) >> 15) - (Op1CZBR * DSP1_Sin(Op1CY) >> 15); - Op1CXAR = Op1CX1; - Op1CZBR = Op1CZ1; - - /* Rotate Around Op1CX1 */ - Op1CY1 = (Op1CZBR * DSP1_Sin(Op1CX) >> 15) + (Op1CYBR * DSP1_Cos(Op1CX) >> 15); - Op1CZ1 = (Op1CZBR * DSP1_Cos(Op1CX) >> 15) - (Op1CYBR * DSP1_Sin(Op1CX) >> 15); - Op1CYAR = Op1CY1; - Op1CZAR = Op1CZ1; -} - -uint16_t Op0FRamsize; -uint16_t Op0FPass; - -void DSPOp0F(void) -{ - Op0FPass = 0x0000; -} - -int16_t Op2FUnknown; -int16_t Op2FSize; - -void DSPOp2F(void) -{ - Op2FSize = 0x100; -} diff --git a/source/dsp1emu.h b/source/dsp1emu.h new file mode 100644 index 0000000..e7c3f7d --- /dev/null +++ b/source/dsp1emu.h @@ -0,0 +1,1127 @@ +#include "../copyright" + +#include +#include +#include +#include +#include + +const uint16_t DSP1ROM[1024] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, + 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08, + 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba, + 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038, + 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64, + 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523, + 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060, + 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c, + 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816, + 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474, + 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c, + 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05, + 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28, + 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f, + 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604, + 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4, + 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189, + 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1, + 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194, + 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a, + 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0, + 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122, + 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9, + 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324, + 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b, + 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de, + 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4, + 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4, + 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24, + 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c, + 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d, + 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6, + 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3, + 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504, + 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6, + 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842, + 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a, + 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11, + 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2, + 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc, + 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5, + 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22, + 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c, + 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c, + 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc, + 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894, + 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3, + 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080, + 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86, + 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40, + 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9, + 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2, + 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69, + 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920, + 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4, + 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686, + 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536, + 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3, + 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c, + 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131, + 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2, + 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e, + 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05, + 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94, + 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d, + 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d, + 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714, + 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581, + 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1, + 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232, + 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074, + 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1, + 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8, + 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1, + 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887, + 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e, + 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395, + 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e, + 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a, + 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811, + 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080, + 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488, + 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +/***************************************************************************\ +* DSP1 code * +\***************************************************************************/ + +int16_t Op00Multiplicand; +int16_t Op00Multiplier; +int16_t Op00Result; + +void DSPOp00(void) +{ + Op00Result = Op00Multiplicand * Op00Multiplier >> 15; +} + +int16_t Op20Multiplicand; +int16_t Op20Multiplier; +int16_t Op20Result; + +void DSPOp20(void) +{ + Op20Result = Op20Multiplicand * Op20Multiplier >> 15; + Op20Result++; +} + +int16_t Op10Coefficient; +int16_t Op10Exponent; +int16_t Op10CoefficientR; +int16_t Op10ExponentR; + +void DSP1_Inverse(int16_t Coefficient, int16_t Exponent, int16_t* iCoefficient, int16_t* iExponent) +{ + /* Step One: Division by Zero */ + if (Coefficient == 0x0000) + { + *iCoefficient = 0x7fff; + *iExponent = 0x002f; + } + else + { + int16_t Sign = 1; + + /* Step Two: Remove Sign */ + if (Coefficient < 0) + { + if (Coefficient < -32767) + Coefficient = -32767; + Coefficient = -Coefficient; + Sign = -1; + } + + /* Step Three: Normalize */ + while (Coefficient < 0x4000) + { + Coefficient <<= 1; + Exponent--; + } + + /* Step Four: Special Case */ + if (Coefficient == 0x4000) + { + if (Sign == 1) + *iCoefficient = 0x7fff; + else + { + *iCoefficient = -0x4000; + Exponent--; + } + } + else + { + /* Step Five: Initial Guess */ + int16_t i = DSP1ROM[((Coefficient - 0x4000) >> 7) + 0x0065]; + + /* Step Six: Iterate "estimated" Newton's Method */ + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1; + + *iCoefficient = i * Sign; + } + + *iExponent = 1 - Exponent; + } +} + +void DSPOp10(void) +{ + DSP1_Inverse(Op10Coefficient, Op10Exponent, &Op10CoefficientR, &Op10ExponentR); +} + +int16_t Op04Angle; +int16_t Op04Radius; +int16_t Op04Sin; +int16_t Op04Cos; + +const int16_t DSP1_MulTable[256] = +{ + 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, + 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f, + 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048, + 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061, + 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a, + 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093, + 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac, + 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5, + 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df, + 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8, + 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111, + 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a, + 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143, + 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c, + 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175, + 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e, + 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8, + 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1, + 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da, + 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3, + 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c, + 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, + 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e, + 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258, + 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271, + 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a, + 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3, + 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc, + 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5, + 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee, + 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307, + 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321 +}; + +const int16_t DSP1_SinTable[256] = +{ + 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, + 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, + 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, + 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, + 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, + 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, + 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, + -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2, + -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504, + -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3, + -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6, + -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d, + -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c, + -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4, + -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4, + -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de, + -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324 +}; + +int16_t DSP1_Sin(int16_t Angle) +{ + int32_t S; + + if (Angle < 0) + { + if (Angle == -32768) + return 0; + return -DSP1_Sin(-Angle); + } + S = DSP1_SinTable[Angle >> 8] + (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[0x40 + (Angle >> 8)] >> 15); + if (S > 32767) + S = 32767; + return (int16_t) S; +} + +int16_t DSP1_Cos(int16_t Angle) +{ + int32_t S; + + if (Angle < 0) + { + if (Angle == -32768) + return -32768; + Angle = -Angle; + } + S = DSP1_SinTable[0x40 + (Angle >> 8)] - (DSP1_MulTable[Angle & 0xff] * DSP1_SinTable[Angle >> 8] >> 15); + if (S < -32768) + S = -32767; + return (int16_t) S; +} + +void DSP1_Normalize(int16_t m, int16_t* Coefficient, int16_t* Exponent) +{ + int16_t i = 0x4000; + int16_t e = 0; + + if (m < 0) + { + while ((m & i) && i) + { + i >>= 1; + e++; + } + } + else + { + while (!(m & i) && i) + { + i >>= 1; + e++; + } + } + + if (e > 0) + *Coefficient = m * DSP1ROM[0x21 + e] << 1; + else + *Coefficient = m; + + *Exponent -= e; +} + +void DSP1_NormalizeDouble(int32_t Product, int16_t* Coefficient, int16_t* Exponent) +{ + int16_t n = Product & 0x7fff; + int16_t m = Product >> 15; + int16_t i = 0x4000; + int16_t e = 0; + + if (m < 0) + { + while ((m & i) && i) + { + i >>= 1; + e++; + } + } + else + { + while (!(m & i) && i) + { + i >>= 1; + e++; + } + } + + if (e > 0) + { + *Coefficient = m * DSP1ROM[0x0021 + e] << 1; + + if (e < 15) + *Coefficient += n * DSP1ROM[0x0040 - e] >> 15; + else + { + i = 0x4000; + + if (m < 0) + { + while ((n & i) && i) + { + i >>= 1; + e++; + } + } + else + { + while (!(n & i) && i) + { + i >>= 1; + e++; + } + } + + if (e > 15) + *Coefficient = n * DSP1ROM[0x0012 + e] << 1; + else + *Coefficient += n; + } + } + else + *Coefficient = m; + + *Exponent = e; +} + +int16_t DSP1_Truncate(int16_t C, int16_t E) +{ + if (E > 0) + { + if (C > 0) + return 32767; + else if (C < 0) + return -32767; + } + else if (E < 0) + return C * DSP1ROM[0x0031 + E] >> 15; + return C; +} + +void DSPOp04(void) +{ + Op04Sin = DSP1_Sin(Op04Angle) * Op04Radius >> 15; + Op04Cos = DSP1_Cos(Op04Angle) * Op04Radius >> 15; +} + +int16_t Op0CA; +int16_t Op0CX1; +int16_t Op0CY1; +int16_t Op0CX2; +int16_t Op0CY2; + +void DSPOp0C(void) +{ + Op0CX2 = (Op0CY1 * DSP1_Sin(Op0CA) >> 15) + (Op0CX1 * DSP1_Cos(Op0CA) >> 15); + Op0CY2 = (Op0CY1 * DSP1_Cos(Op0CA) >> 15) - (Op0CX1 * DSP1_Sin(Op0CA) >> 15); +} + +int16_t CentreX; +int16_t CentreY; +int16_t VOffset; + +int16_t VPlane_C; +int16_t VPlane_E; + +/* Azimuth and Zenith angles */ +int16_t SinAas; +int16_t CosAas; +int16_t SinAzs; +int16_t CosAzs; + +/* Clipped Zenith angle */ +int16_t SinAZS; +int16_t CosAZS; +int16_t SecAZS_C1; +int16_t SecAZS_E1; +int16_t SecAZS_C2; +int16_t SecAZS_E2; + +int16_t Nx, Ny, Nz; +int16_t Gx, Gy, Gz; +int16_t C_Les, E_Les, G_Les; + +const int16_t MaxAZS_Exp[16] = +{ + 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, + 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 +}; + +void DSP1_Parameter(int16_t Fx, int16_t Fy, int16_t Fz, int16_t Lfe, int16_t Les, int16_t Aas, int16_t Azs, int16_t* Vof, int16_t* Vva, int16_t* Cx, int16_t* Cy) +{ + int16_t CSec, C, E, MaxAZS, Aux; + int16_t LfeNx, LfeNy, LfeNz; + int16_t LesNx, LesNy, LesNz; + int16_t CentreZ; + + /* Copy Zenith angle for clipping */ + int16_t AZS = Azs; + + /* Store Sine and Cosine of Azimuth and Zenith angle */ + SinAas = DSP1_Sin(Aas); + CosAas = DSP1_Cos(Aas); + SinAzs = DSP1_Sin(Azs); + CosAzs = DSP1_Cos(Azs); + + Nx = SinAzs * -SinAas >> 15; + Ny = SinAzs * CosAas >> 15; + Nz = CosAzs * 0x7fff >> 15; + + LfeNx = Lfe * Nx >> 15; + LfeNy = Lfe * Ny >> 15; + LfeNz = Lfe * Nz >> 15; + + /* Center of Projection */ + CentreX = Fx + LfeNx; + CentreY = Fy + LfeNy; + CentreZ = Fz + LfeNz; + + LesNx = Les * Nx >> 15; + LesNy = Les * Ny >> 15; + LesNz = Les * Nz >> 15; + + Gx = CentreX - LesNx; + Gy = CentreY - LesNy; + Gz = CentreZ - LesNz; + + E_Les=0; + DSP1_Normalize(Les, &C_Les, &E_Les); + G_Les = Les; + + E = 0; + DSP1_Normalize(CentreZ, &C, &E); + + VPlane_C = C; + VPlane_E = E; + + /* Determine clip boundary and clip Zenith angle if necessary */ + MaxAZS = MaxAZS_Exp[-E]; + + if (AZS < 0) + { + MaxAZS = -MaxAZS; + if (AZS < MaxAZS + 1) + AZS = MaxAZS + 1; + } + else if (AZS > MaxAZS) + AZS = MaxAZS; + + /* Store Sine and Cosine of clipped Zenith angle */ + SinAZS = DSP1_Sin(AZS); + CosAZS = DSP1_Cos(AZS); + + DSP1_Inverse(CosAZS, 0, &SecAZS_C1, &SecAZS_E1); + DSP1_Normalize(C * SecAZS_C1 >> 15, &C, &E); + E += SecAZS_E1; + + C = DSP1_Truncate(C, E) * SinAZS >> 15; + + CentreX += C * SinAas >> 15; + CentreY -= C * CosAas >> 15; + + *Cx = CentreX; + *Cy = CentreY; + + /* Raster number of imaginary center and horizontal line */ + *Vof = 0; + + if ((Azs != AZS) || (Azs == MaxAZS)) + { + if (Azs == -32768) + Azs = -32767; + C = Azs - MaxAZS; + if (C >= 0) + C--; + Aux = ~(C << 2); + + C = Aux * DSP1ROM[0x0328] >> 15; + C = (C * Aux >> 15) + DSP1ROM[0x0327]; + *Vof -= (C * Aux >> 15) * Les >> 15; + + C = Aux * Aux >> 15; + Aux = (C * DSP1ROM[0x0324] >> 15) + DSP1ROM[0x0325]; + CosAZS += (C * Aux >> 15) * CosAZS >> 15; + } + + VOffset = Les * CosAZS >> 15; + + DSP1_Inverse(SinAZS, 0, &CSec, &E); + DSP1_Normalize(VOffset, &C, &E); + DSP1_Normalize(C * CSec >> 15, &C, &E); + + if (C == -32768) + { + C >>= 1; + E++; + } + + *Vva = DSP1_Truncate(-C, E); + + /* Store Secant of clipped Zenith angle */ + DSP1_Inverse(CosAZS, 0, &SecAZS_C2, &SecAZS_E2); +} + +void DSP1_Raster(int16_t Vs, int16_t* An, int16_t* Bn, int16_t* Cn, int16_t* Dn) +{ + int16_t C, E, C1, E1; + + DSP1_Inverse((Vs * SinAzs >> 15) + VOffset, 7, &C, &E); + E += VPlane_E; + + C1 = C * VPlane_C >> 15; + E1 = E + SecAZS_E2; + + DSP1_Normalize(C1, &C, &E); + + C = DSP1_Truncate(C, E); + + *An = C * CosAas >> 15; + *Cn = C * SinAas >> 15; + + DSP1_Normalize(C1 * SecAZS_C2 >> 15, &C, &E1); + + C = DSP1_Truncate(C, E1); + + *Bn = C * -SinAas >> 15; + *Dn = C * CosAas >> 15; +} + +int16_t Op02FX; +int16_t Op02FY; +int16_t Op02FZ; +int16_t Op02LFE; +int16_t Op02LES; +int16_t Op02AAS; +int16_t Op02AZS; +int16_t Op02VOF; +int16_t Op02VVA; +int16_t Op02CX; +int16_t Op02CY; + +void DSPOp02(void) +{ + DSP1_Parameter(Op02FX, Op02FY, Op02FZ, Op02LFE, Op02LES, Op02AAS, Op02AZS, &Op02VOF, &Op02VVA, &Op02CX, &Op02CY); +} + +int16_t Op0AVS; +int16_t Op0AA; +int16_t Op0AB; +int16_t Op0AC; +int16_t Op0AD; + +void DSPOp0A(void) +{ + DSP1_Raster(Op0AVS, &Op0AA, &Op0AB, &Op0AC, &Op0AD); + Op0AVS++; +} + +int16_t DSP1_ShiftR(int16_t C, int16_t E) +{ + return C * DSP1ROM[0x0031 + E] >> 15; +} + +void DSP1_Project(int16_t X, int16_t Y, int16_t Z, int16_t *H, int16_t *V, int16_t *M) +{ + int32_t aux, aux4; + int16_t E, E2, E3, E4, E5, refE, E6, E7; + int16_t C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; + int16_t Px, Py, Pz; + + E4 = E3 = E2 = E = E5 = 0; + + DSP1_NormalizeDouble((int32_t) X - Gx, &Px, &E4); + DSP1_NormalizeDouble((int32_t) Y - Gy, &Py, &E); + DSP1_NormalizeDouble((int32_t) Z - Gz, &Pz, &E3); + Px>>=1; + E4--; /* to avoid overflows when calculating the scalar products */ + Py>>=1; + E--; + Pz>>=1; + E3--; + + refE = MIN(E, E3); + refE = MIN(refE, E4); + + Px = DSP1_ShiftR(Px, E4 - refE); /* normalize them to the same exponent */ + Py = DSP1_ShiftR(Py, E - refE); + Pz = DSP1_ShiftR(Pz, E3 - refE); + + C11 = -(Px * Nx >> 15); + C8 = -(Py * Ny >> 15); + C9 = -(Pz * Nz >> 15); + C12 = C11 + C8 + C9; /* this cannot overflow! */ + + aux4 = C12; /* de-normalization with 32-bit arithmetic */ + refE = 16 - refE; /* refE can be up to 3 */ + if (refE >= 0) + aux4 <<= refE; + else + aux4 >>= -refE; + if (aux4 == -1) + aux4 = 0; /* why? */ + aux4>>=1; + + aux = ((int16_t) G_Les) + aux4; /* Les - the scalar product of P with the normal vector of the screen */ + DSP1_NormalizeDouble(aux, &C10, &E2); + E2 = 15 - E2; + + DSP1_Inverse(C10, 0, &C4, &E4); + C2 = C4 * C_Les >> 15; /* scale factor */ + + /* H */ + E7 = 0; + C16 = (Px * (CosAas * 0x7fff >> 15) >> 15); + C20 = (Py * (SinAas * 0x7fff >> 15) >> 15); + C17 = C16 + C20; /* scalar product of P with the normalized horizontal vector of the screen... */ + + C18 = C17 * C2 >> 15; /* ... multiplied by the scale factor */ + DSP1_Normalize(C18, &C19, &E7); + *H = DSP1_Truncate(C19, E_Les - E2 + refE + E7); + + /* V */ + E6 = 0; + C21 = Px * (CosAzs * -SinAas >> 15) >> 15; + C22 = Py * (CosAzs * CosAas >> 15) >> 15; + C23 = Pz * (-SinAzs * 0x7fff >> 15) >> 15; + C24 = C21 + C22 + C23; /* scalar product of P with the normalized vertical vector of the screen... */ + + C26 = C24 * C2 >> 15; /* ... multiplied by the scale factor */ + DSP1_Normalize(C26, &C25, &E6); + *V = DSP1_Truncate(C25, E_Les - E2 + refE + E6); + + /* M */ + DSP1_Normalize(C2, &C6, &E4); + *M = DSP1_Truncate(C6, E4 + E_Les - E2 - 7); /* M is the scale factor divided by 2^7 */ +} + +int16_t Op06X; +int16_t Op06Y; +int16_t Op06Z; +int16_t Op06H; +int16_t Op06V; +int16_t Op06M; + +void DSPOp06(void) +{ + DSP1_Project(Op06X, Op06Y, Op06Z, &Op06H, &Op06V, &Op06M); +} + +int16_t matrixC[3][3]; +int16_t matrixB[3][3]; +int16_t matrixA[3][3]; + +int16_t Op01m; +int16_t Op01Zr; +int16_t Op01Xr; +int16_t Op01Yr; +int16_t Op11m; +int16_t Op11Zr; +int16_t Op11Xr; +int16_t Op11Yr; +int16_t Op21m; +int16_t Op21Zr; +int16_t Op21Xr; +int16_t Op21Yr; + +void DSPOp01(void) +{ + int16_t SinAz = DSP1_Sin(Op01Zr); + int16_t CosAz = DSP1_Cos(Op01Zr); + int16_t SinAy = DSP1_Sin(Op01Yr); + int16_t CosAy = DSP1_Cos(Op01Yr); + int16_t SinAx = DSP1_Sin(Op01Xr); + int16_t CosAx = DSP1_Cos(Op01Xr); + + Op01m >>= 1; + + matrixA[0][0] = (Op01m * CosAz >> 15) * CosAy >> 15; + matrixA[0][1] = -((Op01m * SinAz >> 15) * CosAy >> 15); + matrixA[0][2] = Op01m * SinAy >> 15; + + matrixA[1][0] = ((Op01m * SinAz >> 15) * CosAx >> 15) + (((Op01m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixA[1][1] = ((Op01m * CosAz >> 15) * CosAx >> 15) - (((Op01m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixA[1][2] = -((Op01m * SinAx >> 15) * CosAy >> 15); + + matrixA[2][0] = ((Op01m * SinAz >> 15) * SinAx >> 15) - (((Op01m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixA[2][1] = ((Op01m * CosAz >> 15) * SinAx >> 15) + (((Op01m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixA[2][2] = (Op01m * CosAx >> 15) * CosAy >> 15; +} + +void DSPOp11(void) +{ + int16_t SinAz = DSP1_Sin(Op11Zr); + int16_t CosAz = DSP1_Cos(Op11Zr); + int16_t SinAy = DSP1_Sin(Op11Yr); + int16_t CosAy = DSP1_Cos(Op11Yr); + int16_t SinAx = DSP1_Sin(Op11Xr); + int16_t CosAx = DSP1_Cos(Op11Xr); + + Op11m >>= 1; + + matrixB[0][0] = (Op11m * CosAz >> 15) * CosAy >> 15; + matrixB[0][1] = -((Op11m * SinAz >> 15) * CosAy >> 15); + matrixB[0][2] = Op11m * SinAy >> 15; + + matrixB[1][0] = ((Op11m * SinAz >> 15) * CosAx >> 15) + (((Op11m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixB[1][1] = ((Op11m * CosAz >> 15) * CosAx >> 15) - (((Op11m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixB[1][2] = -((Op11m * SinAx >> 15) * CosAy >> 15); + + matrixB[2][0] = ((Op11m * SinAz >> 15) * SinAx >> 15) - (((Op11m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixB[2][1] = ((Op11m * CosAz >> 15) * SinAx >> 15) + (((Op11m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixB[2][2] = (Op11m * CosAx >> 15) * CosAy >> 15; +} + +void DSPOp21(void) +{ + int16_t SinAz = DSP1_Sin(Op21Zr); + int16_t CosAz = DSP1_Cos(Op21Zr); + int16_t SinAy = DSP1_Sin(Op21Yr); + int16_t CosAy = DSP1_Cos(Op21Yr); + int16_t SinAx = DSP1_Sin(Op21Xr); + int16_t CosAx = DSP1_Cos(Op21Xr); + + Op21m >>= 1; + + matrixC[0][0] = (Op21m * CosAz >> 15) * CosAy >> 15; + matrixC[0][1] = -((Op21m * SinAz >> 15) * CosAy >> 15); + matrixC[0][2] = Op21m * SinAy >> 15; + + matrixC[1][0] = ((Op21m * SinAz >> 15) * CosAx >> 15) + (((Op21m * CosAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixC[1][1] = ((Op21m * CosAz >> 15) * CosAx >> 15) - (((Op21m * SinAz >> 15) * SinAx >> 15) * SinAy >> 15); + matrixC[1][2] = -((Op21m * SinAx >> 15) * CosAy >> 15); + + matrixC[2][0] = ((Op21m * SinAz >> 15) * SinAx >> 15) - (((Op21m * CosAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixC[2][1] = ((Op21m * CosAz >> 15) * SinAx >> 15) + (((Op21m * SinAz >> 15) * CosAx >> 15) * SinAy >> 15); + matrixC[2][2] = (Op21m * CosAx >> 15) * CosAy >> 15; +} + +int16_t Op0DX; +int16_t Op0DY; +int16_t Op0DZ; +int16_t Op0DF; +int16_t Op0DL; +int16_t Op0DU; +int16_t Op1DX; +int16_t Op1DY; +int16_t Op1DZ; +int16_t Op1DF; +int16_t Op1DL; +int16_t Op1DU; +int16_t Op2DX; +int16_t Op2DY; +int16_t Op2DZ; +int16_t Op2DF; +int16_t Op2DL; +int16_t Op2DU; + +void DSPOp0D(void) +{ + Op0DF = (Op0DX * matrixA[0][0] >> 15) + (Op0DY * matrixA[0][1] >> 15) + (Op0DZ * matrixA[0][2] >> 15); + Op0DL = (Op0DX * matrixA[1][0] >> 15) + (Op0DY * matrixA[1][1] >> 15) + (Op0DZ * matrixA[1][2] >> 15); + Op0DU = (Op0DX * matrixA[2][0] >> 15) + (Op0DY * matrixA[2][1] >> 15) + (Op0DZ * matrixA[2][2] >> 15); +} + +void DSPOp1D(void) +{ + Op1DF = (Op1DX * matrixB[0][0] >> 15) + (Op1DY * matrixB[0][1] >> 15) + (Op1DZ * matrixB[0][2] >> 15); + Op1DL = (Op1DX * matrixB[1][0] >> 15) + (Op1DY * matrixB[1][1] >> 15) + (Op1DZ * matrixB[1][2] >> 15); + Op1DU = (Op1DX * matrixB[2][0] >> 15) + (Op1DY * matrixB[2][1] >> 15) + (Op1DZ * matrixB[2][2] >> 15); +} + +void DSPOp2D(void) +{ + Op2DF = (Op2DX * matrixC[0][0] >> 15) + (Op2DY * matrixC[0][1] >> 15) + (Op2DZ * matrixC[0][2] >> 15); + Op2DL = (Op2DX * matrixC[1][0] >> 15) + (Op2DY * matrixC[1][1] >> 15) + (Op2DZ * matrixC[1][2] >> 15); + Op2DU = (Op2DX * matrixC[2][0] >> 15) + (Op2DY * matrixC[2][1] >> 15) + (Op2DZ * matrixC[2][2] >> 15); +} + +int16_t Op03F; +int16_t Op03L; +int16_t Op03U; +int16_t Op03X; +int16_t Op03Y; +int16_t Op03Z; +int16_t Op13F; +int16_t Op13L; +int16_t Op13U; +int16_t Op13X; +int16_t Op13Y; +int16_t Op13Z; +int16_t Op23F; +int16_t Op23L; +int16_t Op23U; +int16_t Op23X; +int16_t Op23Y; +int16_t Op23Z; + +void DSPOp03(void) +{ + Op03X = (Op03F * matrixA[0][0] >> 15) + (Op03L * matrixA[1][0] >> 15) + (Op03U * matrixA[2][0] >> 15); + Op03Y = (Op03F * matrixA[0][1] >> 15) + (Op03L * matrixA[1][1] >> 15) + (Op03U * matrixA[2][1] >> 15); + Op03Z = (Op03F * matrixA[0][2] >> 15) + (Op03L * matrixA[1][2] >> 15) + (Op03U * matrixA[2][2] >> 15); +} + +void DSPOp13(void) +{ + Op13X = (Op13F * matrixB[0][0] >> 15) + (Op13L * matrixB[1][0] >> 15) + (Op13U * matrixB[2][0] >> 15); + Op13Y = (Op13F * matrixB[0][1] >> 15) + (Op13L * matrixB[1][1] >> 15) + (Op13U * matrixB[2][1] >> 15); + Op13Z = (Op13F * matrixB[0][2] >> 15) + (Op13L * matrixB[1][2] >> 15) + (Op13U * matrixB[2][2] >> 15); +} + +void DSPOp23(void) +{ + Op23X = (Op23F * matrixC[0][0] >> 15) + (Op23L * matrixC[1][0] >> 15) + (Op23U * matrixC[2][0] >> 15); + Op23Y = (Op23F * matrixC[0][1] >> 15) + (Op23L * matrixC[1][1] >> 15) + (Op23U * matrixC[2][1] >> 15); + Op23Z = (Op23F * matrixC[0][2] >> 15) + (Op23L * matrixC[1][2] >> 15) + (Op23U * matrixC[2][2] >> 15); +} + +int16_t Op14Zr; +int16_t Op14Xr; +int16_t Op14Yr; +int16_t Op14U; +int16_t Op14F; +int16_t Op14L; +int16_t Op14Zrr; +int16_t Op14Xrr; +int16_t Op14Yrr; + +void DSPOp14(void) +{ + int16_t CSec, ESec, CTan, CSin, C, E; + + DSP1_Inverse(DSP1_Cos(Op14Xr), 0, &CSec, &ESec); + + /* Rotation Around Z */ + DSP1_NormalizeDouble(Op14U * DSP1_Cos(Op14Yr) - Op14F * DSP1_Sin(Op14Yr), &C, &E); + + E = ESec - E; + + DSP1_Normalize(C * CSec >> 15, &C, &E); + + Op14Zrr = Op14Zr + DSP1_Truncate(C, E); + + /* Rotation Around X */ + Op14Xrr = Op14Xr + (Op14U * DSP1_Sin(Op14Yr) >> 15) + (Op14F * DSP1_Cos(Op14Yr) >> 15); + + /* Rotation Around Y */ + DSP1_NormalizeDouble(Op14U * DSP1_Cos(Op14Yr) + Op14F * DSP1_Sin(Op14Yr), &C, &E); + + E = ESec - E; + + DSP1_Normalize(DSP1_Sin(Op14Xr), &CSin, &E); + + CTan = CSec * CSin >> 15; + + DSP1_Normalize(-(C * CTan >> 15), &C, &E); + + Op14Yrr = Op14Yr + DSP1_Truncate(C, E) + Op14L; +} + +void DSP1_Target(int16_t H, int16_t V, int16_t* X, int16_t* Y) +{ + int16_t C, E, C1, E1; + + DSP1_Inverse((V * SinAzs >> 15) + VOffset, 8, &C, &E); + E += VPlane_E; + + C1 = C * VPlane_C >> 15; + E1 = E + SecAZS_E1; + + H <<= 8; + + DSP1_Normalize(C1, &C, &E); + + C = DSP1_Truncate(C, E) * H >> 15; + + *X = CentreX + (C * CosAas >> 15); + *Y = CentreY - (C * SinAas >> 15); + + V <<= 8; + + DSP1_Normalize(C1 * SecAZS_C1 >> 15, &C, &E1); + + C = DSP1_Truncate(C, E1) * V >> 15; + + *X += C * -SinAas >> 15; + *Y += C * CosAas >> 15; +} + +int16_t Op0EH; +int16_t Op0EV; +int16_t Op0EX; +int16_t Op0EY; + +void DSPOp0E(void) +{ + DSP1_Target(Op0EH, Op0EV, &Op0EX, &Op0EY); +} + +int16_t Op0BX; +int16_t Op0BY; +int16_t Op0BZ; +int16_t Op0BS; +int16_t Op1BX; +int16_t Op1BY; +int16_t Op1BZ; +int16_t Op1BS; +int16_t Op2BX; +int16_t Op2BY; +int16_t Op2BZ; +int16_t Op2BS; + +void DSPOp0B(void) +{ + Op0BS = (Op0BX * matrixA[0][0] + Op0BY * matrixA[0][1] + Op0BZ * matrixA[0][2]) >> 15; +} + +void DSPOp1B(void) +{ + Op1BS = (Op1BX * matrixB[0][0] + Op1BY * matrixB[0][1] + Op1BZ * matrixB[0][2]) >> 15; +} + +void DSPOp2B(void) +{ + Op2BS = (Op2BX * matrixC[0][0] + Op2BY * matrixC[0][1] + Op2BZ * matrixC[0][2]) >> 15; +} + +int16_t Op08X, Op08Y, Op08Z, Op08Ll, Op08Lh; + +void DSPOp08(void) +{ + int32_t Op08Size = (Op08X * Op08X + Op08Y * Op08Y + Op08Z * Op08Z) << 1; + Op08Ll = Op08Size & 0xffff; + Op08Lh = (Op08Size >> 16) & 0xffff; +} + +int16_t Op18X, Op18Y, Op18Z, Op18R, Op18D; + +void DSPOp18(void) +{ + Op18D = (Op18X * Op18X + Op18Y * Op18Y + Op18Z * Op18Z - Op18R * Op18R) >> 15; +} + +int16_t Op38X, Op38Y, Op38Z, Op38R, Op38D; + +void DSPOp38(void) +{ + Op38D = (Op38X * Op38X + Op38Y * Op38Y + Op38Z * Op38Z - Op38R * Op38R) >> 15; + Op38D++; +} + +int16_t Op28X; +int16_t Op28Y; +int16_t Op28Z; +int16_t Op28R; + +void DSPOp28(void) +{ + int32_t Radius = Op28X * Op28X + Op28Y * Op28Y + Op28Z * Op28Z; + + if (Radius == 0) + Op28R = 0; + else + { + int16_t C, E, Pos, Node1, Node2; + DSP1_NormalizeDouble(Radius, &C, &E); + if (E & 1) + C = C * 0x4000 >> 15; + + Pos = C * 0x0040 >> 15; + + Node1 = DSP1ROM[0x00d5 + Pos]; + Node2 = DSP1ROM[0x00d6 + Pos]; + + Op28R = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1; + Op28R >>= (E >> 1); + } +} + +int16_t Op1CX, Op1CY, Op1CZ; +int16_t Op1CXBR, Op1CYBR, Op1CZBR, Op1CXAR, Op1CYAR, Op1CZAR; +int16_t Op1CX1; +int16_t Op1CY1; +int16_t Op1CZ1; +int16_t Op1CX2; +int16_t Op1CY2; +int16_t Op1CZ2; + +void DSPOp1C(void) +{ + /* Rotate Around Op1CZ1 */ + Op1CX1 = (Op1CYBR * DSP1_Sin(Op1CZ) >> 15) + (Op1CXBR * DSP1_Cos(Op1CZ) >> 15); + Op1CY1 = (Op1CYBR * DSP1_Cos(Op1CZ) >> 15) - (Op1CXBR * DSP1_Sin(Op1CZ) >> 15); + Op1CXBR = Op1CX1; + Op1CYBR = Op1CY1; + + /* Rotate Around Op1CY1 */ + Op1CZ1 = (Op1CXBR * DSP1_Sin(Op1CY) >> 15) + (Op1CZBR * DSP1_Cos(Op1CY) >> 15); + Op1CX1 = (Op1CXBR * DSP1_Cos(Op1CY) >> 15) - (Op1CZBR * DSP1_Sin(Op1CY) >> 15); + Op1CXAR = Op1CX1; + Op1CZBR = Op1CZ1; + + /* Rotate Around Op1CX1 */ + Op1CY1 = (Op1CZBR * DSP1_Sin(Op1CX) >> 15) + (Op1CYBR * DSP1_Cos(Op1CX) >> 15); + Op1CZ1 = (Op1CZBR * DSP1_Cos(Op1CX) >> 15) - (Op1CYBR * DSP1_Sin(Op1CX) >> 15); + Op1CYAR = Op1CY1; + Op1CZAR = Op1CZ1; +} + +uint16_t Op0FRamsize; +uint16_t Op0FPass; + +void DSPOp0F(void) +{ + Op0FPass = 0x0000; +} + +int16_t Op2FUnknown; +int16_t Op2FSize; + +void DSPOp2F(void) +{ + Op2FSize = 0x100; +} diff --git a/source/dsp2emu.c b/source/dsp2emu.c deleted file mode 100644 index 48e06c2..0000000 --- a/source/dsp2emu.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "../copyright" - -uint16_t DSP2Op09Word1 = 0; -uint16_t DSP2Op09Word2 = 0; -bool DSP2Op05HasLen = false; -int32_t DSP2Op05Len = 0; -bool DSP2Op06HasLen = false; -int32_t DSP2Op06Len = 0; -uint8_t DSP2Op05Transparent = 0; - -void DSP2_Op05(void) -{ - uint8_t color; - /* Overlay bitmap with transparency. - * Input: - * - * Bitmap 1: i[0] <=> i[size-1] - * Bitmap 2: i[size] <=> i[2*size-1] - * - * Output: - * - * Bitmap 3: o[0] <=> o[size-1] - * - * Processing: - * - * Process all 4-bit pixels (nibbles) in the bitmap - * - * if ( BM2_pixel == transparent_color ) - * pixelout = BM1_pixel - * else - * pixelout = BM2_pixel - - * The max size bitmap is limited to 255 because the size parameter is a byte - * I think size=0 is an error. The behavior of the chip on size=0 is to - * return the last value written to DR if you read DR on Op05 with - * size = 0. I don't think it's worth implementing this quirk unless it's - * proven necessary. - */ - - int32_t n; - uint8_t c1; - uint8_t c2; - uint8_t* p1 = DSP1.parameters; - uint8_t* p2 = &DSP1.parameters[DSP2Op05Len]; - uint8_t* p3 = DSP1.output; - - color = DSP2Op05Transparent & 0x0f; - - for (n = 0; n < DSP2Op05Len; n++) - { - c1 = *p1++; - c2 = *p2++; - *p3++ = (((c2 >> 4) == color) ? c1 & 0xf0 : c2 & 0xf0) | (((c2 & 0x0f) == color) ? c1 & 0x0f : c2 & 0x0f); - } -} - -void DSP2_Op01(void) -{ - /* Op01 size is always 32 bytes input and output. - * The hardware does strange things if you vary the size. */ - int32_t j; - uint8_t c0, c1, c2, c3; - uint8_t* p1 = DSP1.parameters; - uint8_t* p2a = DSP1.output; - uint8_t* p2b = &DSP1.output[16]; /* halfway */ - - /* Process 8 blocks of 4 bytes each */ - for (j = 0; j < 8; j++) - { - c0 = *p1++; - c1 = *p1++; - c2 = *p1++; - c3 = *p1++; - *p2a++ = (c0 & 0x10) << 3 | (c0 & 0x01) << 6 | (c1 & 0x10) << 1 | (c1 & 0x01) << 4 | (c2 & 0x10) >> 1 | (c2 & 0x01) << 2 | (c3 & 0x10) >> 3 | (c3 & 0x01); - *p2a++ = (c0 & 0x20) << 2 | (c0 & 0x02) << 5 | (c1 & 0x20) | (c1 & 0x02) << 3 | (c2 & 0x20) >> 2 | (c2 & 0x02) << 1 | (c3 & 0x20) >> 4 | (c3 & 0x02) >> 1; - *p2b++ = (c0 & 0x40) << 1 | (c0 & 0x04) << 4 | (c1 & 0x40) >> 1 | (c1 & 0x04) << 2 | (c2 & 0x40) >> 3 | (c2 & 0x04) | (c3 & 0x40) >> 5 | (c3 & 0x04) >> 2; - *p2b++ = (c0 & 0x80) | (c0 & 0x08) << 3 | (c1 & 0x80) >> 2 | (c1 & 0x08) << 1 | (c2 & 0x80) >> 4 | (c2 & 0x08) >> 1 | (c3 & 0x80) >> 6 | (c3 & 0x08) >> 3; - } -} - -void DSP2_Op06(void) -{ - /* Input: - * size - * bitmap - */ - - int32_t i, j; - - for (i = 0, j = DSP2Op06Len - 1; i < DSP2Op06Len; i++, j--) - DSP1.output[j] = (DSP1.parameters[i] << 4) | (DSP1.parameters[i] >> 4); -} - -bool DSP2Op0DHasLen = false; -int32_t DSP2Op0DOutLen = 0; -int32_t DSP2Op0DInLen = 0; - -/* Scale bitmap based on input length out output length */ -void DSP2_Op0D(void) -{ - /* (Modified) Overload's algorithm */ - int32_t i; - for(i = 0 ; i < DSP2Op0DOutLen ; i++) - { - int32_t j = i << 1; - int32_t pixel_offset_low = ((j * DSP2Op0DInLen) / DSP2Op0DOutLen) >> 1; - int32_t pixel_offset_high = (((j + 1) * DSP2Op0DInLen) / DSP2Op0DOutLen) >> 1; - uint8_t pixel_low = DSP1.parameters[pixel_offset_low] >> 4; - uint8_t pixel_high = DSP1.parameters[pixel_offset_high] & 0x0f; - DSP1.output[i] = (pixel_low << 4) | pixel_high; - } -} diff --git a/source/dsp2emu.h b/source/dsp2emu.h new file mode 100644 index 0000000..48e06c2 --- /dev/null +++ b/source/dsp2emu.h @@ -0,0 +1,112 @@ +#include "../copyright" + +uint16_t DSP2Op09Word1 = 0; +uint16_t DSP2Op09Word2 = 0; +bool DSP2Op05HasLen = false; +int32_t DSP2Op05Len = 0; +bool DSP2Op06HasLen = false; +int32_t DSP2Op06Len = 0; +uint8_t DSP2Op05Transparent = 0; + +void DSP2_Op05(void) +{ + uint8_t color; + /* Overlay bitmap with transparency. + * Input: + * + * Bitmap 1: i[0] <=> i[size-1] + * Bitmap 2: i[size] <=> i[2*size-1] + * + * Output: + * + * Bitmap 3: o[0] <=> o[size-1] + * + * Processing: + * + * Process all 4-bit pixels (nibbles) in the bitmap + * + * if ( BM2_pixel == transparent_color ) + * pixelout = BM1_pixel + * else + * pixelout = BM2_pixel + + * The max size bitmap is limited to 255 because the size parameter is a byte + * I think size=0 is an error. The behavior of the chip on size=0 is to + * return the last value written to DR if you read DR on Op05 with + * size = 0. I don't think it's worth implementing this quirk unless it's + * proven necessary. + */ + + int32_t n; + uint8_t c1; + uint8_t c2; + uint8_t* p1 = DSP1.parameters; + uint8_t* p2 = &DSP1.parameters[DSP2Op05Len]; + uint8_t* p3 = DSP1.output; + + color = DSP2Op05Transparent & 0x0f; + + for (n = 0; n < DSP2Op05Len; n++) + { + c1 = *p1++; + c2 = *p2++; + *p3++ = (((c2 >> 4) == color) ? c1 & 0xf0 : c2 & 0xf0) | (((c2 & 0x0f) == color) ? c1 & 0x0f : c2 & 0x0f); + } +} + +void DSP2_Op01(void) +{ + /* Op01 size is always 32 bytes input and output. + * The hardware does strange things if you vary the size. */ + int32_t j; + uint8_t c0, c1, c2, c3; + uint8_t* p1 = DSP1.parameters; + uint8_t* p2a = DSP1.output; + uint8_t* p2b = &DSP1.output[16]; /* halfway */ + + /* Process 8 blocks of 4 bytes each */ + for (j = 0; j < 8; j++) + { + c0 = *p1++; + c1 = *p1++; + c2 = *p1++; + c3 = *p1++; + *p2a++ = (c0 & 0x10) << 3 | (c0 & 0x01) << 6 | (c1 & 0x10) << 1 | (c1 & 0x01) << 4 | (c2 & 0x10) >> 1 | (c2 & 0x01) << 2 | (c3 & 0x10) >> 3 | (c3 & 0x01); + *p2a++ = (c0 & 0x20) << 2 | (c0 & 0x02) << 5 | (c1 & 0x20) | (c1 & 0x02) << 3 | (c2 & 0x20) >> 2 | (c2 & 0x02) << 1 | (c3 & 0x20) >> 4 | (c3 & 0x02) >> 1; + *p2b++ = (c0 & 0x40) << 1 | (c0 & 0x04) << 4 | (c1 & 0x40) >> 1 | (c1 & 0x04) << 2 | (c2 & 0x40) >> 3 | (c2 & 0x04) | (c3 & 0x40) >> 5 | (c3 & 0x04) >> 2; + *p2b++ = (c0 & 0x80) | (c0 & 0x08) << 3 | (c1 & 0x80) >> 2 | (c1 & 0x08) << 1 | (c2 & 0x80) >> 4 | (c2 & 0x08) >> 1 | (c3 & 0x80) >> 6 | (c3 & 0x08) >> 3; + } +} + +void DSP2_Op06(void) +{ + /* Input: + * size + * bitmap + */ + + int32_t i, j; + + for (i = 0, j = DSP2Op06Len - 1; i < DSP2Op06Len; i++, j--) + DSP1.output[j] = (DSP1.parameters[i] << 4) | (DSP1.parameters[i] >> 4); +} + +bool DSP2Op0DHasLen = false; +int32_t DSP2Op0DOutLen = 0; +int32_t DSP2Op0DInLen = 0; + +/* Scale bitmap based on input length out output length */ +void DSP2_Op0D(void) +{ + /* (Modified) Overload's algorithm */ + int32_t i; + for(i = 0 ; i < DSP2Op0DOutLen ; i++) + { + int32_t j = i << 1; + int32_t pixel_offset_low = ((j * DSP2Op0DInLen) / DSP2Op0DOutLen) >> 1; + int32_t pixel_offset_high = (((j + 1) * DSP2Op0DInLen) / DSP2Op0DOutLen) >> 1; + uint8_t pixel_low = DSP1.parameters[pixel_offset_low] >> 4; + uint8_t pixel_high = DSP1.parameters[pixel_offset_high] & 0x0f; + DSP1.output[i] = (pixel_low << 4) | pixel_high; + } +} diff --git a/source/dsp4emu.c b/source/dsp4emu.c deleted file mode 100644 index da6e80f..0000000 --- a/source/dsp4emu.c +++ /dev/null @@ -1,1227 +0,0 @@ -#include "../copyright" - -#include "dsp4.h" -#include "memmap.h" - -#define DSP4_READ_WORD(x) \ - READ_WORD(DSP4.parameters+x) - -#define DSP4_WRITE_WORD(x,d) \ - WRITE_WORD(DSP4.output+x,d); - -/* used to wait for dsp i/o */ -#define DSP4_WAIT(x) \ - DSP4_Logic = x; \ - return - -int32_t DSP4_Multiply(int16_t Multiplicand, int16_t Multiplier) -{ - return Multiplicand * Multiplier; -} - -int16_t DSP4_UnknownOP11(int16_t A, int16_t B, int16_t C, int16_t D) -{ - return ((A * 0x0155 >> 2) & 0xf000) | ((B * 0x0155 >> 6) & 0x0f00) | ((C * 0x0155 >> 10) & 0x00f0) | ((D * 0x0155 >> 14) & 0x000f); -} - -void DSP4_Op06(bool size, bool msb) -{ - /* save post-oam table data for future retrieval */ - op06_OAM[op06_index] |= (msb << (op06_offset + 0)); - op06_OAM[op06_index] |= (size << (op06_offset + 1)); - op06_offset += 2; - - if (op06_offset == 8) - { - /* move to next byte in buffer */ - op06_offset = 0; - op06_index++; - } -} - -void DSP4_Op01(void) -{ - int16_t plane; - int16_t index, lcv; - int16_t py_dy, px_dx; - int16_t y_out, x_out; - uint16_t command; - DSP4.waiting4command = false; - - switch (DSP4_Logic) /* op flow control */ - { - case 1: - goto resume1; - break; - case 2: - goto resume2; - break; - } - - /* - * process initial inputs - */ - - /* sort inputs */ - project_focaly = DSP4_READ_WORD(0x02); - raster = DSP4_READ_WORD(0x04); - viewport_top = DSP4_READ_WORD(0x06); - project_y = DSP4_READ_WORD(0x08); - viewport_bottom = DSP4_READ_WORD(0x0a); - project_x1low = DSP4_READ_WORD(0x0c); - project_focalx = DSP4_READ_WORD(0x0e); - project_centerx = DSP4_READ_WORD(0x10); - project_ptr = DSP4_READ_WORD(0x12); - project_pitchylow = DSP4_READ_WORD(0x16); - project_pitchy = DSP4_READ_WORD(0x18); - project_pitchxlow = DSP4_READ_WORD(0x1a); - project_pitchx = DSP4_READ_WORD(0x1c); - far_plane = DSP4_READ_WORD(0x1e); - project_y1low = DSP4_READ_WORD(0x22); - - /* pre-compute */ - view_plane = PLANE_START; - - /* find starting projection points */ - project_x1 = project_focalx; - project_y -= viewport_bottom; - project_x = project_centerx + project_x1; - - /* multi-op storage */ - multi_index1 = 0; - multi_index2 = 0; - - /* - * command check - */ - - do - { - /* scan next command */ - DSP4.in_count = 2; - DSP4_WAIT(1); - -resume1: - /* inspect input */ - command = DSP4_READ_WORD(0); - - /* check for termination */ - if(command == 0x8000) - break; - - /* already have 2 bytes in queue */ - DSP4.in_index = 2; - DSP4.in_count = 8; - DSP4_WAIT(2); - - /* process one iteration of projection */ - - /* inspect inputs */ - -resume2: - plane = DSP4_READ_WORD(0); - px_dx = 0; - - /* ignore invalid data */ - if((uint16_t) plane == 0x8001) - continue; - - /* one-time init */ - if (far_plane) - { - /* setup final parameters */ - project_focalx += plane; - project_x1 = project_focalx; - project_y1 = project_focaly; - plane = far_plane; - far_plane = 0; - } - - /* use proportional triangles to project new coords */ - project_x2 = project_focalx * plane / view_plane; - project_y2 = project_focaly * plane / view_plane; - - /* quadratic regression (rough) */ - if (project_focaly >= -0x0f) - py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); - else - py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); - - /* approximate # of raster lines */ - segments = ABS(project_y2 - project_y1); - - /* prevent overdraw */ - if(project_y2 >= raster) - segments = 0; - else - raster = project_y2; - - /* don't draw outside the window */ - if(project_y2 < viewport_top) - segments = 0; - - /* project new positions */ - if (segments > 0) - px_dx = ((project_x2 - project_x1) << 8) / segments; /* interpolate between projected points */ - - /* prepare output */ - DSP4.out_count = 8 + 2 + 6 * segments; - - /* pre-block data */ - DSP4_WRITE_WORD(0, project_focalx); - DSP4_WRITE_WORD(2, project_x2); - DSP4_WRITE_WORD(4, project_focaly); - DSP4_WRITE_WORD(6, project_y2); - DSP4_WRITE_WORD(8, segments); - - index = 10; - - for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ - { - /* step through the projected line */ - y_out = project_y + ((py_dy * lcv) >> 8); - x_out = project_x + ((px_dx * lcv) >> 8); - - /* data */ - DSP4_WRITE_WORD(index + 0, project_ptr); - DSP4_WRITE_WORD(index + 2, y_out); - DSP4_WRITE_WORD(index + 4, x_out); - index += 6; - - /* post-update */ - project_ptr -= 4; - } - - /* post-update */ - project_y += ((py_dy * lcv) >> 8); - project_x += ((px_dx * lcv) >> 8); - - if (segments > 0) /* new positions */ - { - project_x1 = project_x2; - project_y1 = project_y2; - - /* multi-op storage */ - multi_focaly[multi_index2++] = project_focaly; - multi_farplane[1] = plane; - multi_raster[1] = project_y1 - 1; - } - - /* update projection points */ - project_pitchy += (int8_t)DSP4.parameters[3]; - project_pitchx += (int8_t)DSP4.parameters[5]; - - project_focaly += project_pitchy; - project_focalx += project_pitchx; - } while (1); - - /* terminate op */ - DSP4.waiting4command = true; - DSP4.out_count = 0; -} - -void DSP4_Op07(void) -{ - uint16_t command; - int16_t plane; - int16_t index, lcv; - int16_t y_out, x_out; - int16_t py_dy, px_dx; - - DSP4.waiting4command = false; - - /* op flow control */ - switch (DSP4_Logic) - { - case 1: - goto resume1; - break; - case 2: - goto resume2; - break; - } - - /* sort inputs */ - - project_focaly = DSP4_READ_WORD(0x02); - raster = DSP4_READ_WORD(0x04); - viewport_top = DSP4_READ_WORD(0x06); - project_y = DSP4_READ_WORD(0x08); - viewport_bottom = DSP4_READ_WORD(0x0a); - project_x1low = DSP4_READ_WORD(0x0c); - project_x1 = DSP4_READ_WORD(0x0e); - project_centerx = DSP4_READ_WORD(0x10); - project_ptr = DSP4_READ_WORD(0x12); - - /* pre-compute */ - view_plane = PLANE_START; - - /* find projection targets */ - project_y1 = project_focaly; - project_y -= viewport_bottom; - project_x = project_centerx + project_x1; - - /* multi-op storage */ - multi_index2 = 0; - - /* command check */ - - do - { - /* scan next command */ - DSP4.in_count = 2; - DSP4_WAIT(1); - -resume1: - /* inspect input */ - command = DSP4_READ_WORD(0); - - /* check for opcode termination */ - if(command == 0x8000) - break; - - /* already have 2 bytes in queue */ - DSP4.in_index = 2; - DSP4.in_count = 12; - DSP4_WAIT(2); - - /* process one loop of projection */ - -resume2: - px_dx = 0; - - /* inspect inputs */ - plane = DSP4_READ_WORD(0); - project_y2 = DSP4_READ_WORD(2); - project_x2 = DSP4_READ_WORD(6); - - /* ignore invalid data */ - if((uint16_t) plane == 0x8001) - continue; - - /* multi-op storage */ - project_focaly = multi_focaly[multi_index2]; - - /* quadratic regression (rough) */ - if (project_focaly >= -0x0f) - py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); - else - py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); - - /* approximate # of raster lines */ - segments = ABS(project_y2 - project_y1); - - /* prevent overdraw */ - if(project_y2 >= raster) - segments = 0; - else - raster = project_y2; - - /* don't draw outside the window */ - if(project_y2 < viewport_top) - segments = 0; - - /* project new positions */ - if (segments > 0) - { - /* interpolate between projected points */ - px_dx = ((project_x2 - project_x1) << 8) / segments; - } - - /* prepare pre-output */ - DSP4.out_count = 4 + 2 + 6 * segments; - - DSP4_WRITE_WORD(0, project_x2); - DSP4_WRITE_WORD(2, project_y2); - DSP4_WRITE_WORD(4, segments); - - index = 6; - for (lcv = 0; lcv < segments; lcv++) - { - /* pre-compute */ - y_out = project_y + ((py_dy * lcv) >> 8); - x_out = project_x + ((px_dx * lcv) >> 8); - - /* data */ - DSP4_WRITE_WORD(index + 0, project_ptr); - DSP4_WRITE_WORD(index + 2, y_out); - DSP4_WRITE_WORD(index + 4, x_out); - index += 6; - - /* post-update */ - project_ptr -= 4; - } - - /* update internal variables */ - project_y += ((py_dy * lcv) >> 8); - project_x += ((px_dx * lcv) >> 8); - - /* new positions */ - if (segments > 0) - { - project_x1 = project_x2; - project_y1 = project_y2; - - /* multi-op storage */ - multi_index2++; - } - } while (1); - - DSP4.waiting4command = true; - DSP4.out_count = 0; -} - -void DSP4_Op08(void) -{ - uint16_t command; - /* used in envelope shaping */ - int16_t x1_final; - int16_t x2_final; - int16_t plane, x_left, y_left, x_right, y_right; - int16_t envelope1, envelope2; - DSP4.waiting4command = false; - - /* op flow control */ - switch (DSP4_Logic) - { - case 1: - goto resume1; - break; - case 2: - goto resume2; - break; - } - - /* process initial inputs */ - - /* clip values */ - path_clipRight[0] = DSP4_READ_WORD(0x00); - path_clipRight[1] = DSP4_READ_WORD(0x02); - path_clipRight[2] = DSP4_READ_WORD(0x04); - path_clipRight[3] = DSP4_READ_WORD(0x06); - - path_clipLeft[0] = DSP4_READ_WORD(0x08); - path_clipLeft[1] = DSP4_READ_WORD(0x0a); - path_clipLeft[2] = DSP4_READ_WORD(0x0c); - path_clipLeft[3] = DSP4_READ_WORD(0x0e); - - /* path positions */ - path_pos[0] = DSP4_READ_WORD(0x20); - path_pos[1] = DSP4_READ_WORD(0x22); - path_pos[2] = DSP4_READ_WORD(0x24); - path_pos[3] = DSP4_READ_WORD(0x26); - - /* data locations */ - path_ptr[0] = DSP4_READ_WORD(0x28); - path_ptr[1] = DSP4_READ_WORD(0x2a); - path_ptr[2] = DSP4_READ_WORD(0x2c); - path_ptr[3] = DSP4_READ_WORD(0x2e); - - /* project_y1 lines */ - path_raster[0] = DSP4_READ_WORD(0x30); - path_raster[1] = DSP4_READ_WORD(0x32); - path_raster[2] = DSP4_READ_WORD(0x34); - path_raster[3] = DSP4_READ_WORD(0x36); - - /* viewport_top */ - path_top[0] = DSP4_READ_WORD(0x38); - path_top[1] = DSP4_READ_WORD(0x3a); - path_top[2] = DSP4_READ_WORD(0x3c); - path_top[3] = DSP4_READ_WORD(0x3e); - - /* unknown (constants) */ - - view_plane = PLANE_START; - - /* command check */ - - do - { - /* scan next command */ - DSP4.in_count = 2; - DSP4_WAIT(1); - -resume1: - /* inspect input */ - command = DSP4_READ_WORD(0); - - /* terminate op */ - if(command == 0x8000) - break; - - /* already have 2 bytes in queue */ - DSP4.in_index = 2; - DSP4.in_count = 18; - DSP4_WAIT(2); - -resume2: - /* projection begins */ - - /* look at guidelines */ - plane = DSP4_READ_WORD(0x00); - x_left = DSP4_READ_WORD(0x02); - y_left = DSP4_READ_WORD(0x04); - x_right = DSP4_READ_WORD(0x06); - y_right = DSP4_READ_WORD(0x08); - - /* envelope guidelines (one frame only) */ - envelope1 = DSP4_READ_WORD(0x0a); - envelope2 = DSP4_READ_WORD(0x0c); - - /* ignore invalid data */ - if((uint16_t) plane == 0x8001) - continue; - - /* first init */ - if (plane == 0x7fff) - { - int32_t pos1, pos2; - - /* initialize projection */ - path_x[0] = x_left; - path_x[1] = x_right; - - path_y[0] = y_left; - path_y[1] = y_right; - - /* update coordinates */ - path_pos[0] -= x_left; - path_pos[1] -= x_left; - path_pos[2] -= x_right; - path_pos[3] -= x_right; - - pos1 = path_pos[0] + envelope1; - pos2 = path_pos[1] + envelope2; - - /* clip offscreen data */ - if(pos1 < path_clipLeft[0]) - pos1 = path_clipLeft[0]; - if(pos1 > path_clipRight[0]) - pos1 = path_clipRight[0]; - if(pos2 < path_clipLeft[1]) - pos2 = path_clipLeft[1]; - if(pos2 > path_clipRight[1]) - pos2 = path_clipRight[1]; - - path_plane[0] = plane; - path_plane[1] = plane; - - /* initial output */ - DSP4.out_count = 2; - DSP4.output[0] = pos1 & 0xFF; - DSP4.output[1] = pos2 & 0xFF; - } - /* proceed with projection */ - else - { - int16_t index = 0, lcv; - int16_t left_inc = 0, right_inc = 0; - int16_t dx1 = 0, dx2 = 0, dx3, dx4; - - /* # segments to traverse */ - segments = ABS(y_left - path_y[0]); - - /* prevent overdraw */ - if(y_left >= path_raster[0]) - segments = 0; - else - path_raster[0] = y_left; - - /* don't draw outside the window */ - if(path_raster[0] < path_top[0]) - segments = 0; - - /* proceed if visibility rules apply */ - if (segments > 0) - { - /* use previous data */ - dx1 = (envelope1 * path_plane[0] / view_plane); - dx2 = (envelope2 * path_plane[0] / view_plane); - - /* use temporary envelope pitch (this frame only) */ - dx3 = (envelope1 * plane / view_plane); - dx4 = (envelope2 * plane / view_plane); - - /* project new shapes (left side) */ - x1_final = x_left + dx1; - x2_final = path_x[0] + dx3; - - /* interpolate between projected points with shaping */ - left_inc = ((x2_final - x1_final) << 8) / segments; - - /* project new shapes (right side) */ - x1_final = x_left + dx2; - x2_final = path_x[0] + dx4; - - /* interpolate between projected points with shaping */ - right_inc = ((x2_final - x1_final) << 8) / segments; - path_plane[0] = plane; - } - - /* zone 1 */ - DSP4.out_count = (2 + 4 * segments); - DSP4_WRITE_WORD(index, segments); - index += 2; - - for (lcv = 1; lcv <= segments; lcv++) - { - int16_t pos1, pos2; - - /* pre-compute */ - pos1 = path_pos[0] + ((left_inc * lcv) >> 8) + dx1; - pos2 = path_pos[1] + ((right_inc * lcv) >> 8) + dx2; - - /* clip offscreen data */ - if(pos1 < path_clipLeft[0]) - pos1 = path_clipLeft[0]; - if(pos1 > path_clipRight[0]) - pos1 = path_clipRight[0]; - if(pos2 < path_clipLeft[1]) - pos2 = path_clipLeft[1]; - if(pos2 > path_clipRight[1]) - pos2 = path_clipRight[1]; - - /* data */ - DSP4_WRITE_WORD(index, path_ptr[0]); - index += 2; - DSP4.output[index++] = pos1 & 0xFF; - DSP4.output[index++] = pos2 & 0xFF; - - /* post-update */ - path_ptr[0] -= 4; - path_ptr[1] -= 4; - } - lcv--; - - if (segments > 0) - { - /* project points w/out the envelopes */ - int16_t inc = ((path_x[0] - x_left) << 8) / segments; - - /* post-store */ - path_pos[0] += ((inc * lcv) >> 8); - path_pos[1] += ((inc * lcv) >> 8); - - path_x[0] = x_left; - path_y[0] = y_left; - } - - /* zone 2 */ - segments = ABS(y_right - path_y[1]); - - /* prevent overdraw */ - if(y_right >= path_raster[2]) - segments = 0; - else path_raster[2] = y_right; - - /* don't draw outside the window */ - if(path_raster[2] < path_top[2]) - segments = 0; - - /* proceed if visibility rules apply */ - if (segments > 0) - { - /* use previous data */ - dx1 = (envelope1 * path_plane[1] / view_plane); - dx2 = (envelope2 * path_plane[1] / view_plane); - - /* use temporary envelope pitch (this frame only) */ - dx3 = (envelope1 * plane / view_plane); - dx4 = (envelope2 * plane / view_plane); - - /* project new shapes (left side) */ - x1_final = x_left + dx1; - x2_final = path_x[1] + dx3; - - /* interpolate between projected points with shaping */ - left_inc = ((x2_final - x1_final) << 8) / segments; - - /* project new shapes (right side) */ - x1_final = x_left + dx2; - x2_final = path_x[1] + dx4; - - /* interpolate between projected points with shaping */ - right_inc = ((x2_final - x1_final) << 8) / segments; - - path_plane[1] = plane; - } - - /* write out results */ - DSP4.out_count += (2 + 4 * segments); - DSP4_WRITE_WORD(index, segments); - index += 2; - - for (lcv = 1; lcv <= segments; lcv++) - { - int16_t pos1, pos2; - - /* pre-compute */ - pos1 = path_pos[2] + ((left_inc * lcv) >> 8) + dx1; - pos2 = path_pos[3] + ((right_inc * lcv) >> 8) + dx2; - - /* clip offscreen data */ - if(pos1 < path_clipLeft[2]) - pos1 = path_clipLeft[2]; - if(pos1 > path_clipRight[2]) - pos1 = path_clipRight[2]; - if(pos2 < path_clipLeft[3]) - pos2 = path_clipLeft[3]; - if(pos2 > path_clipRight[3]) - pos2 = path_clipRight[3]; - - /* data */ - DSP4_WRITE_WORD(index, path_ptr[2]); - index += 2; - DSP4.output[index++] = pos1 & 0xFF; - DSP4.output[index++] = pos2 & 0xFF; - - /* post-update */ - path_ptr[2] -= 4; - path_ptr[3] -= 4; - } - lcv--; - - if (segments > 0) - { - /* project points w/out the envelopes */ - int16_t inc = ((path_x[1] - x_right) << 8) / segments; - - /* post-store */ - path_pos[2] += ((inc * lcv) >> 8); - path_pos[3] += ((inc * lcv) >> 8); - - path_x[1] = x_right; - path_y[1] = y_right; - } - } - } while (1); - - DSP4.waiting4command = true; - DSP4.out_count = 2; - DSP4_WRITE_WORD(0, 0); -} - -void DSP4_Op0D(void) -{ - uint16_t command; - /* inspect inputs */ - int16_t plane; - int16_t index, lcv; - int16_t py_dy, px_dx; - int16_t y_out, x_out; - - DSP4.waiting4command = false; - - /* op flow control */ - switch (DSP4_Logic) - { - case 1: - goto resume1; - break; - case 2: - goto resume2; - break; - } - - /* process initial inputs */ - - /* sort inputs */ - project_focaly = DSP4_READ_WORD(0x02); - raster = DSP4_READ_WORD(0x04); - viewport_top = DSP4_READ_WORD(0x06); - project_y = DSP4_READ_WORD(0x08); - viewport_bottom = DSP4_READ_WORD(0x0a); - project_x1low = DSP4_READ_WORD(0x0c); - project_x1 = DSP4_READ_WORD(0x0e); - project_focalx = DSP4_READ_WORD(0x0e); - project_centerx = DSP4_READ_WORD(0x10); - project_ptr = DSP4_READ_WORD(0x12); - project_pitchylow = DSP4_READ_WORD(0x16); - project_pitchy = DSP4_READ_WORD(0x18); - project_pitchxlow = DSP4_READ_WORD(0x1a); - project_pitchx = DSP4_READ_WORD(0x1c); - far_plane = DSP4_READ_WORD(0x1e); - - /* multi-op storage */ - multi_index1++; - multi_index1 %= 4; - - /* remap 0D->09 window data ahead of time */ - /* index starts at 1-3,0 */ - /* Op0D: BL,TL,BR,TR */ - /* Op09: TL,TR,BL,BR (1,2,3,0) */ - switch (multi_index1) - { - case 1: - multi_index2 = 3; - break; - case 2: - multi_index2 = 1; - break; - case 3: - multi_index2 = 0; - break; - case 0: - multi_index2 = 2; - break; - } - - /* pre-compute */ - view_plane = PLANE_START; - - /* figure out projection data */ - project_y -= viewport_bottom; - project_x = project_centerx + project_x1; - - /* command check */ - - do - { - /* scan next command */ - DSP4.in_count = 2; - DSP4_WAIT(1); - -resume1: - /* inspect input */ - command = DSP4_READ_WORD(0); - - /* terminate op */ - if(command == 0x8000) - break; - - /* already have 2 bytes in queue */ - DSP4.in_index = 2; - DSP4.in_count = 8; - DSP4_WAIT(2); - - /* project section of the track */ - -resume2: - plane = DSP4_READ_WORD(0); - px_dx = 0; - - - /* ignore invalid data */ - if((uint16_t) plane == 0x8001) - continue; - - /* one-time init */ - if (far_plane) - { - /* setup final data */ - project_x1 = project_focalx; - project_y1 = project_focaly; - plane = far_plane; - far_plane = 0; - } - - /* use proportional triangles to project new coords */ - project_x2 = project_focalx * plane / view_plane; - project_y2 = project_focaly * plane / view_plane; - - /* quadratic regression (rough) */ - if (project_focaly >= -0x0f) - py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); - else - py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); - - /* approximate # of raster lines */ - segments = ABS(project_y2 - project_y1); - - /* prevent overdraw */ - if(project_y2 >= raster) - segments = 0; - else - raster = project_y2; - - /* don't draw outside the window */ - if(project_y2 < viewport_top) - segments = 0; - - /* project new positions */ - if (segments > 0) - { - /* interpolate between projected points */ - px_dx = ((project_x2 - project_x1) << 8) / segments; - } - - /* prepare output */ - DSP4.out_count = 8 + 2 + 6 * segments; - DSP4_WRITE_WORD(0, project_focalx); - DSP4_WRITE_WORD(2, project_x2); - DSP4_WRITE_WORD(4, project_focaly); - DSP4_WRITE_WORD(6, project_y2); - DSP4_WRITE_WORD(8, segments); - index = 10; - - for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ - { - /* step through the projected line */ - y_out = project_y + ((py_dy * lcv) >> 8); - x_out = project_x + ((px_dx * lcv) >> 8); - - /* data */ - DSP4_WRITE_WORD(index + 0, project_ptr); - DSP4_WRITE_WORD(index + 2, y_out); - DSP4_WRITE_WORD(index + 4, x_out); - index += 6; - - /* post-update */ - project_ptr -= 4; - } - - /* post-update */ - project_y += ((py_dy * lcv) >> 8); - project_x += ((px_dx * lcv) >> 8); - - if (segments > 0) - { - project_x1 = project_x2; - project_y1 = project_y2; - - /* multi-op storage */ - multi_farplane[multi_index2] = plane; - multi_raster[multi_index2] = project_y1; - } - - /* update focal projection points */ - project_pitchy += (int8_t)DSP4.parameters[3]; - project_pitchx += (int8_t)DSP4.parameters[5]; - - project_focaly += project_pitchy; - project_focalx += project_pitchx; - } while (1); - - DSP4.waiting4command = true; - DSP4.out_count = 0; -} - -void DSP4_Op09(void) -{ - uint16_t command; - bool clip; - int16_t sp_x, sp_y, sp_oam, sp_msb; - int16_t sp_dx, sp_dy; - - DSP4.waiting4command = false; - - /* op flow control */ - switch (DSP4_Logic) - { - case 1: - goto resume1; - break; - case 2: - goto resume2; - break; - case 3: - goto resume3; - break; - case 4: - goto resume4; - break; - case 5: - goto resume5; - break; - case 6: - goto resume6; - break; - case 7: - goto resume7; - break; - } - - /* process initial inputs */ - - /* grab screen information */ - view_plane = PLANE_START; - center_x = DSP4_READ_WORD(0x00); - center_y = DSP4_READ_WORD(0x02); - viewport_left = DSP4_READ_WORD(0x06); - viewport_right = DSP4_READ_WORD(0x08); - viewport_top = DSP4_READ_WORD(0x0a); - viewport_bottom = DSP4_READ_WORD(0x0c); - - /* expand viewport dimensions */ - viewport_left -= 8; - - /* cycle through viewport window data */ - multi_index1++; - multi_index1 %= 4; - - /* convert track line to the window region */ - project_y2 = center_y + multi_raster[multi_index1] * (viewport_bottom - center_y) / (0x33 - 0); - if (!op09_mode) - project_y2 -= 2; - - goto no_sprite; - - do - { - /* check for new sprites */ - do - { - uint16_t second; - - DSP4.in_count = 4; - DSP4.in_index = 2; - DSP4_WAIT(1); - -resume1: - /* try to classify sprite */ - second = DSP4_READ_WORD(2); - - /* op termination */ - if(second == 0x8000) - goto terminate; - - second >>= 8; - sprite_type = 0; - - /* vehicle sprite */ - if (second == 0x90) - { - sprite_type = 1; - break; - } - /* terrain sprite */ - else if (second != 0) - { - sprite_type = 2; - break; - } - -no_sprite: - /* no sprite. try again */ - DSP4.in_count = 2; - DSP4_WAIT(2); - -resume2:; - } while (1); - - /* process projection information */ - -sprite_found: - /* vehicle sprite */ - if (sprite_type == 1) - { - int16_t plane; - int16_t car_left, car_right; - int16_t focal_back; - int32_t height; - - /* we already have 4 bytes we want */ - DSP4.in_count = 6 + 12; - DSP4.in_index = 4; - DSP4_WAIT(3); - -resume3: - /* filter inputs */ - project_y1 = DSP4_READ_WORD(0x00); - focal_back = DSP4_READ_WORD(0x06); - car_left = DSP4_READ_WORD(0x0c); - plane = DSP4_READ_WORD(0x0e); - car_right = DSP4_READ_WORD(0x10); - - /* calculate car's x-center */ - project_focalx = car_right - car_left; - - /* determine how far into the screen to project */ - project_focaly = focal_back; - project_x = project_focalx * plane / view_plane; - segments = 0x33 - project_focaly * plane / view_plane; - far_plane = plane; - - /* prepare memory */ - sprite_x = center_x + project_x; - sprite_y = viewport_bottom - segments; - far_plane = plane; - - /* make the car's x-center available */ - DSP4.out_count = 2; - DSP4_WRITE_WORD(0, project_focalx); - - /* grab a few remaining vehicle values */ - DSP4.in_count = 4; - - DSP4_WAIT(4); - -resume4: /* store final values */ - height = DSP4_READ_WORD(0); - sprite_offset = DSP4_READ_WORD(2); - - /* vertical lift factor */ - sprite_y += height; - } - else if (sprite_type == 2) /* terrain sprite */ - { - int16_t plane; - - /* we already have 4 bytes we want */ - DSP4.in_count = 6 + 6 + 2; - DSP4.in_index = 4; - DSP4_WAIT(5); - -resume5: - /* sort loop inputs */ - project_y1 = DSP4_READ_WORD(0x00); - plane = DSP4_READ_WORD(0x02); - project_centerx = DSP4_READ_WORD(0x04); - project_focalx = DSP4_READ_WORD(0x08); - project_focaly = DSP4_READ_WORD(0x0a); - sprite_offset = DSP4_READ_WORD(0x0c); - - /* determine distances into virtual world */ - segments = 0x33 - project_y1; - project_x = project_focalx * plane / view_plane; - project_y = project_focaly * plane / view_plane; - - /* prepare memory */ - sprite_x = center_x + project_x - project_centerx; - sprite_y = viewport_bottom - segments + project_y; - far_plane = plane; - } - - /* default sprite size: 16x16 */ - sprite_size = true; - - /* convert tile data to OAM */ - - do - { - DSP4.in_count = 2; - DSP4_WAIT(6); - -resume6: - command = DSP4_READ_WORD(0); - - /* opcode termination */ - if(command == 0x8000) - goto terminate; - - /* toggle sprite size */ - if (command == 0x0000) - { - sprite_size = !sprite_size; - continue; - } - - /* new sprite information */ - command >>= 8; - if (command != 0x20 && command != 0x40 && command != 0x60 && command != 0xa0 && command != 0xc0 && command != 0xe0) - break; - - DSP4.in_count = 6; - DSP4.in_index = 2; - DSP4_WAIT(7); - - /* process tile data */ - -resume7: - /* sprite deltas */ - sp_dy = DSP4_READ_WORD(2); - sp_dx = DSP4_READ_WORD(4); - - /* update coordinates */ - sp_y = sprite_y + sp_dy; - sp_x = sprite_x + sp_dx; - - /* reject points outside the clipping window */ - clip = false; - if(sp_x < viewport_left || sp_x > viewport_right) - clip = true; - if(sp_y < viewport_top || sp_y > viewport_bottom) - clip = true; - - /* track depth sorting */ - if(far_plane <= multi_farplane[multi_index1] && sp_y >= project_y2) - clip = true; - - /* don't draw offscreen coordinates */ - DSP4.out_count = 0; - if (!clip) - { - int16_t out_index = 0; - int16_t offset = DSP4_READ_WORD(0); - - /* update sprite nametable/attribute information */ - sp_oam = sprite_offset + offset; - sp_msb = (sp_x < 0 || sp_x > 255); - - /* emit transparency information */ - if((sprite_offset & 0x08) && ((sprite_type == 1 && sp_y >= 0xcc) || (sprite_type == 2 && sp_y >= 0xbb))) - { - DSP4.out_count = 6; - - /* one block of OAM data */ - DSP4_WRITE_WORD(0, 1); - - /* OAM: x,y,tile,no attr */ - DSP4.output[2] = sp_x & 0xFF; - DSP4.output[3] = (sp_y + 6) & 0xFF; - DSP4_WRITE_WORD(4, 0xEE); - out_index = 6; - - /* OAM: size,msb data */ - DSP4_Op06(sprite_size, (int8_t) sp_msb); - } - - /* normal data */ - DSP4.out_count += 8; - - /* one block of OAM data */ - DSP4_WRITE_WORD(out_index + 0, 1); - - /* OAM: x,y,tile,attr */ - DSP4.output[out_index + 2] = sp_x & 0xFF; - DSP4.output[out_index + 3] = sp_y & 0xFF; - DSP4_WRITE_WORD(out_index + 4, sp_oam); - - /* no following OAM data */ - DSP4_WRITE_WORD(out_index + 6, 0); - - /* OAM: size,msb data */ - DSP4_Op06(sprite_size, (int8_t) sp_msb); - } - - /* no sprite information */ - if (DSP4.out_count == 0) - { - DSP4.out_count = 2; - DSP4_WRITE_WORD(0, 0); - } - } while (1); - - /* special cases: plane == 0x0000 */ - - /* special vehicle case */ - if (command == 0x90) - { - sprite_type = 1; - - /* shift bytes */ - DSP4.parameters[2] = DSP4.parameters[0]; - DSP4.parameters[3] = DSP4.parameters[1]; - DSP4.parameters[0] = 0; - DSP4.parameters[1] = 0; - - goto sprite_found; - } - else if (command != 0x00 && command != 0xff) /* special terrain case */ - { - sprite_type = 2; - - /* shift bytes */ - DSP4.parameters[2] = DSP4.parameters[0]; - DSP4.parameters[3] = DSP4.parameters[1]; - DSP4.parameters[0] = 0; - DSP4.parameters[1] = 0; - - goto sprite_found; - } - } while (1); - -terminate: - DSP4.waiting4command = true; - DSP4.out_count = 0; -} diff --git a/source/dsp4emu.h b/source/dsp4emu.h new file mode 100644 index 0000000..da6e80f --- /dev/null +++ b/source/dsp4emu.h @@ -0,0 +1,1227 @@ +#include "../copyright" + +#include "dsp4.h" +#include "memmap.h" + +#define DSP4_READ_WORD(x) \ + READ_WORD(DSP4.parameters+x) + +#define DSP4_WRITE_WORD(x,d) \ + WRITE_WORD(DSP4.output+x,d); + +/* used to wait for dsp i/o */ +#define DSP4_WAIT(x) \ + DSP4_Logic = x; \ + return + +int32_t DSP4_Multiply(int16_t Multiplicand, int16_t Multiplier) +{ + return Multiplicand * Multiplier; +} + +int16_t DSP4_UnknownOP11(int16_t A, int16_t B, int16_t C, int16_t D) +{ + return ((A * 0x0155 >> 2) & 0xf000) | ((B * 0x0155 >> 6) & 0x0f00) | ((C * 0x0155 >> 10) & 0x00f0) | ((D * 0x0155 >> 14) & 0x000f); +} + +void DSP4_Op06(bool size, bool msb) +{ + /* save post-oam table data for future retrieval */ + op06_OAM[op06_index] |= (msb << (op06_offset + 0)); + op06_OAM[op06_index] |= (size << (op06_offset + 1)); + op06_offset += 2; + + if (op06_offset == 8) + { + /* move to next byte in buffer */ + op06_offset = 0; + op06_index++; + } +} + +void DSP4_Op01(void) +{ + int16_t plane; + int16_t index, lcv; + int16_t py_dy, px_dx; + int16_t y_out, x_out; + uint16_t command; + DSP4.waiting4command = false; + + switch (DSP4_Logic) /* op flow control */ + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* + * process initial inputs + */ + + /* sort inputs */ + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_focalx = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + project_pitchylow = DSP4_READ_WORD(0x16); + project_pitchy = DSP4_READ_WORD(0x18); + project_pitchxlow = DSP4_READ_WORD(0x1a); + project_pitchx = DSP4_READ_WORD(0x1c); + far_plane = DSP4_READ_WORD(0x1e); + project_y1low = DSP4_READ_WORD(0x22); + + /* pre-compute */ + view_plane = PLANE_START; + + /* find starting projection points */ + project_x1 = project_focalx; + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* multi-op storage */ + multi_index1 = 0; + multi_index2 = 0; + + /* + * command check + */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* check for termination */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 8; + DSP4_WAIT(2); + + /* process one iteration of projection */ + + /* inspect inputs */ + +resume2: + plane = DSP4_READ_WORD(0); + px_dx = 0; + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* one-time init */ + if (far_plane) + { + /* setup final parameters */ + project_focalx += plane; + project_x1 = project_focalx; + project_y1 = project_focaly; + plane = far_plane; + far_plane = 0; + } + + /* use proportional triangles to project new coords */ + project_x2 = project_focalx * plane / view_plane; + project_y2 = project_focaly * plane / view_plane; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + px_dx = ((project_x2 - project_x1) << 8) / segments; /* interpolate between projected points */ + + /* prepare output */ + DSP4.out_count = 8 + 2 + 6 * segments; + + /* pre-block data */ + DSP4_WRITE_WORD(0, project_focalx); + DSP4_WRITE_WORD(2, project_x2); + DSP4_WRITE_WORD(4, project_focaly); + DSP4_WRITE_WORD(6, project_y2); + DSP4_WRITE_WORD(8, segments); + + index = 10; + + for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ + { + /* step through the projected line */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* post-update */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + if (segments > 0) /* new positions */ + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_focaly[multi_index2++] = project_focaly; + multi_farplane[1] = plane; + multi_raster[1] = project_y1 - 1; + } + + /* update projection points */ + project_pitchy += (int8_t)DSP4.parameters[3]; + project_pitchx += (int8_t)DSP4.parameters[5]; + + project_focaly += project_pitchy; + project_focalx += project_pitchx; + } while (1); + + /* terminate op */ + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op07(void) +{ + uint16_t command; + int16_t plane; + int16_t index, lcv; + int16_t y_out, x_out; + int16_t py_dy, px_dx; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* sort inputs */ + + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_x1 = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + + /* pre-compute */ + view_plane = PLANE_START; + + /* find projection targets */ + project_y1 = project_focaly; + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* multi-op storage */ + multi_index2 = 0; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* check for opcode termination */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 12; + DSP4_WAIT(2); + + /* process one loop of projection */ + +resume2: + px_dx = 0; + + /* inspect inputs */ + plane = DSP4_READ_WORD(0); + project_y2 = DSP4_READ_WORD(2); + project_x2 = DSP4_READ_WORD(6); + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* multi-op storage */ + project_focaly = multi_focaly[multi_index2]; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + { + /* interpolate between projected points */ + px_dx = ((project_x2 - project_x1) << 8) / segments; + } + + /* prepare pre-output */ + DSP4.out_count = 4 + 2 + 6 * segments; + + DSP4_WRITE_WORD(0, project_x2); + DSP4_WRITE_WORD(2, project_y2); + DSP4_WRITE_WORD(4, segments); + + index = 6; + for (lcv = 0; lcv < segments; lcv++) + { + /* pre-compute */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* update internal variables */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + /* new positions */ + if (segments > 0) + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_index2++; + } + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op08(void) +{ + uint16_t command; + /* used in envelope shaping */ + int16_t x1_final; + int16_t x2_final; + int16_t plane, x_left, y_left, x_right, y_right; + int16_t envelope1, envelope2; + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* process initial inputs */ + + /* clip values */ + path_clipRight[0] = DSP4_READ_WORD(0x00); + path_clipRight[1] = DSP4_READ_WORD(0x02); + path_clipRight[2] = DSP4_READ_WORD(0x04); + path_clipRight[3] = DSP4_READ_WORD(0x06); + + path_clipLeft[0] = DSP4_READ_WORD(0x08); + path_clipLeft[1] = DSP4_READ_WORD(0x0a); + path_clipLeft[2] = DSP4_READ_WORD(0x0c); + path_clipLeft[3] = DSP4_READ_WORD(0x0e); + + /* path positions */ + path_pos[0] = DSP4_READ_WORD(0x20); + path_pos[1] = DSP4_READ_WORD(0x22); + path_pos[2] = DSP4_READ_WORD(0x24); + path_pos[3] = DSP4_READ_WORD(0x26); + + /* data locations */ + path_ptr[0] = DSP4_READ_WORD(0x28); + path_ptr[1] = DSP4_READ_WORD(0x2a); + path_ptr[2] = DSP4_READ_WORD(0x2c); + path_ptr[3] = DSP4_READ_WORD(0x2e); + + /* project_y1 lines */ + path_raster[0] = DSP4_READ_WORD(0x30); + path_raster[1] = DSP4_READ_WORD(0x32); + path_raster[2] = DSP4_READ_WORD(0x34); + path_raster[3] = DSP4_READ_WORD(0x36); + + /* viewport_top */ + path_top[0] = DSP4_READ_WORD(0x38); + path_top[1] = DSP4_READ_WORD(0x3a); + path_top[2] = DSP4_READ_WORD(0x3c); + path_top[3] = DSP4_READ_WORD(0x3e); + + /* unknown (constants) */ + + view_plane = PLANE_START; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* terminate op */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 18; + DSP4_WAIT(2); + +resume2: + /* projection begins */ + + /* look at guidelines */ + plane = DSP4_READ_WORD(0x00); + x_left = DSP4_READ_WORD(0x02); + y_left = DSP4_READ_WORD(0x04); + x_right = DSP4_READ_WORD(0x06); + y_right = DSP4_READ_WORD(0x08); + + /* envelope guidelines (one frame only) */ + envelope1 = DSP4_READ_WORD(0x0a); + envelope2 = DSP4_READ_WORD(0x0c); + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* first init */ + if (plane == 0x7fff) + { + int32_t pos1, pos2; + + /* initialize projection */ + path_x[0] = x_left; + path_x[1] = x_right; + + path_y[0] = y_left; + path_y[1] = y_right; + + /* update coordinates */ + path_pos[0] -= x_left; + path_pos[1] -= x_left; + path_pos[2] -= x_right; + path_pos[3] -= x_right; + + pos1 = path_pos[0] + envelope1; + pos2 = path_pos[1] + envelope2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[0]) + pos1 = path_clipLeft[0]; + if(pos1 > path_clipRight[0]) + pos1 = path_clipRight[0]; + if(pos2 < path_clipLeft[1]) + pos2 = path_clipLeft[1]; + if(pos2 > path_clipRight[1]) + pos2 = path_clipRight[1]; + + path_plane[0] = plane; + path_plane[1] = plane; + + /* initial output */ + DSP4.out_count = 2; + DSP4.output[0] = pos1 & 0xFF; + DSP4.output[1] = pos2 & 0xFF; + } + /* proceed with projection */ + else + { + int16_t index = 0, lcv; + int16_t left_inc = 0, right_inc = 0; + int16_t dx1 = 0, dx2 = 0, dx3, dx4; + + /* # segments to traverse */ + segments = ABS(y_left - path_y[0]); + + /* prevent overdraw */ + if(y_left >= path_raster[0]) + segments = 0; + else + path_raster[0] = y_left; + + /* don't draw outside the window */ + if(path_raster[0] < path_top[0]) + segments = 0; + + /* proceed if visibility rules apply */ + if (segments > 0) + { + /* use previous data */ + dx1 = (envelope1 * path_plane[0] / view_plane); + dx2 = (envelope2 * path_plane[0] / view_plane); + + /* use temporary envelope pitch (this frame only) */ + dx3 = (envelope1 * plane / view_plane); + dx4 = (envelope2 * plane / view_plane); + + /* project new shapes (left side) */ + x1_final = x_left + dx1; + x2_final = path_x[0] + dx3; + + /* interpolate between projected points with shaping */ + left_inc = ((x2_final - x1_final) << 8) / segments; + + /* project new shapes (right side) */ + x1_final = x_left + dx2; + x2_final = path_x[0] + dx4; + + /* interpolate between projected points with shaping */ + right_inc = ((x2_final - x1_final) << 8) / segments; + path_plane[0] = plane; + } + + /* zone 1 */ + DSP4.out_count = (2 + 4 * segments); + DSP4_WRITE_WORD(index, segments); + index += 2; + + for (lcv = 1; lcv <= segments; lcv++) + { + int16_t pos1, pos2; + + /* pre-compute */ + pos1 = path_pos[0] + ((left_inc * lcv) >> 8) + dx1; + pos2 = path_pos[1] + ((right_inc * lcv) >> 8) + dx2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[0]) + pos1 = path_clipLeft[0]; + if(pos1 > path_clipRight[0]) + pos1 = path_clipRight[0]; + if(pos2 < path_clipLeft[1]) + pos2 = path_clipLeft[1]; + if(pos2 > path_clipRight[1]) + pos2 = path_clipRight[1]; + + /* data */ + DSP4_WRITE_WORD(index, path_ptr[0]); + index += 2; + DSP4.output[index++] = pos1 & 0xFF; + DSP4.output[index++] = pos2 & 0xFF; + + /* post-update */ + path_ptr[0] -= 4; + path_ptr[1] -= 4; + } + lcv--; + + if (segments > 0) + { + /* project points w/out the envelopes */ + int16_t inc = ((path_x[0] - x_left) << 8) / segments; + + /* post-store */ + path_pos[0] += ((inc * lcv) >> 8); + path_pos[1] += ((inc * lcv) >> 8); + + path_x[0] = x_left; + path_y[0] = y_left; + } + + /* zone 2 */ + segments = ABS(y_right - path_y[1]); + + /* prevent overdraw */ + if(y_right >= path_raster[2]) + segments = 0; + else path_raster[2] = y_right; + + /* don't draw outside the window */ + if(path_raster[2] < path_top[2]) + segments = 0; + + /* proceed if visibility rules apply */ + if (segments > 0) + { + /* use previous data */ + dx1 = (envelope1 * path_plane[1] / view_plane); + dx2 = (envelope2 * path_plane[1] / view_plane); + + /* use temporary envelope pitch (this frame only) */ + dx3 = (envelope1 * plane / view_plane); + dx4 = (envelope2 * plane / view_plane); + + /* project new shapes (left side) */ + x1_final = x_left + dx1; + x2_final = path_x[1] + dx3; + + /* interpolate between projected points with shaping */ + left_inc = ((x2_final - x1_final) << 8) / segments; + + /* project new shapes (right side) */ + x1_final = x_left + dx2; + x2_final = path_x[1] + dx4; + + /* interpolate between projected points with shaping */ + right_inc = ((x2_final - x1_final) << 8) / segments; + + path_plane[1] = plane; + } + + /* write out results */ + DSP4.out_count += (2 + 4 * segments); + DSP4_WRITE_WORD(index, segments); + index += 2; + + for (lcv = 1; lcv <= segments; lcv++) + { + int16_t pos1, pos2; + + /* pre-compute */ + pos1 = path_pos[2] + ((left_inc * lcv) >> 8) + dx1; + pos2 = path_pos[3] + ((right_inc * lcv) >> 8) + dx2; + + /* clip offscreen data */ + if(pos1 < path_clipLeft[2]) + pos1 = path_clipLeft[2]; + if(pos1 > path_clipRight[2]) + pos1 = path_clipRight[2]; + if(pos2 < path_clipLeft[3]) + pos2 = path_clipLeft[3]; + if(pos2 > path_clipRight[3]) + pos2 = path_clipRight[3]; + + /* data */ + DSP4_WRITE_WORD(index, path_ptr[2]); + index += 2; + DSP4.output[index++] = pos1 & 0xFF; + DSP4.output[index++] = pos2 & 0xFF; + + /* post-update */ + path_ptr[2] -= 4; + path_ptr[3] -= 4; + } + lcv--; + + if (segments > 0) + { + /* project points w/out the envelopes */ + int16_t inc = ((path_x[1] - x_right) << 8) / segments; + + /* post-store */ + path_pos[2] += ((inc * lcv) >> 8); + path_pos[3] += ((inc * lcv) >> 8); + + path_x[1] = x_right; + path_y[1] = y_right; + } + } + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, 0); +} + +void DSP4_Op0D(void) +{ + uint16_t command; + /* inspect inputs */ + int16_t plane; + int16_t index, lcv; + int16_t py_dy, px_dx; + int16_t y_out, x_out; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + } + + /* process initial inputs */ + + /* sort inputs */ + project_focaly = DSP4_READ_WORD(0x02); + raster = DSP4_READ_WORD(0x04); + viewport_top = DSP4_READ_WORD(0x06); + project_y = DSP4_READ_WORD(0x08); + viewport_bottom = DSP4_READ_WORD(0x0a); + project_x1low = DSP4_READ_WORD(0x0c); + project_x1 = DSP4_READ_WORD(0x0e); + project_focalx = DSP4_READ_WORD(0x0e); + project_centerx = DSP4_READ_WORD(0x10); + project_ptr = DSP4_READ_WORD(0x12); + project_pitchylow = DSP4_READ_WORD(0x16); + project_pitchy = DSP4_READ_WORD(0x18); + project_pitchxlow = DSP4_READ_WORD(0x1a); + project_pitchx = DSP4_READ_WORD(0x1c); + far_plane = DSP4_READ_WORD(0x1e); + + /* multi-op storage */ + multi_index1++; + multi_index1 %= 4; + + /* remap 0D->09 window data ahead of time */ + /* index starts at 1-3,0 */ + /* Op0D: BL,TL,BR,TR */ + /* Op09: TL,TR,BL,BR (1,2,3,0) */ + switch (multi_index1) + { + case 1: + multi_index2 = 3; + break; + case 2: + multi_index2 = 1; + break; + case 3: + multi_index2 = 0; + break; + case 0: + multi_index2 = 2; + break; + } + + /* pre-compute */ + view_plane = PLANE_START; + + /* figure out projection data */ + project_y -= viewport_bottom; + project_x = project_centerx + project_x1; + + /* command check */ + + do + { + /* scan next command */ + DSP4.in_count = 2; + DSP4_WAIT(1); + +resume1: + /* inspect input */ + command = DSP4_READ_WORD(0); + + /* terminate op */ + if(command == 0x8000) + break; + + /* already have 2 bytes in queue */ + DSP4.in_index = 2; + DSP4.in_count = 8; + DSP4_WAIT(2); + + /* project section of the track */ + +resume2: + plane = DSP4_READ_WORD(0); + px_dx = 0; + + + /* ignore invalid data */ + if((uint16_t) plane == 0x8001) + continue; + + /* one-time init */ + if (far_plane) + { + /* setup final data */ + project_x1 = project_focalx; + project_y1 = project_focaly; + plane = far_plane; + far_plane = 0; + } + + /* use proportional triangles to project new coords */ + project_x2 = project_focalx * plane / view_plane; + project_y2 = project_focaly * plane / view_plane; + + /* quadratic regression (rough) */ + if (project_focaly >= -0x0f) + py_dy = (int16_t)(project_focaly * project_focaly * -0.20533553 - 1.08330005 * project_focaly - 69.61094639); + else + py_dy = (int16_t)(project_focaly * project_focaly * -0.000657035759 - 1.07629051 * project_focaly - 65.69315963); + + /* approximate # of raster lines */ + segments = ABS(project_y2 - project_y1); + + /* prevent overdraw */ + if(project_y2 >= raster) + segments = 0; + else + raster = project_y2; + + /* don't draw outside the window */ + if(project_y2 < viewport_top) + segments = 0; + + /* project new positions */ + if (segments > 0) + { + /* interpolate between projected points */ + px_dx = ((project_x2 - project_x1) << 8) / segments; + } + + /* prepare output */ + DSP4.out_count = 8 + 2 + 6 * segments; + DSP4_WRITE_WORD(0, project_focalx); + DSP4_WRITE_WORD(2, project_x2); + DSP4_WRITE_WORD(4, project_focaly); + DSP4_WRITE_WORD(6, project_y2); + DSP4_WRITE_WORD(8, segments); + index = 10; + + for (lcv = 0; lcv < segments; lcv++) /* iterate through each point */ + { + /* step through the projected line */ + y_out = project_y + ((py_dy * lcv) >> 8); + x_out = project_x + ((px_dx * lcv) >> 8); + + /* data */ + DSP4_WRITE_WORD(index + 0, project_ptr); + DSP4_WRITE_WORD(index + 2, y_out); + DSP4_WRITE_WORD(index + 4, x_out); + index += 6; + + /* post-update */ + project_ptr -= 4; + } + + /* post-update */ + project_y += ((py_dy * lcv) >> 8); + project_x += ((px_dx * lcv) >> 8); + + if (segments > 0) + { + project_x1 = project_x2; + project_y1 = project_y2; + + /* multi-op storage */ + multi_farplane[multi_index2] = plane; + multi_raster[multi_index2] = project_y1; + } + + /* update focal projection points */ + project_pitchy += (int8_t)DSP4.parameters[3]; + project_pitchx += (int8_t)DSP4.parameters[5]; + + project_focaly += project_pitchy; + project_focalx += project_pitchx; + } while (1); + + DSP4.waiting4command = true; + DSP4.out_count = 0; +} + +void DSP4_Op09(void) +{ + uint16_t command; + bool clip; + int16_t sp_x, sp_y, sp_oam, sp_msb; + int16_t sp_dx, sp_dy; + + DSP4.waiting4command = false; + + /* op flow control */ + switch (DSP4_Logic) + { + case 1: + goto resume1; + break; + case 2: + goto resume2; + break; + case 3: + goto resume3; + break; + case 4: + goto resume4; + break; + case 5: + goto resume5; + break; + case 6: + goto resume6; + break; + case 7: + goto resume7; + break; + } + + /* process initial inputs */ + + /* grab screen information */ + view_plane = PLANE_START; + center_x = DSP4_READ_WORD(0x00); + center_y = DSP4_READ_WORD(0x02); + viewport_left = DSP4_READ_WORD(0x06); + viewport_right = DSP4_READ_WORD(0x08); + viewport_top = DSP4_READ_WORD(0x0a); + viewport_bottom = DSP4_READ_WORD(0x0c); + + /* expand viewport dimensions */ + viewport_left -= 8; + + /* cycle through viewport window data */ + multi_index1++; + multi_index1 %= 4; + + /* convert track line to the window region */ + project_y2 = center_y + multi_raster[multi_index1] * (viewport_bottom - center_y) / (0x33 - 0); + if (!op09_mode) + project_y2 -= 2; + + goto no_sprite; + + do + { + /* check for new sprites */ + do + { + uint16_t second; + + DSP4.in_count = 4; + DSP4.in_index = 2; + DSP4_WAIT(1); + +resume1: + /* try to classify sprite */ + second = DSP4_READ_WORD(2); + + /* op termination */ + if(second == 0x8000) + goto terminate; + + second >>= 8; + sprite_type = 0; + + /* vehicle sprite */ + if (second == 0x90) + { + sprite_type = 1; + break; + } + /* terrain sprite */ + else if (second != 0) + { + sprite_type = 2; + break; + } + +no_sprite: + /* no sprite. try again */ + DSP4.in_count = 2; + DSP4_WAIT(2); + +resume2:; + } while (1); + + /* process projection information */ + +sprite_found: + /* vehicle sprite */ + if (sprite_type == 1) + { + int16_t plane; + int16_t car_left, car_right; + int16_t focal_back; + int32_t height; + + /* we already have 4 bytes we want */ + DSP4.in_count = 6 + 12; + DSP4.in_index = 4; + DSP4_WAIT(3); + +resume3: + /* filter inputs */ + project_y1 = DSP4_READ_WORD(0x00); + focal_back = DSP4_READ_WORD(0x06); + car_left = DSP4_READ_WORD(0x0c); + plane = DSP4_READ_WORD(0x0e); + car_right = DSP4_READ_WORD(0x10); + + /* calculate car's x-center */ + project_focalx = car_right - car_left; + + /* determine how far into the screen to project */ + project_focaly = focal_back; + project_x = project_focalx * plane / view_plane; + segments = 0x33 - project_focaly * plane / view_plane; + far_plane = plane; + + /* prepare memory */ + sprite_x = center_x + project_x; + sprite_y = viewport_bottom - segments; + far_plane = plane; + + /* make the car's x-center available */ + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, project_focalx); + + /* grab a few remaining vehicle values */ + DSP4.in_count = 4; + + DSP4_WAIT(4); + +resume4: /* store final values */ + height = DSP4_READ_WORD(0); + sprite_offset = DSP4_READ_WORD(2); + + /* vertical lift factor */ + sprite_y += height; + } + else if (sprite_type == 2) /* terrain sprite */ + { + int16_t plane; + + /* we already have 4 bytes we want */ + DSP4.in_count = 6 + 6 + 2; + DSP4.in_index = 4; + DSP4_WAIT(5); + +resume5: + /* sort loop inputs */ + project_y1 = DSP4_READ_WORD(0x00); + plane = DSP4_READ_WORD(0x02); + project_centerx = DSP4_READ_WORD(0x04); + project_focalx = DSP4_READ_WORD(0x08); + project_focaly = DSP4_READ_WORD(0x0a); + sprite_offset = DSP4_READ_WORD(0x0c); + + /* determine distances into virtual world */ + segments = 0x33 - project_y1; + project_x = project_focalx * plane / view_plane; + project_y = project_focaly * plane / view_plane; + + /* prepare memory */ + sprite_x = center_x + project_x - project_centerx; + sprite_y = viewport_bottom - segments + project_y; + far_plane = plane; + } + + /* default sprite size: 16x16 */ + sprite_size = true; + + /* convert tile data to OAM */ + + do + { + DSP4.in_count = 2; + DSP4_WAIT(6); + +resume6: + command = DSP4_READ_WORD(0); + + /* opcode termination */ + if(command == 0x8000) + goto terminate; + + /* toggle sprite size */ + if (command == 0x0000) + { + sprite_size = !sprite_size; + continue; + } + + /* new sprite information */ + command >>= 8; + if (command != 0x20 && command != 0x40 && command != 0x60 && command != 0xa0 && command != 0xc0 && command != 0xe0) + break; + + DSP4.in_count = 6; + DSP4.in_index = 2; + DSP4_WAIT(7); + + /* process tile data */ + +resume7: + /* sprite deltas */ + sp_dy = DSP4_READ_WORD(2); + sp_dx = DSP4_READ_WORD(4); + + /* update coordinates */ + sp_y = sprite_y + sp_dy; + sp_x = sprite_x + sp_dx; + + /* reject points outside the clipping window */ + clip = false; + if(sp_x < viewport_left || sp_x > viewport_right) + clip = true; + if(sp_y < viewport_top || sp_y > viewport_bottom) + clip = true; + + /* track depth sorting */ + if(far_plane <= multi_farplane[multi_index1] && sp_y >= project_y2) + clip = true; + + /* don't draw offscreen coordinates */ + DSP4.out_count = 0; + if (!clip) + { + int16_t out_index = 0; + int16_t offset = DSP4_READ_WORD(0); + + /* update sprite nametable/attribute information */ + sp_oam = sprite_offset + offset; + sp_msb = (sp_x < 0 || sp_x > 255); + + /* emit transparency information */ + if((sprite_offset & 0x08) && ((sprite_type == 1 && sp_y >= 0xcc) || (sprite_type == 2 && sp_y >= 0xbb))) + { + DSP4.out_count = 6; + + /* one block of OAM data */ + DSP4_WRITE_WORD(0, 1); + + /* OAM: x,y,tile,no attr */ + DSP4.output[2] = sp_x & 0xFF; + DSP4.output[3] = (sp_y + 6) & 0xFF; + DSP4_WRITE_WORD(4, 0xEE); + out_index = 6; + + /* OAM: size,msb data */ + DSP4_Op06(sprite_size, (int8_t) sp_msb); + } + + /* normal data */ + DSP4.out_count += 8; + + /* one block of OAM data */ + DSP4_WRITE_WORD(out_index + 0, 1); + + /* OAM: x,y,tile,attr */ + DSP4.output[out_index + 2] = sp_x & 0xFF; + DSP4.output[out_index + 3] = sp_y & 0xFF; + DSP4_WRITE_WORD(out_index + 4, sp_oam); + + /* no following OAM data */ + DSP4_WRITE_WORD(out_index + 6, 0); + + /* OAM: size,msb data */ + DSP4_Op06(sprite_size, (int8_t) sp_msb); + } + + /* no sprite information */ + if (DSP4.out_count == 0) + { + DSP4.out_count = 2; + DSP4_WRITE_WORD(0, 0); + } + } while (1); + + /* special cases: plane == 0x0000 */ + + /* special vehicle case */ + if (command == 0x90) + { + sprite_type = 1; + + /* shift bytes */ + DSP4.parameters[2] = DSP4.parameters[0]; + DSP4.parameters[3] = DSP4.parameters[1]; + DSP4.parameters[0] = 0; + DSP4.parameters[1] = 0; + + goto sprite_found; + } + else if (command != 0x00 && command != 0xff) /* special terrain case */ + { + sprite_type = 2; + + /* shift bytes */ + DSP4.parameters[2] = DSP4.parameters[0]; + DSP4.parameters[3] = DSP4.parameters[1]; + DSP4.parameters[0] = 0; + DSP4.parameters[1] = 0; + + goto sprite_found; + } + } while (1); + +terminate: + DSP4.waiting4command = true; + DSP4.out_count = 0; +} diff --git a/source/port.h b/source/port.h index fcfe836..06c5f5e 100644 --- a/source/port.h +++ b/source/port.h @@ -3,6 +3,12 @@ #ifndef _PORT_H_ #define _PORT_H_ +#include +#include +#include +#include + +#include #include #include #include @@ -62,8 +68,6 @@ void _splitpath(const char* path, char* drive, char* dir, char* fname, char* ext #define FAST_ALIGNED_LSB_WORD_ACCESS #endif -#include - #define ABS(X) ((X) < 0 ? -(X) : (X)) #define MIN(A,B) ((A) < (B) ? (A) : (B)) #define MAX(A,B) ((A) > (B) ? (A) : (B)) diff --git a/source/snes9x.h b/source/snes9x.h index ad410e1..6f6caf5 100644 --- a/source/snes9x.h +++ b/source/snes9x.h @@ -4,10 +4,11 @@ #define _SNES9X_H_ #include +#include #include #include -#include +#include #include "port.h" #include "65c816.h" diff --git a/source/srtc.c b/source/srtc.c index 0bfa7d9..3f4f257 100644 --- a/source/srtc.c +++ b/source/srtc.c @@ -371,7 +371,7 @@ void S9xSRTCPreSaveState() Memory.SRAM [s + 12 + MAX_RTC_INDEX] = (uint8_t)(rtc.system_timestamp >> 56); #else /* memmove converted: Different mallocs [Neb] */ - memcpy(&Memory.SRAM [s + 5 + MAX_RTC_INDEX], &rtc.system_timestamp, 8); + memcpy(&Memory.SRAM [s + 5 + MAX_RTC_INDEX], &rtc.system_timestamp, sizeof(time_t)); #endif } } @@ -402,7 +402,7 @@ void S9xSRTCPostLoadState() rtc.system_timestamp |= (Memory.SRAM [s + 12 + MAX_RTC_INDEX] << 56); #else /* memmove converted: Different mallocs [Neb] */ - memcpy(&rtc.system_timestamp, &Memory.SRAM [s + 5 + MAX_RTC_INDEX], 8); + memcpy(&rtc.system_timestamp, &Memory.SRAM [s + 5 + MAX_RTC_INDEX], sizeof(time_t)); #endif S9xUpdateSrtcTime(); } -- cgit v1.2.3