commit ceacc3a72c803ba6447666534c0f3efa5c0de968 Author: michniewski Date: Wed Aug 6 01:09:59 2008 +0000 Original version off of which work began. Crunchy2's last release (2.0.1b8) diff --git a/COMPILING.txt b/COMPILING.txt new file mode 100644 index 0000000..01149eb --- /dev/null +++ b/COMPILING.txt @@ -0,0 +1,6 @@ +In order to compile Snes9xGx 2.0 with actual libogc, you need to: + +1/ download last libogc source (04-02-2007) +2/ replace gu_psasm.S in /LIBBOGC directory located in root libogc source directory by the one included with this release +3/ recompile and reinstall libogc in your devkitPP environment (type 'make' then 'make install') +4/ compile snes9xgx source (type 'make' in snes9xgx folder) \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..343af2d --- /dev/null +++ b/Makefile @@ -0,0 +1,181 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xgx-crunchy2-wii +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=4 -DSMB_SVID='"Crunchewy"' \ + -DSMB_IP='"192.168.1.111"' -DGW_IP='"192.168.1.1"'\ + -DFORCE_WII=1 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..fc257ca --- /dev/null +++ b/README.txt @@ -0,0 +1,326 @@ +­———————————————————————————————————————————————————————————————————————————­ +:::::::::::::::×:::::::::::: .______ ::::::::::::::::::: _ :::::::::: +| _________ / ___°/ -------. (_)'\ / `°| +× /______ ° ---__---./ /___ _________ / --- / __| / \ °² +× _______\ \ / ___ // /____//\_____ ° /---/ / ___ --- × +| °________/ / / / // /__ _______\ \ / / \ \ / / .|| +::::::::::::::::/ /::--/_______\::.________/::::/ /:­::\ _ \::::::×::: +:::::::°:::::::/___\:::::::::::::::::::::::::::::/ /::::/__/ \--::­:::::: +°:::::::::::::::::×:::::::::::::::°::::×:::::::::\--/::::::::::::::::::×::::: +­———————————————————————————————————————————————————————————————————————•ßrK• + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· SNES9XGX v2.0.1b8 ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +******************************************************************************* +PLEASE NOTE: THIS DOCUMENT IS A WORK IN PROGRESS - IT IS INCOMPLETE AND SOME OF +THE INFORMATION IS OUT OF DATE +******************************************************************************* + +Welcome to the revolution in GameCube emulators! SNES9X is by far the most +complete and accurate Super Nintendo Entertainment System emulator to date. +Taking full power of the ATi-GX chipset and packed full of features that are +to die for after playing your games you'll never want to come back to +reality. + +SNES9X is a very popular open source emulator mainly for the PC platform, but +has seen many ports to other consoles such as the Nintendo DS, Microsoft XBOX +and now thanks to SoftDev the Nintendo GameCube! This is a straight port and +is not based on any previous SNES emulators that have existed for the +GameCube. You can get more information on SNES9X here from the below URL. +http://snes9x.ipherswipsite.com/ + +[What's New 2.0.1b8] +* Added: SD slot B options for freezes, sram and loading of roms +* Changed: SMB options no longer displayed in menus when run on a Wii +* Changed: Game auto resumes running after resetting when choosing the "Reset + Game" menu option +* Fixed (maybe): Reading of DVDs past the 1.36 GB barrier (Wii only) please + test! - svpe + +[What Was New 2.0.1b7] +* Fixed: Zip compressed freezes to memory card could become corrupted as the + file size changed - fixed this by deleting the existing file before writing + a new one if the file size increased. If the file got smaller or stayed the + same the original file is updated, using less of the existing file if the + actual file size is smaller. A check is made before deleting the existing + freeze file to ensure that there is enough space available for the new + file. Note that additional space equivalent to the new file size must be + available. If not enough space is available the original freeze is retained + and the user is informed of the lack of space. +* Fixed: If option to auto-load freeze was selected, joypad config would not + be restored since that is stored in SRAM. Resolved this for now by first + loading SRAM if any and then loading the freeze. Obviously having to have + both SRAM and freeze is not ideal, but this gets the job done if you have + enough space on your memory card, SD card, etc. +* Added prompt when returning to the menu with autosave enabled allowing the + user choose whether or not to perform the save. Press A to save or B if you + don't wish to save. +* Added optional verification of Gamecube memory card saves. After writing + the file it reads it back in and verifies that the written file matches + what was to be saved. If it doesn't or if there was a problem opening the + file it reports the problem to the user. Set this option in the preferences + if desired. +* Added Reset Gamecube/Wii menu item +* Experimental DVD support for reading beyond 1.36 GB barrier on Wii. I have + no way to test this, so please report on whether or not it works! Based on + svpe's code. + +NOTE: due to changes in the settings, this version will reset your emulator +options settings, so if you had saved preferences you will need to make your +changes to the emulator settings again and save them. + +[What Was New 2.0.1b6a] +* Fixed: Going up a directory when selecting a rom on a DVD wasn't working + +[What's Was New 2.0.1b6] +* PAL Wii support - no separate version necessary! - eke-eke +* PAL roms now play at correct speed via internal timer, ntsc roms still use + more accurate VSYNC timing - eke-eke +* Zipped freezes to memory card - take 9-12 blocks or so - based on denman's + code +* Added option for auto save and load of freezes. For saving, can do both SRAM + and Freeze if desired +* Memory card saving and loading shows a progress bar +* More miscellaneous ease-of-use improvements and cleanup +* Fixed: pressing B to get out of a rom file selection screen no longer drops + you all the way back to the main menu. Now goes back to choice of where to + load ROM (the "Load from DVD", "Load from SMB"... screen) +* Fixed: loading of joypad configuration in SRAM works again - no longer gets + messed up + +[ What Was New in 2.0.1b5] +* B button implemented in all menus (returns to previous menu) +* Fixed bug when freezing state to SD card - would crash if SD support was not + previously initialized +* Fixed double A button press needed after manual prefs/sram save to memory card +* Fixed delay after pressing A button after saving freeze to SD card +* Fixed problem of ".srm" SRAM file being created when SRAM was saved with no + ROM loaded +* Fixed version number in SRAM and preferences +* Minor other code revisions + +[ What Was New 2.0.1b1 through 2.0.1b4] +* SRAM saving and loading from snes9x on other platforms via SD card or SMB +* Games now autostart once loaded +* After manually loading SRAM the emulator is automatically reset +* Optional auto-loading of SRAM from memory card, SD or SMB after game loads +* Optional auto-saving of SRAM to memory card, SD or SMB when returning to menu +* TurboMode +* Global emulator preferences +* Menus redesigned (hopefully for the better!) +* Comes in 6 variants, each auto-loading/saving preferences/sram to a different + location: mcslota, mcslotb, sdslota, sdslotb, smb, and noload +* ROM injector works again +* A number of small improvements and bug fixes + +[ What Was New in 2.0 WIP6 ] +* Port of SNES9X 1.50 +* SMB support +* SD support +* Greatly improved emulation and timing for NTSC roms +* Save states (freezes) to SD and SMB +* Screen zoom +* Improved font and display +* ROM injector +* ... and more ... + +[ Features - OLD 1.43 LIST! ] +* Port of SNES9X v1.43 +* Fullscreen Graphics +* Sound Emulation +* SRAM Manager +* DVD Loading +* 1-4 Player Support +* Mode 7 Supported +* Super FX Supported +* SDD1, SRTC, SA-1 Supported +* DSP1 & DSP2 Supported +* Partial DSP4 Support +* Supports Hi-Res 512x224 screens +* Joliet Browser +* PAD Configuration saved with SRAM +* Memcard save/load time extended +* Partial Zip support +* Crude Timer +* Sound Sync Option +* Analog Clip +* XenoGC Support (GC-Linux Homebrew DVD Compatibility) + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· SETUP & INSTALLATION ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +Unzip the archive into a folder. You'll find 6 variations of the dol, along +with an "inject" tool for (optionally) injecting a rom into a dol. The six +variants auto save and load preferences and sram to/from different locations +as follows (you can also manually save and load SRAM to any location): + + filename preferences/sram autoloading location + ------------------------- ------------------------------------- + snes9xGx201b8-mcslota.dol Memory card in slot A + snes9xGx201b8-mcslotb.dol Memory card in slot B + snes9xGx201b8-sdslota.dol SD card in SD adapter in slot A + snes9xGx201b8-sdslotb.dol SD card in SD adapter in slot B + snes9xGx201b8-smb.dol SMB share (see SMB section below) + snes9xGx201b8-noload.dol none - doesn't load prefs nor autosave SRAM + + +Your SNES rom images must be in the Super Magicom (SMC) or FIG format. Generally, +all images you find will be in this format, but if you run across one that isn't +please download RTOOL which will allow you to convert the image into SMC format. + +You can load roms from DVD, SD card or SMB share. If you wish to use an SD card +or SMB share, you must create an SNESROMS and an SNESSAVE folder at the top +level (root) of the card or share. Put your roms in the SNESROMS folder. On DVD +you can either place your roms at the top level, or optionally you may have an +SNESROMS folder at the top level of the DVD, in which case the game selector +will default to showing that folder when first entered. If you create a bootable +DVD of Snes9xGx you can put roms on the same DVD. + +Now that you have that set up all you need to do is load the dol of your choice. +You can load it via sdload and an SD card in slot A, or by streaming it to your +cube, or by booting a bootable DVD with it on it. This document doesn't cover +how to do any of that. A good source for information on these topics is the +tehskeen forums: + + http://www.tehskeen.com/forums/ + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· PARTIAL PKZIP SUPPORT ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +The Zip support in the emulator is courtesy of the zlib library. Currently, +it supports only the Inflate method. + +The good news is that this is by far the most common zip method! + +You should note also that this implementation assumes that the first file +in each archive is the required rom in smc/fig format. + +In an attempt to save you time, we recommend using 7-Zip as the compressor, +as it gives a gain of 5-25% better compression over standard zips. + +To use 7-Zip compression on either linux or windows, use the following command: + + 7za a -tzip -mx=9 myrom.zip myrom.smc + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· MAIN MENU ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +Once the DOL file is loaded you will be presented with main menu where you can +load a rom from DVD, SD or SMB, set options for the emulator, set the joypad +configuration (on a per-game basis), save or load freezes, manage SRAM, etc. +After loading a game the game will start running immediately. If you have the +auto-load SRAM option enabled it will automatically load SRAM (if it exists) +before starting play. You can return to the main menu at any time by pressing +the c-stick (the yellow control stick) to the left, or by pressing L+R+X+Y. +Return to the game by selecting "Resume Game" or by pressing the B button until +play resumes. + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· TURBO MODE ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +TurboMode increases the playback speed of the game by about 2x. To use TurboMode +simply press the c-stick (yellow control stick) to the right and hold it right +as long as you want playback to be double-speed. Release the c-stick when you +want normal playback speed to resume. + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· IMPORTING AND EXPORTING SRAM ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +Snes9xGx 2.0.1 now includes the ability to load SRAM from Snes9x on other +platforms (Mac/PC/Linux/Etc) and to save back to those platforms. To use this +feature simply save or load SRAM to/from SD card or an SMB share. + +The only thing to be aware of is that Snes9xGx requires that the SRM file have a +name that is the rom name (not necessarily the same as the file name!) with .SRM +at the end. For example, the game "Super Mario All-Stars + World" has a rom name +of "ALL_STARS + WORLD", so the SRAM file should have the name "ALL_STARS + +WORLD.srm". You can see the rom name for a game by loading the game - the rom +name is shown in the information that is briefly shown at the bottom of the +screen. A perhaps easier way to find the correct name is simply to load the game +and then save SRAM to SD or SMB and look at the filename that Snes9xGx uses. +That's the name you should use when importing an SRAM from another platform. + +To use an Snes9xGx SRAM on another platform just do the opposite: save SRAM to +SD or SMB, and then copy that saved SRAM file to the other platform. You may +have to rename the file to be what that version of snes9x expects it to be. + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· INJECTING A ROM ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +Injecting a rom is not required to use snes9xGx, but if you primarily use +snes9xGx by streaming it to your cube you may wish to inject a rom into the dol. +In that case the game will start playing immediately once Snes9xGx loads. If you +have the auto-load SRAM option enabled it will load SRAM before starting the +game as well. + +To inject a rom you use the "inject.exe" tool on Windows or the "inject" tool on +Mac OS X. This tool works at the command line and has syntax as follows: + + inject original.dol gamerom.smc output.dol + +On the Mac you will either need to copy the inject tool into a location that is +in your "PATH" or just go into the directory that has the inject tool in it and +proceed the command with "./" like this: + + ./inject original.dol gamerom.smc output.dol + +Once you run the tool on your dol, just stream the outputted dol to your cube, +or otherwise load it and Snes9xGx will load and the game will start running. + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· WAVEBIRD WIRELESS CONTROLLER ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +This note applies to all homebrew GC software. The Wavebird wireless controller +CAN be used with homebrew, including Snes9xGx, but to enable it you must press a +button on the controller when you power up the GC and see the Gamecube logo. +This will initialize the controller and allow it to function in Snes9xGx and +other homebrew software. + +You must do this each time you power up your Gamecube. Also, if you unplug the +wireless receiver while Snes9xGx is running and plug it back in, it will not +work - you will then have to plug in a wired controller to continue play. Until +someone figures out how to properly handle the Wavebird, this will continue to +be the case. My ears are open! + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· SMB ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + +TBD + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· CREDITS ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' + + Technical Credits + + Snes9x v1.5.0/1.4.3 - Snes9x Team + GameCube Port 2.0 WIP6 and earlier - SoftDev + Additional improvements to 2.0 WIP6 - eke-eke + GameCube 2.0.1bx enhancements - crunchy2 + >1.36 GB DVD reading on Wii - svpe + GX - http://www.gc-linux.org + Font - Qoob Team + libogc - Shagkur + + + Testing + crunchy2 / tehskeen users / others + + + Documentation + original by brakken/updated by crunchy2 + + +×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ +|0O×øo· SNES9XGX v2.0.1b8 ·oø×O0| +`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨' diff --git a/gu_psasm.S b/gu_psasm.S new file mode 100644 index 0000000..b030e74 --- /dev/null +++ b/gu_psasm.S @@ -0,0 +1,694 @@ +#include + +#define A00_A01 fr0 +#define A02_A03 fr1 +#define A10_A11 fr2 +#define A12_A13 fr3 +#define A20_A21 fr4 +#define A22_A23 fr5 + +#define B00_B01 fr6 +#define B02_B03 fr7 +#define B10_B11 fr8 +#define B12_B13 fr9 +#define B20_B21 fr10 +#define B22_B23 fr11 + +#define D00_D01 fr12 +#define D02_D03 fr13 +#define D10_D11 fr14 +#define D12_D13 fr15 +#define D20_D21 fr2 +#define D22_D23 fr0 + +#define UNIT01 fr31 + +#define RET_REG fr1 +#define V1_XY fr2 +#define V1_Z fr3 +#define V2_XY fr4 +#define V2_Z fr5 +#define D1_XY fr6 +#define D1_Z fr7 +#define D2_XY fr8 +#define D2_Z fr9 +#define W1_XY fr10 +#define W1_Z fr11 +#define W2_XY fr12 +#define W2_Z fr13 + + .globl ps_guMtxConcat + //r3 = mtxA, r4 = mtxB, r5 = mtxAB +ps_guMtxConcat: + stwu r1,-64(r1) + psq_l A00_A01,0(r3),0,0 + stfd fr14,8(r1) + psq_l B00_B01,0(r4),0,0 + lis r6,Unit01@ha + psq_l B02_B03,8(r4),0,0 + stfd fr15,16(r1) + addi 6,6,Unit01@l + stfd fr31,40(r1) + psq_l B10_B11,16(r4),0,0 + ps_muls0 D00_D01,B00_B01,A00_A01 + psq_l A10_A11,16(r3),0,0 + ps_muls0 D02_D03,B02_B03,A00_A01 + psq_l UNIT01,0(r6),0,0 + ps_muls0 D10_D11,B00_B01,A10_A11 + psq_l B12_B13,24(r4),0,0 + ps_muls0 D12_D13,B02_B03,A10_A11 + psq_l A02_A03,8(r3),0,0 + ps_madds1 D00_D01,B10_B11,A00_A01,D00_D01 + psq_l A12_A13,24(r3),0,0 + ps_madds1 D10_D11,B10_B11,A10_A11,D10_D11 + psq_l B20_B21,32(r4),0,0 + ps_madds1 D02_D03,B12_B13,A00_A01,D02_D03 + psq_l B22_B23,40(r4),0,0 + ps_madds1 D12_D13,B12_B13,A10_A11,D12_D13 + psq_l A20_A21,32(r3),0,0 + psq_l A22_A23,40(r3),0,0 + ps_madds0 D00_D01,B20_B21,A02_A03,D00_D01 + ps_madds0 D02_D03,B22_B23,A02_A03,D02_D03 + ps_madds0 D10_D11,B20_B21,A12_A13,D10_D11 + ps_madds0 D12_D13,B22_B23,A12_A13,D12_D13 + psq_st D00_D01,0(r5),0,0 + ps_muls0 D20_D21,B00_B01,A20_A21 + ps_madds1 D02_D03,UNIT01,A02_A03,D02_D03 + ps_muls0 D22_D23,B02_B03,A20_A21 + psq_st D10_D11,16(r5),0,0 + ps_madds1 D12_D13,UNIT01,A12_A13,D12_D13 + psq_st D02_D03,8(r5),0,0 + ps_madds1 D20_D21,B10_B11,A20_A21,D20_D21 + ps_madds1 D22_D23,B12_B13,A20_A21,D22_D23 + ps_madds0 D20_D21,B20_B21,A22_A23,D20_D21 + lfd fr14,8(r1) + psq_st D12_D13,24(r5),0,0 + ps_madds0 D22_D23,B22_B23,A22_A23,D22_D23 + psq_st D20_D21,32(r5),0,0 + ps_madds1 D22_D23,UNIT01,A22_A23,D22_D23 + lfd fr15,16(r1) + psq_st D22_D23,40(r5),0,0 + lfd fr31,40(r1) + addi r1,r1,64 + blr + + .globl ps_guMtxIdentity + //r3 == mtx +ps_guMtxIdentity: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr0,0(r9) + lfs fr1,4(r9) + psq_st fr0,8(r3),0,0 + ps_merge01 fr2,fr0,fr1 + psq_st fr0,24(r3),0,0 + ps_merge10 fr3,fr1,fr0 + psq_st fr0,32(r3),0,0 + psq_st fr2,16(r3),0,0 + psq_st fr3,0(r3),0,0 + psq_st fr3,40(r3),0,0 + blr + + .globl ps_guMtxCopy + //r3 = src, r4 = dst +ps_guMtxCopy: + psq_l fr0,0(r3),0,0 + psq_st fr0,0(r4),0,0 + psq_l fr1,8(r3),0,0 + psq_st fr1,8(r4),0,0 + psq_l fr2,16(r3),0,0 + psq_st fr2,16(r4),0,0 + psq_l fr3,24(r3),0,0 + psq_st fr3,24(r4),0,0 + psq_l fr4,32(r3),0,0 + psq_st fr4,32(r4),0,0 + psq_l fr5,40(r3),0,0 + psq_st fr5,40(r4),0,0 + blr + + .globl ps_guMtxTranspose + //r3 = src, r4 = xpose +ps_guMtxTranspose: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr0,0(r9) + psq_l fr1,0(r3),0,0 + stfs fr0,44(r4) + psq_l fr2,16(r3),0,0 + ps_merge00 fr5,fr1,fr2 + psq_l fr3,8(r3),1,0 + ps_merge11 fr6,fr1,fr2 + psq_l fr4,24(r3),1,0 + psq_st fr5,0(r4),0,0 + psq_l fr1,32(r3),0,0 + ps_merge00 fr7,fr3,fr4 + psq_st fr6,16(r4),0,0 + ps_merge00 fr5,fr1,fr0 + psq_st fr7,32(r4),0,0 + ps_merge10 fr6,fr1,fr0 + psq_st fr5,8(r4),0,0 + lfs fr3,40(r3) + psq_st fr6,24(r4),0,0 + stfs fr3,40(r4) + blr + + .globl ps_guMtxInverse + //r3 = src, r4 = inv +ps_guMtxInverse: + psq_l fr0,0(r3),1,0 + psq_l fr1,4(r3),0,0 + psq_l fr2,16(r3),1,0 + ps_merge10 fr6,fr1,fr0 + psq_l fr3,20(r3),0,0 + psq_l fr4,32(r3),1,0 + ps_merge10 fr7,fr3,fr2 + psq_l fr5,36(r3),0,0 + ps_mul fr11,fr3,fr6 + ps_mul fr13,fr5,fr7 + ps_merge10 fr8,fr5,fr4 + ps_msub fr11,fr1,fr7,fr11 + ps_mul fr12,fr1,fr8 + ps_msub fr13,fr3,fr8,fr13 + ps_mul fr10,fr3,fr4 + ps_msub fr12,fr5,fr6,fr12 + ps_mul fr9,fr0,fr5 + ps_mul fr8,fr1,fr2 + ps_sub fr6,fr6,fr6 + ps_msub fr10,fr2,fr5,fr10 + ps_mul fr7,fr0,fr13 + ps_msub fr9,fr1,fr4,fr9 + ps_madd fr7,fr2,fr12,fr7 + ps_msub fr8,fr0,fr3,fr8 + ps_madd fr7,fr4,fr11,fr7 + ps_cmpo0 cr0,fr7,fr6 + bne 0f + li r3,0 + blr + +0: fres fr0,fr7 + ps_add fr6,fr0,fr0 + ps_mul fr5,fr0,fr0 + ps_nmsub fr0,fr7,fr5,fr6 + lfs fr1,12(r3) + ps_muls0 fr13,fr13,fr0 + lfs fr2,28(r3) + ps_muls0 fr12,fr12,fr0 + lfs fr3,44(r3) + ps_muls0 fr11,fr11,fr0 + ps_merge00 fr5,fr13,fr12 + ps_muls0 fr10,fr10,fr0 + ps_merge11 fr4,fr13,fr12 + ps_muls0 fr9,fr9,fr0 + psq_st fr5,0(r4),0,0 + ps_mul fr6,fr13,fr1 + psq_st fr4,16(r4),0,0 + ps_muls0 fr8,fr8,fr0 + ps_madd fr6,fr12,fr2,fr6 + psq_st fr10,32(r4),1,0 + ps_nmadd fr6,fr11,fr3,fr6 + psq_st fr9,36(r4),1,0 + ps_mul fr7,fr10,fr1 + ps_merge00 fr5,fr11,fr6 + psq_st fr8,40(r4),1,0 + ps_merge11 fr4,fr11,fr6 + psq_st fr5,8(r4),0,0 + ps_madd fr7,fr9,fr2,fr7 + psq_st fr4,24(r4),0,0 + ps_nmadd fr7,fr8,fr3,fr7 + li r3,1 + psq_st fr7,44(r4),1,0 + blr + + .globl ps_guMtxInvXpos + //r3 = src, r4 = invx +ps_guMtxInvXpos: + psq_l fr0, 0(r3), 1, 0 + psq_l fr1, 4(r3), 0, 0 + psq_l fr2, 16(r3), 1, 0 + ps_merge10 fr6, fr1, fr0 + psq_l fr3, 20(r3), 0, 0 + psq_l fr4, 32(r3), 1, 0 + ps_merge10 fr7, fr3, fr2 + psq_l fr5, 36(r3), 0, 0 + ps_mul fr11, fr3, fr6 + ps_merge10 fr8, fr5, fr4 + ps_mul fr13, fr5, fr7 + ps_msub fr11, fr1, fr7, fr11 + ps_mul fr12, fr1, fr8 + ps_msub fr13, fr3, fr8, fr13 + ps_msub fr12, fr5, fr6, fr12 + ps_mul fr10, fr3, fr4 + ps_mul fr9, fr0, fr5 + ps_mul fr8, fr1, fr2 + ps_msub fr10, fr2, fr5, fr10 + ps_msub fr9, fr1, fr4, fr9 + ps_msub fr8, fr0, fr3, fr8 + ps_mul fr7, fr0, fr13 + ps_sub fr1, fr1, fr1 + ps_madd fr7, fr2, fr12, fr7 + ps_madd fr7, fr4, fr11, fr7 + ps_cmpo0 cr0, fr7, fr1 + bne 0f + addi r3, 0, 0 + blr + +0: fres fr0, fr7 + psq_st fr1, 12(r4), 1, 0 + ps_add fr6, fr0, fr0 + ps_mul fr5, fr0, fr0 + psq_st fr1, 28(r4), 1, 0 + ps_nmsub fr0, fr7, fr5, fr6 + psq_st fr1, 44(r4), 1, 0 + ps_muls0 fr13, fr13, fr0 + ps_muls0 fr12, fr12, fr0 + ps_muls0 fr11, fr11, fr0 + psq_st fr13, 0(r4), 0, 0 + psq_st fr12, 16(r4), 0, 0 + ps_muls0 fr10, fr10, fr0 + ps_muls0 fr9, fr9, fr0 + psq_st fr11, 32(r4), 0, 0 + psq_st fr10, 8(r4), 1, 0 + ps_muls0 fr8, fr8, fr0 + addi r3, 0, 1 + psq_st fr9, 24(r4), 1, 0 + psq_st fr8, 40(r4), 1, 0 + blr + + .globl ps_guMtxScale + //r3 = mtx,fr1 = xS,fr2 = yS,fr3 = zS +ps_guMtxScale: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr0,0(r9) + stfs fr1,0(r3) + psq_st fr0,4(r3),0,0 + psq_st fr0,12(r3),0,0 + stfs fr2,20(r3) + psq_st fr0,24(r3),0,0 + psq_st fr0,32(r3),0,0 + stfs fr3,40(r3) + stfs fr0,44(r3) + blr + + .globl ps_guMtxScaleApply + //r3 = src,r4 = dst,fr1 = xS,fr2 = yS,fr3 = zS +ps_guMtxScaleApply: + psq_l fr4,0(r3),0,0 + psq_l fr5,8(r3),0,0 + ps_muls0 fr4,fr4,fr1 + psq_l fr6,16(r3),0,0 + ps_muls0 fr5,fr5,fr1 + psq_l fr7,24(r3),0,0 + ps_muls0 fr6,fr6,fr2 + psq_l fr8,32(r3),0,0 + psq_st fr4,0(r4),0,0 + ps_muls0 fr7,fr7,fr2 + psq_l fr2,40(r3),0,0 + psq_st fr5,8(r4),0,0 + ps_muls0 fr8,fr8,fr3 + psq_st fr6,16(r4),0,0 + ps_muls0 fr2,fr2,fr3 + psq_st fr7,24(r4),0,0 + psq_st fr8,32(r4),0,0 + psq_st fr2,40(r4),0,0 + blr + + .globl ps_guMtxTrans + //r3 = mtx,fr1 = xT,fr2 = yT,fr3 = zT +ps_guMtxTrans: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr4,0(r9) + lfs fr5,4(r9) + stfs fr1,12(r3) + stfs fr2,28(r3) + psq_st fr4,4(r3),0,0 + psq_st fr4,32(r3),0,0 + stfs fr5,20(r3) + stfs fr4,24(r3) + stfs fr5,40(r3) + stfs fr3,44(r3) + stfs fr5,0(r3) + blr + + .globl ps_guMtxTransApply + //r3 = src,r4 = dst,fr1 = xT,fr2 = yT,fr3 = zT +ps_guMtxTransApply: + psq_l fr4,0(r3),0,0 + psq_l fr5,8(r3),0,0 + psq_l fr7,24(r3),0,0 + psq_l fr8,40(r3),0,0 + ps_sum1 fr5,fr1,fr5,fr5 + psq_l fr6,16(r3),0,0 + ps_sum1 fr7,fr2,fr7,fr7 + psq_l fr9,32(r3),0,0 + ps_sum1 fr8,fr3,fr8,fr8 + psq_st fr4,0(r4),0,0 + psq_st fr5,8(r4),0,0 + psq_st fr6,16(r4),0,0 + psq_st fr7,24(r4),0,0 + psq_st fr9,32(r4),0,0 + psq_st fr8,40(r4),0,0 + blr + + .globl ps_guMtxRotTrig + //r3 = mt,r4 = axis,fr1 = sinA,fr2 = cosA +ps_guMtxRotTrig: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr3,0(r9) + lfs fr4,4(r9) + ori r4,r4,0x20 + ps_neg fr5,fr1 + cmplwi r4,'x' + beq 0f + cmplwi r4,'y' + beq 1f + cmplwi r4,'z' + beq 2f + b 3f +0: + psq_st fr4,0(r3),1,0 + psq_st fr3,4(r3),0,0 + ps_merge00 fr6,fr1,fr2 + psq_st fr3,12(r3),0,0 + ps_merge00 fr7,fr2,fr5 + psq_st fr3,28(r3),0,0 + psq_st fr3,44(r3),1,0 + psq_st fr6,36(r3),0,0 + psq_st fr7,20(r3),0,0 + b 3f +1: + ps_merge00 fr6,fr2,fr3 + ps_merge00 fr7,fr3,fr4 + psq_st fr3,24(r3),0,0 + psq_st fr6,0(r3),0,0 + ps_merge00 fr8,fr5,fr3 + ps_merge00 fr9,fr1,fr3 + psq_st fr6,40(r3),0,0 + psq_st fr7,16(r3),0,0 + psq_st fr9,8(r3),0,0 + psq_st fr8,32(r3),0,0 + b 3f +2: + psq_st fr3,8(r3),0,0 + ps_merge00 fr6,fr1,fr2 + ps_merge00 fr8,fr2,fr5 + psq_st fr3,24(r3),0,0 + psq_st fr3,32(r3),0,0 + ps_merge00 fr7,fr4,fr3 + psq_st fr6,16(r3),0,0 + psq_st fr8,0(r3),0,0 + psq_st fr7,40(r3),0,0 +3: + blr + + .globl ps_guMtxReflect + //r3 = mtx,r4 = vec1,r5 = vec2 +ps_guMtxReflect: + lis r9,Unit01@ha + addi r9,r9,Unit01@l + lfs fr0,4(r9) + psq_l fr1,8(r5),1,0 + psq_l fr2,0(r5),0,0 + psq_l fr3,0(r4),0,0 + ps_nmadd fr5,fr1,fr0,fr1 + psq_l fr4,8(r4),1,0 + ps_nmadd fr6,fr2,fr0,fr2 + ps_muls0 fr7,fr2,fr5 + ps_mul fr8,fr6,fr3 + ps_muls0 fr9,fr2,fr6 + ps_sum0 fr8,fr8,fr8,fr8 + ps_muls1 fr10,fr2,fr6 + psq_st fr7,32(r3),0,0 + ps_sum0 fr2,fr2,fr2,fr0 + ps_nmadd fr8,fr5,fr4,fr8 + ps_sum1 fr10,fr0,fr10,fr10 + psq_st fr9,0(r3),0,0 + ps_muls0 fr11,fr2,fr8 + ps_merge00 fr12,fr5,fr8 + psq_st fr10,16(r3),0,0 + ps_merge00 fr13,fr7,fr11 + ps_muls0 fr12,fr12,fr1 + ps_merge11 fr11,fr7,fr11 + psq_st fr13,8(r3),0,0 + ps_sum0 fr12,fr12,fr12,fr0 + psq_st fr11,24(r3),0,0 + psq_st fr12,40(r3),0,0 + blr + + .globl ps_guVecAdd + //r3 = v1,r4 = v2,r5 = dst +ps_guVecAdd: + psq_l V1_XY,0(r3),0,0 + psq_l V2_XY,0(r4),0,0 + ps_add D1_XY,V1_XY,V2_XY + psq_st D1_XY,0(r5),0,0 + psq_l V1_Z,8(r3),1,0 + psq_l V2_Z,8(r4),1,0 + ps_add D1_Z,V1_Z,V2_Z + psq_st D1_Z,8(r5),1,0 + blr + + .globl ps_guVecSub + //r3 = v1,r4 = v2,r5 = dst +ps_guVecSub: + psq_l V1_XY,0(r3),0,0 + psq_l V2_XY,0(r4),0,0 + ps_sub D1_XY,V1_XY,V2_XY + psq_st D1_XY,0(r5),0,0 + psq_l V1_Z,8(r3),1,0 + psq_l V2_Z,8(r4),1,0 + ps_sub D1_Z,V1_Z,V2_Z + psq_st D1_Z,8(r5),1,0 + blr + + .globl ps_guVecScale + //r3 = src,r4 = dst,fr1 = S +ps_guVecScale: + psq_l fr2,0(r3),0,0 + psq_l fr3,8(r3),1,0 + ps_muls0 fr4,fr2,fr1 + psq_st fr4,0(r4),0,0 + ps_muls0 fr4,fr3,fr1 + psq_st fr4,8(r4),1,0 + blr + + .globl ps_guVecNormalize + //r3 = v +ps_guVecNormalize: + lis r9,NrmData@ha + addi r9,r9,NrmData@l + lfs fr0,0(r9) + lfs fr1,4(r9) + psq_l fr2,0(r3),0,0 + ps_mul fr4,fr2,fr2 + psq_l fr3,8(r3),1,0 + ps_madd fr5,fr3,fr3,fr4 + ps_sum0 fr6,fr5,fr3,fr4 + frsqrte fr7,fr6 + fmuls fr8,fr7,fr7 + fmuls fr9,fr7,fr0 + fnmsubs fr8,fr8,fr6,fr1 + fmuls fr7,fr8,fr9 + ps_muls0 fr2,fr2,fr7 + psq_st fr2,0(r3),0,0 + ps_muls0 fr3,fr3,fr7 + psq_st fr3,8(r3),1,0 + blr + + .globl ps_guVecCross + //r3 = v1,r4 = v2,r5 = v12 +ps_guVecCross: + psq_l fr1,0(r4),0,0 + lfs fr2,8(r3) + psq_l fr0,0(r3),0,0 + ps_merge10 fr6,fr1,fr1 + lfs fr3,8(r4) + ps_mul fr4,fr1,fr2 + ps_muls0 fr7,fr1,fr0 + ps_msub fr5,fr0,fr3,fr4 + ps_msub fr8,fr0,fr6,fr7 + ps_merge11 fr9,fr5,fr5 + ps_merge01 fr10,fr5,fr8 + psq_st fr9,0(r5),1,0 + ps_neg fr10,fr10 + psq_st fr10,4(r5),0,0 + blr + + .globl ps_guVecDotProduct + //r3 = vec1,r4 = vec2 +ps_guVecDotProduct: + psq_l fr2,4(r3),0,0 + psq_l fr3,4(r4),0,0 + ps_mul fr2,fr2,fr3 + psq_l fr5,0(r3),0,0 + psq_l fr4,0(r4),0,0 + ps_madd fr3,fr5,fr4,fr2 + ps_sum0 fr1,fr3,fr2,fr2 + blr + + .globl ps_guVecMultiply +ps_guVecMultiply: + psq_l fr0,0(r4),0,0 + psq_l fr2,0(r3),0,0 + psq_l fr1,8(r4),1,0 + ps_mul fr4,fr2,fr0 + psq_l fr3,8(r3),0,0 + ps_madd fr5,fr3,fr1,fr4 + psq_l fr8,16(r3),0,0 + ps_sum0 fr6,fr5,fr6,fr5 + psq_l fr9,24(r3),0,0 + ps_mul fr10,fr8,fr0 + psq_st fr6,0(r5),1,0 + ps_madd fr11,fr9,fr1,fr10 + psq_l fr2,32(r3),0,0 + ps_sum0 fr12,fr11,fr12,fr11 + psq_l fr3,40(r3),0,0 + ps_mul fr4,fr2,fr0 + psq_st fr12,4(r5),1,0 + ps_madd fr5,fr3,fr1,fr4 + ps_sum0 fr6,fr5,fr6,fr5 + psq_st fr6,8(r5),1,0 + blr + + .globl ps_guVecMultiplySR + // r3 = mt, r4 = src, r5 = dst +ps_guVecMultiplySR: + psq_l fr0,0(r3),0,0 // m[0][0], m[0][1] GQR0 = 0 + // fp6 - x y + psq_l fr6,0(r4),0,0 + psq_l fr2,16(r3),0,0 // m[1][0], m[1][1] + // fp8 = m00x m01y // next X + ps_mul fr8,fr0,fr6 + psq_l fr4,32(r3),0,0 // m[2][0], m[2][1] + // fp10 = m10x m11y // next Y + ps_mul fr10,fr2,fr6 + psq_l fr7,8(r4),1,0 // fp7 - z,1.0 + // fp12 = m20x m21y // next Z + ps_mul fr12,fr4,fr6 // YYY last FP6 usage + psq_l fr3,24(r3),0,0 // m[1][2], m[1][3] + ps_sum0 fr8,fr8,fr8,fr8 + psq_l fr5,40(r3),0,0 // m[2][2], m[2][3] + ps_sum0 fr10,fr10,fr10,fr10 + psq_l fr1,8(r3),0,0 // m[0][2], m[0][3] + ps_sum0 fr12,fr12,fr12,fr12 + ps_madd fr9,fr1,fr7,fr8 + psq_st fr9,0(r5),1,0 // store X + ps_madd fr11,fr3,fr7,fr10 + psq_st fr11,4(r5),1,0 // store Y + ps_madd fr13,fr5,fr7,fr12 + psq_st fr13,8(r5),1,0 // sore Z + blr + + .globl ps_guQuatAdd + //r3 = a, r4 = b, r5 = ab +ps_guQuatAdd: + psq_l fr0,0(r3),0,0 + psq_l fr1,0(r4),0,0 + ps_add fr1,fr0,fr1 + psq_st fr1,0(r5),0,0 + psq_l fr0,8(r3),0,0 + psq_l fr1,8(r4),0,0 + ps_add fr1,fr0,fr1 + psq_st fr1,8(r5),0,0 + blr + + .globl ps_guQuatSub + //r3 = a, r4 = b, r5 = ab +ps_guQuatSub: + psq_l fr0,0(r3),0,0 + psq_l fr1,0(r4),0,0 + ps_sub fr1,fr0,fr1 + psq_st fr1,0(r5),0,0 + psq_l fr0,8(r3),0,0 + psq_l fr1,8(r4),0,0 + ps_sub fr1,fr0,fr1 + psq_st fr1,8(r5),0,0 + blr + + .globl ps_guQuatMultiply + //r3 = a, r4 = b, r5 = ab +ps_guQuatMultiply: + psq_l fr0,0(r3),0,0 + psq_l fr1,8(r3),0,0 + psq_l fr2,0(r4),0,0 + ps_neg fr4,fr0 + psq_l fr3,8(r4),0,0 + ps_neg fr5,fr1 + ps_merge01 fr6,fr4,fr0 + ps_muls0 fr8,fr1,fr2 + ps_muls0 fr9,fr4,fr2 + ps_merge01 fr7,fr5,fr1 + ps_muls1 fr11,fr6,fr2 + ps_madds0 fr8,fr6,fr3,fr8 + ps_muls1 fr10,fr7,fr2 + ps_madds0 fr9,fr7,fr3,fr9 + ps_madds1 fr11,fr5,fr3,fr11 + ps_merge10 fr8,fr8,fr8 + ps_madds1 fr10,fr0,fr3,fr10 + ps_merge10 fr9,fr9,fr9 + ps_add fr8,fr8,fr8 + psq_st fr8,0(r5),0,0 + ps_sub fr9,fr9,fr9 + psq_st fr9,8(r5),0,0 + blr + + .globl ps_quQuatScale + //r3 = q,r4 = r, fr1 = scale +ps_guQuatScale: + psq_l fr4,0(r3),0,0 + psq_l fr5,8(r3),0,0 + ps_muls0 fr4,fr4,fr1 + psq_st fr4,0(r4),0,0 + ps_muls0 fr5,fr5,fr1 + psq_st fr5,8(r4),0,0 + blr + + .globl ps_guQuatDotProduct + //r3 = p, r4 = q ; fr1 = res +ps_guQuatDotProduct: + psq_l fr2,0(r3),0,0 + psq_l fr4,0(r4),0,0 + ps_mul fr1,fr2,fr4 + psq_l fr3,8(r3),0,0 + psq_l fr5,8(r4),0,0 + ps_madd fr1,fr3,fr5,fr1 + ps_sum0 fr1,fr1,fr1,fr1 + blr + + .globl ps_guQuatNormalize + //r3 = src, r4 = unit +ps_guQuatNormalize: + lis r9,NrmData@ha + addi r9,r9,NrmData@l + lfs fr9,0(r9) + lfs fr10,4(r9) + lis r9,QuatEpsilon@ha + lfs fr8,QuatEpsilon@l(r9) + psq_l fr0,0(r3),0,0 + ps_mul fr2,fr0,fr0 + psq_l fr1,8(r3),0,0 + ps_sub fr5,fr8,fr8 + ps_madd fr2,fr2,fr2,fr2 + frsqrte fr3,fr2 + ps_sub fr4,fr2,fr8 + fmul fr6,fr3,fr3 + fmul fr7,fr3,fr9 + fnmsub fr6,fr6,fr2,fr10 + fmul fr3,fr6,fr7 + ps_sel fr3,fr4,fr3,fr5 + ps_muls0 fr0,fr0,fr3 + ps_muls0 fr1,fr1,fr3 + psq_st fr0,0(r4),0,0 + psq_st fr1,8(r4),0,0 + blr + + .section .data + .balign 4 +QuatEpsilon: + .float 0.00001 +Unit01: + .float 0.0, 1.0 +NrmData: + .float 0.5, 3.0 diff --git a/inject/Makefile b/inject/Makefile new file mode 100644 index 0000000..141d2bd --- /dev/null +++ b/inject/Makefile @@ -0,0 +1,4 @@ +inject.exe : inject.c + @gcc -O2 -Wall inject.c -o inject.exe + @strip inject.exe + diff --git a/inject/inject.c b/inject/inject.c new file mode 100644 index 0000000..a2c89fc --- /dev/null +++ b/inject/inject.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * Snes9x-GX 2.0 + * + * Developer ROM injector. + * + * You should set ROMOFFSET to match aram.cpp, as this will change as the + * binary expands and/or contracts. + ****************************************************************************/ +#include +#include +#include + +#define DOLHEADERLENGTH 256 // GC DOL Header Length +#define MAXTEXT 7 // Maximum 7 Text Sections +#define MAXDATA 11 // Maximum 11 Data Sections + +struct DOLHEADER{ + unsigned int textOffsets[MAXTEXT]; + unsigned int dataOffsets[MAXDATA]; + + unsigned int textAddress[MAXTEXT]; + unsigned int dataAddress[MAXDATA]; + + unsigned int textLength[MAXTEXT]; + unsigned int dataLength[MAXDATA]; + + unsigned int bssAddress; + unsigned int bssLength; + + unsigned int entryPoint; + unsigned int unused[MAXTEXT]; +} dolheader; + +unsigned int FLIP32(unsigned int b) +{ + unsigned int c; + + c = ( b & 0xff000000 ) >> 24; + c |= ( b & 0xff0000 ) >> 8; + c |= ( b & 0xff00 ) << 8; + c |= ( b & 0xff ) << 24; + + return c; +} + +#define ROMOFFSET 0x81000000 + +int main( int argc, char *argv[] ) +{ + FILE *infile, *outfile; + char *dol; + char *rom; + int dollen, romlen, outlen; + char *sig = "SNESROM0"; + + if ( argc != 4 ) + { + printf("Usage : %s snes9xGx201.dol snesrom.smc output.dol\n", argv[0]); + return 1; + } + + /*** Try to open all three handles ***/ + infile = fopen(argv[1], "rb"); + if ( infile == NULL ) + { + printf("Unable to open %s for reading\n", argv[1]); + return 1; + } + + /*** Allocate and load ***/ + fseek(infile, 0, SEEK_END); + dollen=ftell(infile); + fseek(infile, 0, SEEK_SET); + + dol = calloc(sizeof(char), dollen + 32); + + if ( fread(dol, 1, dollen, infile ) != dollen ) + { + free(dol); + printf("Error reading %s\n", argv[1]); + fclose(infile); + return 1; + } + + fclose(infile); + + infile = fopen(argv[2], "rb"); + if ( infile == NULL ) + { + printf("Unable to open %s for reading\n", argv[2]); + free(dol); + return 1; + } + + /*** Allocate and load ***/ + fseek( infile, 0, SEEK_END); + romlen = ftell(infile); + fseek( infile, 0, SEEK_SET); + rom = calloc( sizeof(char), romlen + 48 ); + + if ( fread(rom, 1, romlen, infile) != romlen ) + { + printf("Error reading %s\n", argv[2]); + fclose(infile); + free(rom); + free(dol); + return 1; + } + + fclose(infile); + + /*** Ok, now have both in memory - so update the dol header and get this file done -;) ***/ + memcpy(&dolheader, dol, DOLHEADERLENGTH); + + /*** Align to 32 bytes - no real reason, I just like it -;) ***/ + if ( dollen & 0x1f ) + dollen = ( dollen & ~0x1f ) + 0x20; + + dolheader.dataOffsets[1] = FLIP32(dollen); + dolheader.dataAddress[1] = FLIP32(ROMOFFSET); + dolheader.dataLength[1] = FLIP32(romlen + 32); + + /*** Move the updated header back ***/ + memcpy(dol, &dolheader, DOLHEADERLENGTH); + + outfile = fopen(argv[3], "wb"); + if ( outfile == NULL ) + { + printf("Unable to open %s for writing!\n", argv[3]); + free(rom); + free(dol); + } + + /*** Now simply update the files ***/ + fwrite(dol, 1, dollen, outfile); + fwrite(sig, 1, 8, outfile); + + outlen = FLIP32(romlen); + fwrite(&outlen, 1, 4, outfile); + + char align[32]; + memset(align, 0, 32); + fwrite(align, 1, 20, outfile); + fwrite(rom, 1, romlen, outfile); + fclose(outfile); + + free(dol); + free(rom); + + printf("Output file %s created successfully\n", argv[3]); + + return 0; +} + diff --git a/inject/make-inject b/inject/make-inject new file mode 100644 index 0000000..4c82ecd --- /dev/null +++ b/inject/make-inject @@ -0,0 +1,10 @@ +#!/bin/bash + +#OS="macosx" +OS="win32" +#OS="linux" + +echo Compiling inject.c for ${OS}... +cp makefiles/Makefile-inject-${OS} Makefile +make +echo \ No newline at end of file diff --git a/inject/makefiles/Makefile-inject-linux b/inject/makefiles/Makefile-inject-linux new file mode 100644 index 0000000..d55da10 --- /dev/null +++ b/inject/makefiles/Makefile-inject-linux @@ -0,0 +1,4 @@ +inject.exe : inject.c + @gcc -O2 -Wall inject.c -o inject + @strip inject + diff --git a/inject/makefiles/Makefile-inject-macosx b/inject/makefiles/Makefile-inject-macosx new file mode 100644 index 0000000..f1a75a8 --- /dev/null +++ b/inject/makefiles/Makefile-inject-macosx @@ -0,0 +1,4 @@ +inject.exe : inject.c + @gcc -O2 -arch i386 -arch ppc -Wall inject.c -o inject + @strip inject + diff --git a/inject/makefiles/Makefile-inject-win32 b/inject/makefiles/Makefile-inject-win32 new file mode 100644 index 0000000..141d2bd --- /dev/null +++ b/inject/makefiles/Makefile-inject-win32 @@ -0,0 +1,4 @@ +inject.exe : inject.c + @gcc -O2 -Wall inject.c -o inject.exe + @strip inject.exe + diff --git a/makeall b/makeall new file mode 100644 index 0000000..a392821 --- /dev/null +++ b/makeall @@ -0,0 +1,25 @@ +#!/bin/bash + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-mcslota Makefile +make + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-sdslota Makefile +make + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-sdslotb Makefile +make + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-smb Makefile +make + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-noload Makefile +make + +touch source/ngc/snes9xGX.h +cp makefiles/Makefile-mcslotb Makefile +make \ No newline at end of file diff --git a/makefiles/Makefile-mcslota b/makefiles/Makefile-mcslota new file mode 100644 index 0000000..acf8e02 --- /dev/null +++ b/makefiles/Makefile-mcslota @@ -0,0 +1,179 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-mcslota +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=0 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/makefiles/Makefile-mcslotb b/makefiles/Makefile-mcslotb new file mode 100644 index 0000000..509a98d --- /dev/null +++ b/makefiles/Makefile-mcslotb @@ -0,0 +1,179 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-mcslotb +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=1 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/makefiles/Makefile-noload b/makefiles/Makefile-noload new file mode 100644 index 0000000..db328ca --- /dev/null +++ b/makefiles/Makefile-noload @@ -0,0 +1,179 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-noload +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=-1 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/makefiles/Makefile-sdslota b/makefiles/Makefile-sdslota new file mode 100644 index 0000000..f2556ed --- /dev/null +++ b/makefiles/Makefile-sdslota @@ -0,0 +1,179 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-sdslota +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=2 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/makefiles/Makefile-sdslotb b/makefiles/Makefile-sdslotb new file mode 100644 index 0000000..1cc28c8 --- /dev/null +++ b/makefiles/Makefile-sdslotb @@ -0,0 +1,179 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-sdslotb +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=3 \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/makefiles/Makefile-smb b/makefiles/Makefile-smb new file mode 100644 index 0000000..aefe15e --- /dev/null +++ b/makefiles/Makefile-smb @@ -0,0 +1,188 @@ +#--------------------------------------------------------------------------------- +# Generic makefile for Gamecube projects +# +# Tab stops set to 4 +# | | | | +# 0 1 2 3 +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := bin/snes9xGx201b8-smb +BUILD := build +SOURCES := source/snes9x source/unzip source/ngc source/smb +INCLUDES := source/snes9x source/unzip source/ngc source/smb + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \ + -DNGC -DNO_ASM -DCPU_SHUTDOWN -DSPC700C \ + -DSPC700_SHUTDOWN -DNEW_COLOUR_BLENDING \ + -DNO_INLINE_GET_SET -DSDD1_DECOMP -DCORRECT_VRAM_READS \ + -DDETECT_NASTY_FX_INTERLEAVE -DNGC_ZOOM -DSDUSE_LFN \ + -DQUICK_SAVE_SLOT=4 \ + -DGC_IP='"192.168.1.32"' \ + -DGW_IP='"192.168.1.100"' \ + -DMASK='"255.255.255.0"' \ + -DSMB_USER='"Guest"' \ + -DSMB_PWD='"password"' \ + -DSMB_GCID='"gamecube"' \ + -DSMB_SVID='"mypc"' \ + -DSMB_SHARE='"gcshare"' \ + -DSMB_IP='"192.168.1.100"' \ + -fomit-frame-pointer -fno-exceptions -Wno-unused-parameter \ + -pipe + + +LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref + +PREFIX := powerpc-gekko- + +#export PATH:=/c/devkitPPC_r11/bin:/bin + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -logc -lm -lz -logcsys -lfreetype -lbba -lsdcard + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- +export OUTPUT := $(CURDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) *.elf + +#--------------------------------------------------------------------------------- +run: + psoload $(TARGET).dol + +#--------------------------------------------------------------------------------- +reload: + psoload -r $(TARGET).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf + @echo output ... $(notdir $@) + @$(OBJCOPY) -O binary $< $@ + +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo Compiling ... $(notdir $<) + @$(CXX) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.S + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +%.o : %.s + @echo Compiling ... $(notdir $<) + @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data +#--------------------------------------------------------------------------------- +define bin2o + cp $(<) $(*).tmp + $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ + --rename-section .data=.rodata,readonly,data,contents,alloc \ + --redefine-sym _binary_$*_tmp_start=$*\ + --redefine-sym _binary_$*_tmp_end=$*_end\ + --redefine-sym _binary_$*_tmp_size=$*_size\ + $(*).tmp $(@) + echo "extern const u8" $(*)"[];" > $(*).h + echo "extern const u32" $(*)_size[]";" >> $(*).h + rm $(*).tmp +endef + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/source/ngc/aram.cpp b/source/ngc/aram.cpp new file mode 100644 index 0000000..b79b6ac --- /dev/null +++ b/source/ngc/aram.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Audio RAM + * + * softdev July 2006 + ****************************************************************************/ +#include +#include +#include "aram.h" + +#define ARAM_READ 1 +#define ARAM_WRITE 0 + +#define TEMPSIZE 32768 +static char tempbuffer[TEMPSIZE] ATTRIBUTE_ALIGN (32); + +/** + * ARAMPut + * + * Move data from MAIN memory to ARAM + */ +void +ARAMPut (char *src, char *dst, int len) +{ + DCFlushRange (src, len); + AR_StartDMA (ARAM_WRITE, (u32) src, (u32) dst, len); + while (AR_GetDMAStatus()); +} + +/** + * ARAMFetch + * + * This function will move data from ARAM to MAIN memory + */ +void +ARAMFetch (char *dst, char *src, int len) +{ + DCInvalidateRange (dst, len); + AR_StartDMA (ARAM_READ, (u32) dst, (u32) src, len); + while (AR_GetDMAStatus ()); +} + +/** + * ARAMFetchSlow + * + * Required as SNES memory may NOT be 32-byte aligned + */ +void +ARAMFetchSlow (char *dst, char *src, int len) +{ + int t; + + if (len > TEMPSIZE) + { + t = 0; + while (t < len) + { + ARAMFetch (tempbuffer, src + t, TEMPSIZE); + + if (t + TEMPSIZE > len) + { + memcpy (dst + t, tempbuffer, len - t); + } + else + memcpy (dst + t, tempbuffer, TEMPSIZE); + + t += TEMPSIZE; + } + + } + else + { + ARAMFetch (tempbuffer, src, len); + memcpy (dst, tempbuffer, len); + } +} diff --git a/source/ngc/aram.h b/source/ngc/aram.h new file mode 100644 index 0000000..e3a7124 --- /dev/null +++ b/source/ngc/aram.h @@ -0,0 +1,19 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Audio RAM + * + * softdev July 2006 + ****************************************************************************/ +#ifndef _GCARAMI_ + +#define _GCARAMI_ + +#define AR_BACKDROP 0x8000 +#define AR_SNESROM 0x200000 + +void ARAMPut (char *src, char *dst, int len); +void ARAMFetch (char *dst, char *src, int len); +void ARAMFetchSlow (char *dst, char *src, int len); + +#endif diff --git a/source/ngc/audio.cpp b/source/ngc/audio.cpp new file mode 100644 index 0000000..3b7e34b --- /dev/null +++ b/source/ngc/audio.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Audio + * + * Audio is fixed to 32Khz/16bit/Stereo + * + * softdev July 2006 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" +#include "controls.h" + +#include "video.h" +#include "ftfont.h" + +/*** Double buffered audio ***/ +#define AUDIOBUFFER 2048 +static unsigned char soundbuffer[2][AUDIOBUFFER] + __attribute__ ((__aligned__ (32))); +static int whichab = 0; /*** Audio buffer flip switch ***/ +extern int ConfigRequested; + +#define AUDIOSTACK 16384 +lwpq_t audioqueue; +lwp_t athread; +static uint8 astack[AUDIOSTACK]; + +/** + * Audio Threading + */ +static void * +AudioThread (void *arg) +{ + LWP_InitQueue (&audioqueue); + + while (1) + { + whichab ^= 1; + if (ConfigRequested) + memset (soundbuffer[whichab], 0, AUDIOBUFFER); + else + { + so.samples_mixed_so_far = so.play_position = 0; + S9xMixSamples (soundbuffer[whichab], AUDIOBUFFER >> 1); + } + LWP_ThreadSleep (audioqueue); + } + + return NULL; +} + +/** + * MixSamples + * This continually calls S9xMixSamples On each DMA Completion + */ +static void +GCMixSamples () +{ + AUDIO_StopDMA (); + + DCFlushRange (soundbuffer[whichab], AUDIOBUFFER); + AUDIO_InitDMA ((u32) soundbuffer[whichab], AUDIOBUFFER); + AUDIO_StartDMA (); + + LWP_ThreadSignal (audioqueue); +} + +/** + * InitGCAudio + */ +void +InitGCAudio () +{ + AUDIO_SetDSPSampleRate (AI_SAMPLERATE_32KHZ); + AUDIO_RegisterDMACallback (GCMixSamples); + + LWP_CreateThread (&athread, AudioThread, NULL, astack, AUDIOSTACK, 80); +} + +/** + * AudioStart + * + * Called to kick off the Audio Queue + */ +void +AudioStart () +{ + GCMixSamples (); +} diff --git a/source/ngc/audio.h b/source/ngc/audio.h new file mode 100644 index 0000000..9054046 --- /dev/null +++ b/source/ngc/audio.h @@ -0,0 +1,12 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Audio + * + * Audio is fixed to 32Khz/16bit/Stereo + * + * softdev July 2006 + ****************************************************************************/ + +void InitGCAudio (); +void AudioStart (); diff --git a/source/ngc/dkpro.h b/source/ngc/dkpro.h new file mode 100644 index 0000000..718d401 --- /dev/null +++ b/source/ngc/dkpro.h @@ -0,0 +1,877 @@ +/******************************************************************* + * Image File : /public/dkpro.bmp + * Width : 218 + * Height : 65 + * + * This header contains a compressed Zip image. + * Use zlib1.2.3 uncompress function to restore. + *******************************************************************/ + +#define dkpro_RAW 28340 +#define dkpro_COMPRESSED 6887 +#define dkpro_WIDTH 218 +#define dkpro_HEIGHT 65 + +unsigned char dkpro[6887] = { + 0x78, 0xda, 0xed, 0x9c, 0x67, 0x70, 0x54, 0x57, 0x96, 0xc7, 0xf9, 0xb8, + 0xb5, 0x55, 0xbb, 0x55, + 0x53, 0xb5, 0xb5, 0xb3, 0x9e, 0x31, 0xc6, 0x98, 0x20, 0x31, 0xf6, 0x38, + 0x7b, 0xc6, 0x33, 0x0e, + 0xe3, 0x34, 0x60, 0x03, 0x36, 0xc9, 0x80, 0x49, 0xb6, 0x41, 0x42, 0x59, + 0x42, 0x39, 0x20, 0x75, + 0xbf, 0xd3, 0x92, 0x90, 0x84, 0x32, 0x41, 0x02, 0x11, 0xd4, 0x48, 0xe4, + 0x60, 0x72, 0x0e, 0x22, + 0x98, 0x8c, 0x8d, 0x04, 0x26, 0x83, 0x31, 0xe0, 0xec, 0x71, 0x06, 0xe7, + 0xa0, 0xfd, 0xdd, 0xdb, + 0xdd, 0xaf, 0x5f, 0xb7, 0xba, 0x07, 0x30, 0xc6, 0xf6, 0x87, 0xd6, 0xbf, + 0x1e, 0xb4, 0x6e, 0x38, + 0xf7, 0xe4, 0x7b, 0xee, 0x7b, 0x4f, 0xdd, 0x4e, 0xda, 0x5d, 0x1d, 0xaa, + 0xc3, 0x52, 0xba, 0x38, + 0x3b, 0x46, 0x75, 0x70, 0xb6, 0x8f, 0xbd, 0xb1, 0xfe, 0xc6, 0xf8, 0x3f, + 0x3a, 0x6f, 0x8c, 0x6f, + 0xef, 0xbc, 0x29, 0xb6, 0xa3, 0xb3, 0x53, 0x74, 0x57, 0x67, 0xb7, 0x88, + 0x76, 0x12, 0xc2, 0x6f, + 0x06, 0x55, 0xe1, 0xd8, 0xea, 0xe6, 0xa8, 0x3f, 0x38, 0xc3, 0x62, 0xfa, + 0xd5, 0x94, 0xc4, 0x2f, + 0x28, 0xdd, 0x91, 0x71, 0x74, 0xdc, 0xf9, 0xdc, 0x0b, 0x85, 0xa7, 0x72, + 0x0f, 0x8c, 0x5f, 0x95, + 0x59, 0x37, 0x29, 0x32, 0xf1, 0xfe, 0xfa, 0x3f, 0xc4, 0xb4, 0x77, 0x76, + 0x8a, 0x09, 0x9b, 0x15, + 0xb2, 0xdd, 0xaf, 0x6f, 0xaf, 0xb0, 0x94, 0x9b, 0x89, 0xa3, 0xbe, 0x93, + 0x9d, 0x09, 0xef, 0x39, + 0x5a, 0xed, 0xad, 0x12, 0x0c, 0x3f, 0xca, 0x8e, 0xca, 0x84, 0x94, 0xdb, + 0x9d, 0xed, 0xa3, 0xba, + 0x84, 0xec, 0xf6, 0x6b, 0xda, 0x2b, 0xf5, 0x26, 0x67, 0x58, 0x74, 0xe5, + 0xf8, 0x7f, 0x65, 0x6a, + 0xab, 0x18, 0xdf, 0x49, 0x50, 0x18, 0x3f, 0xb8, 0x6c, 0x37, 0x6e, 0x5d, + 0xee, 0xd3, 0x33, 0x6e, + 0x88, 0xeb, 0xec, 0xec, 0x16, 0x19, 0xd2, 0xe0, 0x2f, 0x9f, 0x0f, 0x3b, + 0xd4, 0xdf, 0x1b, 0x35, + 0xaf, 0xa8, 0x75, 0x6c, 0x2b, 0xf6, 0xf8, 0xc6, 0xf8, 0x46, 0x3c, 0xf8, + 0x9e, 0x98, 0xf2, 0x46, + 0xd7, 0x0f, 0xf2, 0xad, 0x78, 0xfb, 0xbe, 0x33, 0x68, 0xcd, 0x3f, 0x69, + 0x1b, 0x36, 0xfd, 0xa6, + 0xd8, 0x2e, 0xd5, 0xed, 0x52, 0x43, 0x9a, 0xfc, 0x85, 0x50, 0xdd, 0x2d, + 0xa5, 0xb3, 0xb3, 0x43, + 0x74, 0x69, 0x49, 0x6b, 0x76, 0xab, 0xf1, 0xb5, 0x7c, 0xa5, 0xa1, 0x6c, + 0xe5, 0xb2, 0xd3, 0x27, + 0x72, 0x52, 0xf6, 0xcb, 0x36, 0x69, 0x92, 0x5d, 0x72, 0x48, 0xde, 0x96, + 0x1f, 0xdc, 0xd6, 0xfb, + 0x56, 0xdc, 0x63, 0x0d, 0x6c, 0x5a, 0xb0, 0x3b, 0xef, 0xfe, 0xfa, 0x9b, + 0xa2, 0xc3, 0xab, 0xda, + 0xa5, 0x84, 0x34, 0x7a, 0xfd, 0xd1, 0xcd, 0xd9, 0x61, 0x74, 0x8f, 0xca, + 0x8f, 0x53, 0x5b, 0x8d, + 0xaf, 0xe4, 0x4b, 0x8d, 0x6f, 0xb0, 0xc9, 0xb7, 0x72, 0x5c, 0xe6, 0x48, + 0x86, 0x3c, 0x2b, 0x4f, + 0x4b, 0x5f, 0xe9, 0x2f, 0x03, 0x40, 0x7f, 0xe9, 0x27, 0x7d, 0xf8, 0x3d, + 0x5a, 0x2a, 0x65, 0x27, + 0xb6, 0x6c, 0xc5, 0xae, 0xae, 0x19, 0x5f, 0x2a, 0xbb, 0x95, 0x8c, 0xcf, + 0xea, 0xe8, 0x0c, 0x8b, + 0x0a, 0x69, 0xf4, 0x7a, 0xc7, 0x58, 0x58, 0xca, 0x1f, 0xa7, 0x94, 0x24, + 0xfd, 0x68, 0xff, 0x46, + 0x2e, 0x6a, 0x7c, 0x85, 0x25, 0x3e, 0x90, 0x06, 0x19, 0x8d, 0xb5, 0x06, + 0xcb, 0x70, 0x79, 0x41, + 0x5e, 0x6c, 0x83, 0x11, 0x32, 0x84, 0xde, 0x61, 0x32, 0x4e, 0x5e, 0xd5, + 0xd6, 0xbd, 0xa4, 0x67, + 0x5e, 0x22, 0x4f, 0x1e, 0x9a, 0x78, 0x4b, 0xca, 0xef, 0x9d, 0x37, 0x24, + 0xdd, 0xe0, 0xbc, 0x21, + 0x31, 0x74, 0x5d, 0xdb, 0xd5, 0xa1, 0xaa, 0x5d, 0x7a, 0x20, 0x9b, 0x85, + 0xcd, 0xea, 0x34, 0x7a, + 0x4d, 0x61, 0x6b, 0xee, 0xe7, 0xc6, 0x67, 0xf2, 0x99, 0x7c, 0x4e, 0xdc, + 0x9c, 0x93, 0x72, 0xe2, + 0x69, 0x08, 0x96, 0x19, 0x75, 0x19, 0x8c, 0xc4, 0x76, 0x03, 0x24, 0x81, + 0xac, 0xf9, 0x9d, 0x7c, + 0x21, 0x9f, 0x69, 0x7c, 0x65, 0x04, 0xaf, 0x34, 0x43, 0xb8, 0x3a, 0xac, + 0x99, 0xdc, 0x21, 0xb9, + 0x6d, 0xdd, 0xd1, 0x35, 0xb5, 0xc3, 0xc4, 0xe6, 0x94, 0xef, 0xed, 0x9f, + 0x88, 0xc2, 0x25, 0x62, + 0xac, 0x51, 0x86, 0x62, 0x89, 0xc8, 0xab, 0xc0, 0x48, 0x79, 0x4e, 0xc6, + 0xca, 0x19, 0xec, 0xf6, + 0xa9, 0x7c, 0x12, 0xc2, 0xcf, 0x05, 0xea, 0x8a, 0x39, 0x35, 0x1d, 0x92, + 0xda, 0xc6, 0x58, 0x97, + 0xc8, 0x23, 0xf2, 0x95, 0xfd, 0x43, 0x51, 0xf8, 0x42, 0x8e, 0x92, 0x0f, + 0x87, 0x73, 0x45, 0x5d, + 0x35, 0x46, 0x92, 0x45, 0x17, 0x90, 0x1d, 0x3f, 0x96, 0x0f, 0x43, 0xf8, + 0x79, 0x60, 0x7c, 0x21, + 0x8d, 0x35, 0x37, 0x27, 0xf9, 0xd7, 0xf6, 0xed, 0x27, 0xee, 0x4e, 0xbd, + 0x64, 0x7f, 0x5f, 0xde, + 0x67, 0xff, 0xfa, 0x5a, 0x56, 0x90, 0x0d, 0x47, 0x4b, 0xec, 0x4f, 0x44, + 0x8c, 0x3c, 0x2f, 0x42, + 0xa4, 0xaa, 0x5a, 0x32, 0x84, 0x6b, 0xc3, 0x87, 0x58, 0xe4, 0x7d, 0xe3, + 0x73, 0x69, 0xf0, 0xb3, + 0x99, 0xaa, 0x15, 0xe7, 0x17, 0x7c, 0x99, 0xf7, 0xae, 0xbc, 0x2b, 0xef, + 0x11, 0x8b, 0x33, 0x89, + 0xb0, 0x38, 0x89, 0xbf, 0x26, 0x44, 0x63, 0x37, 0xb5, 0xcb, 0x85, 0x70, + 0x2d, 0x18, 0x28, 0x47, + 0x88, 0xa1, 0x77, 0x8d, 0x4f, 0xc5, 0xe9, 0x67, 0xb3, 0x9b, 0xa7, 0x66, + 0xc4, 0x7d, 0x61, 0x7f, + 0xdb, 0xf1, 0x16, 0xe7, 0xad, 0xcf, 0x64, 0xaa, 0x44, 0x48, 0xa2, 0x24, + 0x5d, 0x33, 0x12, 0x43, + 0xb8, 0x66, 0x8c, 0x94, 0x63, 0xc4, 0xd1, 0x5b, 0xc6, 0x47, 0x52, 0x6f, + 0xb5, 0x59, 0x75, 0x97, + 0xd4, 0xbf, 0x95, 0x5f, 0x4c, 0xbf, 0x60, 0x9c, 0x97, 0xf3, 0xd8, 0x74, + 0x16, 0x95, 0x44, 0x4a, + 0x08, 0xbf, 0x11, 0x44, 0xc9, 0x6b, 0xf2, 0x96, 0x9c, 0x37, 0x3e, 0x90, + 0xe9, 0x35, 0x1d, 0x4d, + 0x9b, 0x85, 0x3b, 0x3b, 0x8e, 0xde, 0xe6, 0x78, 0xdb, 0x7e, 0x56, 0xce, + 0x62, 0xd1, 0xd5, 0xec, + 0x46, 0x69, 0x57, 0x81, 0x74, 0x13, 0x69, 0xd7, 0x1d, 0xe9, 0x57, 0xb9, + 0x5a, 0xaa, 0xbe, 0x52, + 0xaf, 0x61, 0x95, 0xf4, 0x5f, 0x54, 0xbe, 0x40, 0x88, 0x91, 0x43, 0x44, + 0xd2, 0x59, 0xe3, 0x5d, + 0x99, 0x66, 0xb1, 0xd9, 0x2d, 0x75, 0xa9, 0x71, 0x1f, 0xd8, 0x4f, 0x3b, + 0x4e, 0xcb, 0x1b, 0xd2, + 0xcc, 0xf9, 0x2a, 0x53, 0xb2, 0xae, 0x10, 0x99, 0x3e, 0x92, 0xa4, 0x4b, + 0xc6, 0x15, 0xcf, 0xbc, + 0x7a, 0x64, 0xfa, 0x69, 0x2d, 0xfd, 0xdf, 0xf2, 0x99, 0x89, 0xa5, 0xd4, + 0x8e, 0xea, 0xaa, 0x63, + 0xa3, 0xf1, 0xc3, 0x64, 0x66, 0x5c, 0xfd, 0x2a, 0x69, 0x7e, 0xf2, 0x65, + 0x5e, 0x47, 0x09, 0x03, + 0x23, 0x41, 0x0e, 0x12, 0x4b, 0xa7, 0x8d, 0x37, 0x65, 0xaa, 0xc7, 0x66, + 0xd4, 0x8b, 0xb7, 0x54, + 0x9d, 0x4d, 0x3f, 0x65, 0x9c, 0x90, 0x93, 0xf4, 0x8d, 0x83, 0xab, 0xb1, + 0x57, 0x88, 0x2c, 0x19, + 0x23, 0x2f, 0xc8, 0x30, 0xce, 0xdb, 0x0a, 0xc3, 0xa9, 0x33, 0xd3, 0x25, + 0xfb, 0x8a, 0x67, 0x5f, + 0x1d, 0x72, 0xd0, 0x57, 0x2c, 0x27, 0xc5, 0xa1, 0xe6, 0x6a, 0xa3, 0x69, + 0xc9, 0x09, 0x3a, 0x3e, + 0x93, 0x9d, 0x40, 0x5d, 0xb1, 0x54, 0x52, 0xb1, 0x58, 0x2f, 0x8d, 0x2c, + 0x93, 0xa6, 0xc7, 0xe7, + 0xc0, 0xa3, 0xb2, 0x4d, 0x86, 0x86, 0xb2, 0x81, 0x97, 0xe7, 0x6c, 0x2c, + 0xfd, 0xa2, 0x29, 0x91, + 0x15, 0x43, 0x59, 0xf1, 0x79, 0xf6, 0x0c, 0x65, 0xfb, 0x8c, 0xeb, 0x26, + 0x65, 0x20, 0x24, 0xcb, + 0x2b, 0x72, 0x5a, 0x4e, 0xb0, 0x6f, 0xd5, 0xd6, 0xba, 0x6c, 0xd6, 0x6d, + 0x56, 0xc7, 0x48, 0x5b, + 0xd1, 0xf9, 0x9c, 0x23, 0x54, 0x27, 0xa7, 0x39, 0x53, 0x65, 0x88, 0xed, + 0x8a, 0xa1, 0xfc, 0x6e, + 0xbf, 0x6c, 0x91, 0xcd, 0x1a, 0x4d, 0xf2, 0x2a, 0x3a, 0xcd, 0x11, 0xfb, + 0x55, 0x50, 0xb8, 0x72, + 0xe4, 0xa2, 0x77, 0xa7, 0xec, 0x34, 0x57, 0xdb, 0x2e, 0x6b, 0xa9, 0x93, + 0xc6, 0x06, 0x1d, 0x9f, + 0x49, 0x74, 0xf9, 0xde, 0x45, 0xa8, 0x46, 0xe3, 0x36, 0xb8, 0xcb, 0xc1, + 0xd3, 0x46, 0x70, 0xee, + 0x1f, 0xa4, 0x31, 0x84, 0x3d, 0x3e, 0x03, 0xea, 0x36, 0xdd, 0x97, 0xc9, + 0x2a, 0x07, 0x90, 0x64, + 0x73, 0x1b, 0x34, 0xc9, 0x4a, 0x99, 0x27, 0xe5, 0xd8, 0x7d, 0x04, 0x67, + 0xcf, 0x04, 0x2c, 0x9d, + 0x7b, 0x5d, 0xe4, 0x0c, 0xa4, 0xe5, 0xfd, 0x72, 0x5c, 0x8e, 0x18, 0x67, + 0x64, 0xb2, 0x3b, 0xce, + 0xc2, 0x9d, 0x5d, 0x22, 0x0f, 0x18, 0x47, 0x8c, 0x43, 0x72, 0x98, 0xbd, + 0x6e, 0xac, 0x18, 0x72, + 0xa5, 0x3f, 0x06, 0x3e, 0x99, 0xe2, 0xa7, 0x97, 0xdb, 0xd0, 0xc8, 0xf5, + 0xf9, 0xb1, 0xa1, 0xdb, + 0x26, 0x9f, 0xb5, 0xde, 0x94, 0x87, 0xd0, 0x72, 0xb0, 0x9f, 0x4c, 0xa2, + 0xe2, 0x0b, 0xf9, 0xc1, + 0x7c, 0xbe, 0xd7, 0x0a, 0xb7, 0x23, 0x34, 0xd7, 0x69, 0x52, 0x88, 0x77, + 0x36, 0xbb, 0x71, 0x48, + 0x5a, 0x88, 0x44, 0x97, 0xdc, 0x06, 0xd6, 0x7b, 0xfe, 0xb2, 0x77, 0x90, + 0xbe, 0xc6, 0xaa, 0xd1, + 0xc4, 0x62, 0x16, 0x3c, 0xfd, 0x12, 0x3f, 0x59, 0xb2, 0x07, 0xcb, 0x1c, + 0x32, 0x4e, 0xca, 0xc4, + 0x9a, 0x8e, 0x89, 0xca, 0x66, 0x9d, 0xa7, 0x45, 0xc4, 0xbe, 0x6e, 0x6f, + 0x76, 0x34, 0x13, 0x67, + 0x0d, 0x70, 0x5d, 0x70, 0x85, 0x28, 0xe4, 0x4a, 0xc3, 0x2b, 0x5b, 0x3d, + 0xf7, 0xf1, 0x41, 0xab, + 0xfc, 0x51, 0xf2, 0xe8, 0x29, 0xbc, 0x62, 0x2a, 0x57, 0xbe, 0x9a, 0x90, + 0xb3, 0x56, 0xc9, 0x8f, + 0xe6, 0x5a, 0xdf, 0xc9, 0x51, 0xb9, 0x5b, 0xf2, 0x03, 0xae, 0xa5, 0xda, + 0x72, 0xb0, 0xd0, 0xa7, + 0xe8, 0xd7, 0xcb, 0x9b, 0xca, 0xe3, 0xaa, 0x27, 0x85, 0x59, 0xea, 0xf9, + 0x83, 0x0b, 0xad, 0x9c, + 0xfb, 0x9f, 0xc0, 0x66, 0x8a, 0xeb, 0x7c, 0xf4, 0x33, 0xd8, 0x47, 0xa2, + 0x40, 0xf8, 0x5a, 0x3f, + 0x7b, 0x9a, 0x43, 0x8c, 0x8e, 0x15, 0xc7, 0xcf, 0x2e, 0x69, 0x5b, 0xe4, + 0xc9, 0x6e, 0xfc, 0xaa, + 0xd9, 0x38, 0x26, 0xd5, 0x6e, 0x9b, 0xdd, 0x34, 0x71, 0x69, 0x6a, 0x8b, + 0x71, 0x80, 0x9c, 0xb9, + 0x5f, 0x8a, 0xd8, 0xcd, 0x8a, 0x2e, 0x8b, 0x62, 0xa0, 0xfe, 0x1d, 0xa7, + 0x33, 0x49, 0xab, 0x7c, + 0x6e, 0xa2, 0x55, 0xda, 0xe3, 0xf9, 0x81, 0x66, 0x78, 0xe7, 0xfd, 0x34, + 0x14, 0xc3, 0xfb, 0x48, + 0x59, 0x21, 0xdf, 0x9a, 0x6b, 0x7d, 0x45, 0x5e, 0xb8, 0x87, 0xd6, 0x60, + 0x34, 0xf3, 0xc8, 0x9c, + 0x1f, 0x11, 0x69, 0x17, 0xdd, 0x50, 0x36, 0x8b, 0xd0, 0x12, 0xa6, 0xd0, + 0xe7, 0xe5, 0xfa, 0x12, + 0x67, 0x9b, 0xfb, 0x89, 0x98, 0x22, 0xdd, 0x97, 0x43, 0xae, 0xb4, 0x4a, + 0x14, 0x1c, 0xad, 0x64, + 0xea, 0x61, 0x78, 0xd2, 0xb8, 0x9f, 0x20, 0x4b, 0xb1, 0x45, 0x2b, 0x97, + 0x87, 0x21, 0x3b, 0xd8, + 0x75, 0x0e, 0x18, 0x87, 0xa5, 0xb2, 0x16, 0x9b, 0x55, 0x87, 0xa5, 0xdc, + 0x56, 0x71, 0x32, 0x75, + 0xaf, 0xec, 0x25, 0xde, 0x97, 0xb2, 0x7e, 0x69, 0x50, 0x94, 0x81, 0x52, + 0x19, 0x2f, 0x25, 0x7a, + 0xad, 0x12, 0x3e, 0x95, 0x92, 0xd1, 0x93, 0xd0, 0xa2, 0xf7, 0x9e, 0x58, + 0xab, 0x74, 0x44, 0x8b, + 0xae, 0x91, 0xbe, 0x33, 0xc6, 0xb9, 0x65, 0x73, 0xcd, 0xf3, 0x8c, 0x08, + 0xbe, 0x8e, 0xff, 0x88, + 0x32, 0x68, 0x44, 0xc1, 0xe1, 0x25, 0x73, 0xad, 0xcf, 0x90, 0xe3, 0x7e, + 0xe8, 0x05, 0xa3, 0x95, + 0x0f, 0x6f, 0xff, 0x72, 0x3f, 0x13, 0x72, 0xd9, 0x4c, 0xd5, 0x91, 0x6a, + 0x6c, 0x06, 0x36, 0xfb, + 0xc6, 0xa4, 0xf3, 0x09, 0x67, 0x9f, 0x07, 0xd0, 0xbd, 0x8b, 0x8a, 0x8d, + 0x4a, 0xe3, 0xfb, 0x2b, + 0xbc, 0x03, 0xf8, 0x23, 0xd6, 0xcf, 0x80, 0x83, 0xc0, 0x72, 0x28, 0xb9, + 0x95, 0xb4, 0xe3, 0x03, + 0x68, 0xa3, 0xc8, 0xad, 0x8f, 0x62, 0xb7, 0x36, 0x4a, 0xff, 0x8d, 0x3e, + 0x4a, 0x89, 0xff, 0x6d, + 0xb2, 0x4f, 0xf6, 0x1a, 0xcd, 0x52, 0xae, 0x6a, 0x90, 0xea, 0xce, 0xa9, + 0x11, 0x25, 0xcd, 0x59, + 0x3b, 0xd9, 0xdb, 0xf7, 0x4b, 0x0d, 0x3b, 0x6c, 0x45, 0x10, 0x54, 0x72, + 0x95, 0xb3, 0x82, 0x50, + 0x31, 0x25, 0xe3, 0xb1, 0x69, 0xd8, 0xab, 0x10, 0xaf, 0x4c, 0x42, 0x2b, + 0xef, 0x9a, 0xf8, 0x5e, + 0x6e, 0x81, 0x97, 0x4a, 0x0d, 0x35, 0xab, 0x4c, 0x7b, 0x49, 0x26, 0xe3, + 0xe3, 0x75, 0xed, 0x36, + 0x86, 0xdc, 0x63, 0xc0, 0x69, 0x99, 0x9b, 0x66, 0x39, 0x1c, 0x15, 0x61, + 0xe5, 0x7c, 0x33, 0xa7, + 0x95, 0x68, 0x1e, 0x5c, 0xab, 0x95, 0x40, 0xcb, 0xd3, 0x33, 0x8e, 0xbe, + 0x18, 0x59, 0x2c, 0x1f, + 0x9b, 0x6b, 0x7d, 0x88, 0x9f, 0xfd, 0x4d, 0x53, 0x2a, 0x63, 0x64, 0xa1, + 0x39, 0x32, 0x9f, 0xb1, + 0xc5, 0x9a, 0xd7, 0x6c, 0xe9, 0x21, 0x37, 0x49, 0x07, 0x8d, 0x9b, 0xc1, + 0x7d, 0xd8, 0x4a, 0x71, + 0xa4, 0xb8, 0xb8, 0x68, 0xd2, 0x79, 0x5f, 0xce, 0xc9, 0x5f, 0x90, 0x64, + 0x9c, 0x5e, 0x5b, 0xd8, + 0xcf, 0xbe, 0xb4, 0x48, 0xa4, 0x70, 0xc9, 0x8d, 0x4f, 0xf1, 0x01, 0x6b, + 0xfb, 0x47, 0xb2, 0x4b, + 0x06, 0x6a, 0x69, 0x8a, 0xcd, 0xf5, 0x0b, 0xa1, 0x5f, 0xaa, 0xa5, 0xb2, + 0xe9, 0x3a, 0x3d, 0x9f, + 0xcf, 0x15, 0xa6, 0x36, 0x4a, 0xdc, 0xfa, 0x8b, 0xd7, 0x77, 0x64, 0x93, + 0xa8, 0x2e, 0x6c, 0x3a, + 0x4e, 0xca, 0x4d, 0x8d, 0x05, 0x42, 0x09, 0x75, 0xd7, 0x2e, 0xd9, 0x49, + 0x2e, 0x2c, 0xad, 0xb9, + 0x25, 0x91, 0x9a, 0x71, 0x74, 0x4d, 0xc1, 0xee, 0xbc, 0xed, 0x54, 0x61, + 0x5b, 0x99, 0x39, 0x31, + 0x28, 0x26, 0x40, 0x73, 0x1c, 0xd2, 0xa6, 0xf0, 0x79, 0x31, 0x15, 0x54, + 0x23, 0xdc, 0xc4, 0xea, + 0x3a, 0xfa, 0x23, 0x64, 0xf6, 0xe0, 0x92, 0x74, 0x41, 0x57, 0xae, 0xf1, + 0x55, 0x7c, 0xca, 0x65, + 0x44, 0x3a, 0xf5, 0xda, 0x22, 0xd9, 0x48, 0xfd, 0xb0, 0x89, 0x99, 0x55, + 0x50, 0x88, 0x25, 0x7f, + 0x96, 0xd2, 0xaa, 0xc6, 0x14, 0xf3, 0x39, 0x85, 0x2a, 0x4c, 0x21, 0x09, + 0xaf, 0x55, 0x3d, 0x13, + 0x98, 0x5f, 0x05, 0xa7, 0x79, 0xcc, 0x4d, 0xd4, 0x3d, 0x63, 0xb0, 0xbb, + 0xb0, 0xef, 0x2f, 0x40, + 0x53, 0x9e, 0xb5, 0xde, 0x26, 0x63, 0x3c, 0xc4, 0xb8, 0x4a, 0xf4, 0x94, + 0x61, 0xd2, 0x48, 0xe4, + 0xd3, 0x58, 0xb4, 0x53, 0xae, 0xf5, 0x1f, 0x47, 0x75, 0x38, 0x50, 0x9e, + 0x05, 0x83, 0xb0, 0x45, + 0xaa, 0xf6, 0xef, 0x5c, 0x72, 0x6c, 0x16, 0xda, 0xf7, 0xd0, 0xb9, 0xc0, + 0x09, 0xe7, 0x2f, 0xd0, + 0xce, 0x40, 0xa2, 0x32, 0x68, 0x8d, 0xc4, 0x2f, 0xce, 0x59, 0xf0, 0x31, + 0x19, 0x55, 0xdd, 0x8d, + 0x48, 0x86, 0xaf, 0x3d, 0x96, 0x79, 0x0a, 0x5f, 0xca, 0x3f, 0xb1, 0x93, + 0xb2, 0x4f, 0xaa, 0x7b, + 0xfd, 0x64, 0x5d, 0x83, 0xd9, 0xb0, 0x4a, 0xae, 0x4c, 0x41, 0xee, 0x32, + 0x56, 0x74, 0xc9, 0x53, + 0x8a, 0xb7, 0xc6, 0xe1, 0xeb, 0x65, 0x48, 0xb1, 0x01, 0x2b, 0x6c, 0x95, + 0x97, 0x64, 0x2a, 0x72, + 0xc5, 0x60, 0xc5, 0x12, 0xfa, 0x27, 0x04, 0xd5, 0x7d, 0x05, 0x9a, 0xdb, + 0x21, 0xdb, 0x8d, 0xbd, + 0x52, 0x8c, 0xcd, 0xc2, 0x67, 0x75, 0x89, 0x58, 0x23, 0x5b, 0xed, 0x8a, + 0xc2, 0x32, 0x66, 0xd5, + 0x04, 0xc5, 0x04, 0x38, 0x8b, 0xa6, 0xd6, 0x3d, 0x8f, 0xae, 0x2e, 0xf0, + 0xef, 0x9b, 0x68, 0xaf, + 0x45, 0xd7, 0xcc, 0xef, 0x51, 0x83, 0x79, 0xf0, 0xb1, 0x84, 0xa1, 0x2b, + 0xd7, 0xf8, 0xf1, 0xe8, + 0xcf, 0x4e, 0x2c, 0xbc, 0xa9, 0x67, 0x78, 0xf4, 0xa3, 0x3e, 0x6f, 0xd5, + 0xf7, 0x26, 0xca, 0xe0, + 0xa6, 0x1a, 0xc9, 0x8e, 0xa0, 0xb3, 0xe3, 0x6e, 0xbc, 0x41, 0x6b, 0x1e, + 0xed, 0x35, 0xf4, 0xe4, + 0xc9, 0x5c, 0x79, 0xdd, 0xec, 0x39, 0x2f, 0x93, 0xc8, 0x5a, 0xf3, 0x98, + 0xed, 0x59, 0xeb, 0x1c, + 0x72, 0x3f, 0xcc, 0xb8, 0x12, 0x7c, 0x60, 0xbb, 0x9c, 0x32, 0x47, 0x9e, + 0x24, 0x72, 0xd4, 0xee, + 0x57, 0x01, 0x85, 0x63, 0x8c, 0x3b, 0xe5, 0xc6, 0x05, 0xc6, 0xaa, 0x13, + 0x65, 0x33, 0x23, 0x4e, + 0xca, 0x19, 0x0b, 0xd7, 0x67, 0x98, 0x75, 0x02, 0x7a, 0x55, 0x68, 0xb5, + 0x08, 0x0b, 0x59, 0x25, + 0x3a, 0xcd, 0xce, 0xd5, 0x0e, 0xdf, 0x78, 0x4c, 0x1e, 0x91, 0xbb, 0xe4, + 0x77, 0xe8, 0xf9, 0xbc, + 0xa5, 0xef, 0x7d, 0xe4, 0xcf, 0x46, 0xef, 0xfb, 0x2d, 0xeb, 0xbf, 0x23, + 0x3d, 0xb1, 0xcd, 0x7e, + 0xfe, 0x7f, 0x0b, 0x7f, 0xce, 0xa3, 0x77, 0x32, 0x12, 0x95, 0xe9, 0xfb, + 0x28, 0x4d, 0x70, 0xf1, + 0x8e, 0xa9, 0x8d, 0xf3, 0xa2, 0xee, 0xed, 0x1e, 0x84, 0xdb, 0x18, 0xae, + 0x6a, 0xc6, 0x05, 0xd3, + 0xfd, 0x7a, 0x66, 0x6e, 0x31, 0x76, 0xca, 0x38, 0x6c, 0x16, 0xe6, 0xbc, + 0x3b, 0x62, 0x9b, 0x7d, + 0x23, 0x51, 0xb0, 0x59, 0x66, 0xe3, 0x17, 0x53, 0x03, 0xa0, 0x8e, 0xab, + 0x16, 0x2f, 0x89, 0x23, + 0x7f, 0xbe, 0x4e, 0xad, 0x76, 0xc4, 0xc4, 0x71, 0xd6, 0x2c, 0x83, 0x73, + 0x6f, 0xcb, 0x3b, 0xf2, + 0x27, 0x24, 0xaf, 0x63, 0x1d, 0x65, 0xb1, 0x25, 0x70, 0x75, 0xdc, 0xd2, + 0xeb, 0xc1, 0x09, 0xe6, + 0x4d, 0xc2, 0x27, 0x2b, 0x91, 0x25, 0x4b, 0x66, 0xa0, 0xb3, 0xa3, 0x6e, + 0xa8, 0xf3, 0xe1, 0x08, + 0x78, 0x9f, 0x8a, 0x04, 0xf1, 0xd8, 0xfb, 0x84, 0xbb, 0xfd, 0x18, 0x2b, + 0xdf, 0x43, 0x04, 0xcc, + 0x46, 0x37, 0x5e, 0x2a, 0xeb, 0xd0, 0x63, 0x29, 0xe3, 0x96, 0x6b, 0xbe, + 0x5c, 0x38, 0x8e, 0x1e, + 0x9f, 0x64, 0x9f, 0xab, 0x86, 0x7a, 0x32, 0xf6, 0x39, 0x6e, 0xf6, 0x9c, + 0x47, 0x02, 0x75, 0xd7, + 0x7b, 0xbf, 0xa6, 0xea, 0xcb, 0xd1, 0x31, 0xdd, 0x1f, 0x8f, 0x56, 0xcb, + 0xd8, 0x35, 0xcf, 0xf9, + 0xf4, 0x29, 0x99, 0xaa, 0x65, 0x1a, 0x98, 0x04, 0xb7, 0xd1, 0xf8, 0x95, + 0xb7, 0xef, 0x0d, 0xe8, + 0x25, 0x43, 0x75, 0xa7, 0xc9, 0xe9, 0x51, 0xc6, 0x77, 0x14, 0x75, 0x77, + 0x42, 0xf5, 0x9f, 0xe3, + 0xdc, 0x9f, 0x8a, 0xf6, 0x14, 0x2f, 0x53, 0x91, 0xfa, 0x44, 0x00, 0x6d, + 0x28, 0x7f, 0x5c, 0xcf, + 0xb8, 0x12, 0xb4, 0xe6, 0xd2, 0xb6, 0x3f, 0x6a, 0x64, 0x0d, 0x16, 0xda, + 0x68, 0x6c, 0x93, 0x82, + 0xda, 0x5b, 0x92, 0xba, 0xce, 0x78, 0x2a, 0xea, 0x65, 0xfb, 0x5a, 0xc7, + 0x5a, 0x66, 0xcd, 0x42, + 0x7b, 0x33, 0x03, 0x62, 0x06, 0x5a, 0xcc, 0x90, 0x85, 0xf0, 0xf3, 0x6a, + 0x1b, 0xbc, 0xe6, 0xf3, + 0xdb, 0x59, 0xf9, 0x33, 0x63, 0xa7, 0x63, 0x8b, 0x64, 0xe2, 0xf6, 0xb8, + 0xd9, 0x7e, 0x90, 0x1a, + 0xef, 0x08, 0xd7, 0x41, 0xb3, 0xe5, 0x04, 0xde, 0x93, 0x8e, 0x16, 0x4a, + 0xd0, 0xd1, 0x29, 0xb3, + 0xb5, 0x19, 0xe9, 0xfb, 0x41, 0x61, 0x06, 0x51, 0x92, 0x80, 0xdc, 0x9e, + 0xf6, 0xc3, 0x64, 0xd5, + 0x3f, 0x21, 0xbd, 0xd3, 0xb2, 0xde, 0x21, 0x32, 0xf4, 0xc3, 0x5a, 0x23, + 0x27, 0x2c, 0xf3, 0xcf, + 0xb1, 0x87, 0x75, 0x25, 0x5a, 0x66, 0x42, 0x7f, 0x0c, 0xb9, 0xac, 0xd9, + 0xec, 0x3b, 0xc9, 0x89, + 0x5a, 0x69, 0x78, 0xbb, 0xa5, 0xcd, 0x8a, 0x13, 0xf4, 0x67, 0xe1, 0x71, + 0xb1, 0x16, 0x7a, 0x2e, + 0x99, 0x6e, 0x83, 0x4f, 0xa5, 0x85, 0x5a, 0xb2, 0x5e, 0x86, 0x45, 0x2a, + 0x45, 0x33, 0x8a, 0xac, + 0x99, 0x44, 0xc4, 0xb7, 0x98, 0x6d, 0xc7, 0x90, 0xeb, 0x84, 0x65, 0xcd, + 0x74, 0xe4, 0xc9, 0xc1, + 0xe2, 0xc7, 0x03, 0xae, 0xea, 0xc2, 0x51, 0x59, 0x8b, 0x37, 0x4c, 0x64, + 0x54, 0x20, 0xfd, 0x4f, + 0xe3, 0x8c, 0xb3, 0x4e, 0xd6, 0x1a, 0x9b, 0xc5, 0x51, 0xd3, 0x29, 0xb1, + 0xcb, 0xb4, 0x11, 0xb1, + 0x9b, 0xed, 0x2b, 0x45, 0x61, 0x56, 0x10, 0x34, 0x60, 0x03, 0x55, 0x85, + 0x1d, 0x64, 0x1f, 0xbc, + 0x1c, 0x8e, 0xca, 0xed, 0x44, 0xeb, 0x34, 0x4e, 0x2d, 0xb5, 0x68, 0xc6, + 0xd3, 0xba, 0x1b, 0xfd, + 0x2e, 0x20, 0x67, 0xce, 0x87, 0xc6, 0x6e, 0xcb, 0xd8, 0x24, 0x72, 0xfd, + 0x64, 0x4e, 0x5d, 0x9b, + 0xd0, 0xad, 0xa7, 0xf5, 0x90, 0x0c, 0x65, 0xb5, 0xe9, 0x7a, 0x27, 0x7f, + 0xc5, 0x6c, 0x6d, 0x61, + 0x37, 0x7a, 0x8e, 0x5d, 0x62, 0x1a, 0x51, 0xe2, 0x69, 0xdb, 0x47, 0x1c, + 0xdf, 0x81, 0xcd, 0x5b, + 0x2c, 0xeb, 0x9c, 0x90, 0x07, 0xa5, 0x1b, 0x51, 0xd1, 0x08, 0xdf, 0x93, + 0xb1, 0xcf, 0x56, 0xcb, + 0x7a, 0x2d, 0xc4, 0x69, 0x2a, 0xb9, 0x78, 0x17, 0xda, 0x3b, 0xe4, 0xc3, + 0xf5, 0x1e, 0x1d, 0x1f, + 0xe7, 0xf4, 0x3e, 0x3b, 0x91, 0x68, 0x6b, 0xf6, 0xe9, 0x3d, 0x46, 0x5d, + 0x95, 0xaf, 0x2b, 0x3e, + 0x21, 0x6f, 0xd6, 0x5b, 0x38, 0x50, 0xdc, 0x0e, 0xc0, 0xce, 0xa9, 0xc4, + 0xc1, 0x1e, 0x0b, 0x17, + 0xbb, 0xcc, 0x55, 0x5b, 0x64, 0x14, 0x56, 0x2e, 0x46, 0x1f, 0x87, 0x2d, + 0xb3, 0x76, 0x6b, 0x1f, + 0x6e, 0xb1, 0xcc, 0xd9, 0x45, 0x4b, 0x0d, 0x23, 0xeb, 0xf0, 0xca, 0xb6, + 0x16, 0xa8, 0x27, 0x93, + 0x60, 0x21, 0x63, 0xbd, 0xd8, 0xb1, 0x59, 0xe7, 0xa9, 0x71, 0x71, 0xeb, + 0xec, 0xcb, 0x88, 0x89, + 0xa5, 0xe4, 0x9d, 0x40, 0x98, 0xc3, 0x35, 0x03, 0x49, 0x5f, 0x62, 0x17, + 0xdc, 0x6a, 0x62, 0x3b, + 0xfa, 0x6c, 0x61, 0x9d, 0x3d, 0x96, 0x36, 0x85, 0x83, 0x9c, 0x72, 0xeb, + 0xf4, 0xea, 0xbb, 0xcc, + 0xb6, 0x6d, 0x9c, 0x22, 0xba, 0xcb, 0x7f, 0xa2, 0xcb, 0x8e, 0x68, 0xf4, + 0x80, 0xd9, 0xbe, 0x03, + 0x4e, 0xa2, 0xb4, 0xef, 0x16, 0x22, 0x85, 0xa7, 0x75, 0x37, 0x96, 0xc9, + 0x81, 0x46, 0x1e, 0xeb, + 0x7a, 0x57, 0x3c, 0x2c, 0xe1, 0xec, 0x35, 0x0e, 0xfc, 0x61, 0xa7, 0xd9, + 0xf6, 0x32, 0x96, 0x79, + 0x1c, 0x7a, 0xdb, 0xcc, 0x75, 0x0e, 0xb1, 0xeb, 0xdc, 0x4a, 0x84, 0xce, + 0x85, 0xeb, 0x39, 0xe4, + 0x94, 0x34, 0xf6, 0xfa, 0x6d, 0xe6, 0xf8, 0x7d, 0x78, 0x47, 0x0e, 0x36, + 0x19, 0x2a, 0x37, 0xca, + 0x53, 0x16, 0x3e, 0xb6, 0xe3, 0x33, 0x37, 0x63, 0x97, 0x4e, 0xf2, 0x77, + 0xbd, 0xa3, 0x27, 0x92, + 0x93, 0xad, 0x32, 0xed, 0x97, 0xde, 0xfa, 0xe4, 0x9c, 0x8f, 0xd7, 0xcd, + 0xb1, 0xc8, 0xa5, 0xd0, + 0x42, 0x16, 0x2e, 0x64, 0xc7, 0x5a, 0xae, 0x6b, 0x38, 0xaf, 0xc4, 0xd6, + 0x35, 0xd5, 0x3d, 0xce, + 0x55, 0x96, 0xfe, 0x6d, 0x50, 0x4c, 0x93, 0x47, 0x39, 0x07, 0x6e, 0x41, + 0x06, 0xeb, 0x3a, 0xc3, + 0x89, 0xe7, 0x46, 0xad, 0x71, 0x5f, 0x34, 0x62, 0x1d, 0x6c, 0x64, 0xac, + 0x91, 0xbc, 0xda, 0x4e, + 0x89, 0x9d, 0x6a, 0xd3, 0x12, 0x56, 0xda, 0x17, 0x8b, 0xc2, 0x82, 0x20, + 0x98, 0x8f, 0x06, 0x33, + 0x58, 0x73, 0x9d, 0x89, 0x0d, 0xec, 0x7e, 0x0f, 0xc8, 0x7f, 0x53, 0x41, + 0xa7, 0xa2, 0xd7, 0x75, + 0x16, 0xec, 0x92, 0x7b, 0x89, 0x11, 0x55, 0x5d, 0x6c, 0x36, 0xdb, 0xb6, + 0x22, 0x53, 0x7b, 0x64, + 0x9e, 0x82, 0xff, 0x0f, 0x67, 0xc7, 0x6e, 0x32, 0x7b, 0xb6, 0x93, 0xc5, + 0xab, 0xd0, 0x52, 0x2c, + 0xa3, 0xd7, 0xbb, 0xdb, 0x36, 0x52, 0x67, 0x0c, 0xa3, 0x2d, 0x07, 0xcf, + 0xf2, 0xb4, 0x6d, 0xc2, + 0xfb, 0xee, 0x84, 0x8b, 0x22, 0x64, 0xda, 0x64, 0xe1, 0x62, 0x01, 0xb2, + 0x6c, 0x74, 0xff, 0xb6, + 0x1e, 0x4d, 0xdf, 0x4f, 0x66, 0x9e, 0x4a, 0x0e, 0x77, 0xf1, 0x3d, 0x83, + 0x75, 0xbd, 0x34, 0xd4, + 0x6a, 0x23, 0xb0, 0xfb, 0x1c, 0xec, 0x92, 0xc8, 0xce, 0xb6, 0xcd, 0x42, + 0x67, 0x39, 0x5c, 0x67, + 0x62, 0x97, 0x6a, 0xac, 0x3d, 0x4d, 0x47, 0xe7, 0x3a, 0x1f, 0xbc, 0x0c, + 0xcf, 0x0a, 0x5b, 0x2c, + 0xab, 0xbb, 0x78, 0x5d, 0x8a, 0x8f, 0xd4, 0x52, 0xd9, 0x2c, 0x82, 0xca, + 0x3a, 0x3f, 0xac, 0x67, + 0xf4, 0x2e, 0x6c, 0x96, 0x82, 0x57, 0x36, 0x59, 0xda, 0xf7, 0xb0, 0x5a, + 0x07, 0x2c, 0xd6, 0x97, + 0x9c, 0xbb, 0xce, 0x32, 0xaf, 0x09, 0x0e, 0x6c, 0x70, 0xb0, 0x30, 0x80, + 0x0d, 0xb4, 0x85, 0x8c, + 0x15, 0x32, 0x56, 0xd9, 0xac, 0x26, 0x2b, 0x71, 0xa9, 0xa1, 0x5a, 0x17, + 0x92, 0x69, 0x16, 0x07, + 0xc0, 0x12, 0x7a, 0x6a, 0xc8, 0x61, 0x6b, 0x90, 0xcc, 0x83, 0x2d, 0x9c, + 0x8b, 0xee, 0x85, 0xd3, + 0x5c, 0xf9, 0x07, 0xbe, 0xb7, 0xda, 0xd2, 0xb3, 0x59, 0xfe, 0x8a, 0xcd, + 0x0a, 0xf0, 0x8c, 0x95, + 0x66, 0xdb, 0x26, 0xec, 0xdb, 0x47, 0xdf, 0xcd, 0x53, 0x77, 0x79, 0x5f, + 0x44, 0x16, 0x4f, 0xcf, + 0x5a, 0x5a, 0x6d, 0xd8, 0x23, 0x85, 0x6b, 0xa5, 0x85, 0x46, 0x1f, 0x5d, + 0xe7, 0x7b, 0x57, 0xdc, + 0x28, 0x83, 0xd9, 0x17, 0xe6, 0x90, 0x9d, 0xaa, 0x7c, 0x56, 0x5b, 0x69, + 0x99, 0xb5, 0x16, 0x9e, + 0xd4, 0xbe, 0xf3, 0x12, 0x1c, 0xbb, 0xe0, 0xc4, 0xee, 0x8b, 0x64, 0x85, + 0x39, 0x62, 0x03, 0xbe, + 0x50, 0xa0, 0xa5, 0x9c, 0x42, 0x0e, 0x5c, 0x6b, 0xa1, 0xb2, 0x80, 0xaa, + 0x65, 0xb6, 0xce, 0x35, + 0x4b, 0xd8, 0x3d, 0x52, 0x2d, 0x7d, 0xff, 0x1e, 0x4d, 0x9c, 0x20, 0x5e, + 0x60, 0xef, 0xb0, 0xc3, + 0xdb, 0x4a, 0x9f, 0x9e, 0x55, 0xd8, 0x7d, 0x0d, 0x3e, 0x30, 0x15, 0x3f, + 0x49, 0xc1, 0x4b, 0x56, + 0x5b, 0x56, 0x5b, 0x2c, 0xff, 0xa7, 0x4f, 0x3f, 0x73, 0xe8, 0xb1, 0xea, + 0x75, 0x15, 0x5e, 0x16, + 0x41, 0x84, 0x2c, 0x69, 0x63, 0x89, 0x25, 0x2e, 0x3b, 0x1a, 0x4b, 0x25, + 0x5b, 0xc7, 0x59, 0x46, + 0xe2, 0x22, 0x43, 0x65, 0x92, 0xb9, 0x48, 0xb7, 0x2c, 0x00, 0x96, 0x33, + 0x63, 0x22, 0xd9, 0xdc, + 0x1b, 0x87, 0x8b, 0xe0, 0x32, 0x1c, 0xaf, 0x5f, 0x89, 0x7e, 0x6a, 0xd9, + 0x39, 0x97, 0x5a, 0xfc, + 0x61, 0x15, 0xf9, 0x45, 0xed, 0x66, 0x8d, 0x16, 0x6f, 0x59, 0x08, 0x1f, + 0x0b, 0x88, 0x9e, 0xb9, + 0x5c, 0xf3, 0xc1, 0x42, 0x0b, 0xa5, 0xa9, 0xd8, 0x70, 0x2e, 0x12, 0x64, + 0x41, 0xcb, 0xd3, 0xba, + 0x8c, 0x8c, 0x99, 0x48, 0xac, 0x2e, 0x31, 0x5b, 0x56, 0x10, 0x3f, 0xd5, + 0x70, 0x50, 0xee, 0xc3, + 0x87, 0x2f, 0x96, 0xe3, 0xb9, 0x39, 0x7a, 0xf6, 0x72, 0xf7, 0x35, 0x07, + 0xaf, 0xb2, 0xf2, 0xb1, + 0x9c, 0x1d, 0xb1, 0x98, 0x7f, 0x97, 0xc2, 0xa1, 0xcd, 0x42, 0x7d, 0x11, + 0x3b, 0xc6, 0x93, 0x8c, + 0x5e, 0xae, 0x67, 0x39, 0xa9, 0x19, 0x5e, 0x0a, 0x9a, 0x73, 0xac, 0x50, + 0x67, 0xa3, 0x1b, 0x91, + 0x60, 0x01, 0x59, 0x73, 0xa6, 0x4f, 0x74, 0x2c, 0xc1, 0x6f, 0x6f, 0x92, + 0xff, 0xa0, 0x16, 0xba, + 0x15, 0xff, 0x13, 0x7c, 0x7e, 0x91, 0xd9, 0xf7, 0x12, 0x5c, 0x0e, 0x40, + 0x8a, 0x15, 0x7c, 0x9a, + 0xc4, 0xe7, 0x97, 0x2c, 0x7c, 0x38, 0xf1, 0x81, 0xf9, 0x6e, 0x3e, 0xac, + 0x58, 0xe1, 0xca, 0xf6, + 0xc6, 0x42, 0xc9, 0xc0, 0x66, 0x9d, 0x6b, 0x13, 0xe3, 0xe7, 0x19, 0x6a, + 0x9f, 0x6b, 0xc4, 0x17, + 0x56, 0x06, 0xc0, 0x2a, 0x64, 0x9c, 0x80, 0xae, 0xe6, 0x30, 0xc2, 0x85, + 0xb9, 0xe8, 0xee, 0x51, + 0xf8, 0x5a, 0x0d, 0xad, 0x06, 0x32, 0xf3, 0x3c, 0xb3, 0xa7, 0x91, 0xd6, + 0x07, 0xe0, 0xd7, 0xa1, + 0xe9, 0x79, 0xe1, 0x9f, 0x9d, 0xbd, 0x58, 0x84, 0xb6, 0x16, 0xf0, 0x7f, + 0x14, 0x9f, 0x3c, 0x6d, + 0xf3, 0xd8, 0x21, 0xfa, 0xa1, 0xd7, 0xd9, 0xe6, 0x7a, 0x95, 0x44, 0xf5, + 0x42, 0xf8, 0xa8, 0x44, + 0xe7, 0x73, 0x7d, 0xe6, 0x5b, 0xb1, 0x10, 0x2a, 0xf5, 0x48, 0xe8, 0xe2, + 0x5a, 0x3d, 0x37, 0xb1, + 0xe1, 0xb9, 0xb3, 0x2d, 0x6b, 0x0d, 0x46, 0x8e, 0x55, 0x70, 0x3d, 0x83, + 0x28, 0xf6, 0x72, 0x3d, + 0x07, 0xff, 0x7b, 0x0a, 0x5d, 0xb9, 0x66, 0xcd, 0xc6, 0x7f, 0xe6, 0x05, + 0x5d, 0xc3, 0x3b, 0x47, + 0x9d, 0x87, 0xff, 0x8b, 0x3c, 0xba, 0x02, 0x99, 0x0b, 0xf9, 0x3c, 0xdb, + 0x22, 0xed, 0x3c, 0xf9, + 0x3d, 0xa7, 0xf8, 0x49, 0x7c, 0x9a, 0xcf, 0x55, 0xc2, 0x27, 0xaf, 0xf6, + 0x16, 0xe0, 0xe5, 0xf1, + 0x70, 0xa9, 0x22, 0x6f, 0x3a, 0x3b, 0xc5, 0x3c, 0xcb, 0xbc, 0x06, 0x2c, + 0x3c, 0xd7, 0xcd, 0x87, + 0x15, 0xab, 0xe9, 0xc3, 0x46, 0xc6, 0x3c, 0x49, 0xc3, 0x66, 0x5d, 0xa6, + 0x8e, 0x8c, 0x9b, 0x6d, + 0x9f, 0x81, 0x14, 0xf5, 0x96, 0xcc, 0xef, 0x9b, 0x95, 0x57, 0xe2, 0x27, + 0x85, 0x8c, 0x98, 0xe6, + 0xc6, 0x4c, 0x7e, 0x1b, 0x08, 0xdd, 0xf5, 0xe4, 0x90, 0xf9, 0xf8, 0xf2, + 0x54, 0xd6, 0xf6, 0xf4, + 0xcd, 0x26, 0x5b, 0x3a, 0xb1, 0x59, 0x9d, 0xd9, 0xe2, 0x9a, 0x51, 0x1f, + 0x10, 0x33, 0xe1, 0xf0, + 0x19, 0x7c, 0x6e, 0x99, 0xbe, 0xa7, 0xee, 0x59, 0x61, 0x3a, 0xd1, 0xfb, + 0x0c, 0x94, 0x3c, 0xb3, + 0x1b, 0x91, 0x3f, 0x12, 0x4e, 0x56, 0x52, 0x09, 0x5a, 0xf9, 0xf0, 0xc7, + 0x4c, 0x2c, 0x92, 0x0d, + 0xb5, 0x35, 0x5a, 0x92, 0xb5, 0x7c, 0x52, 0x1e, 0xee, 0xe5, 0xad, 0x01, + 0x3a, 0x15, 0xf4, 0xad, + 0xe1, 0x93, 0x4d, 0x57, 0xd0, 0x2e, 0xcc, 0x20, 0x8f, 0xf4, 0xc2, 0x06, + 0xeb, 0xf4, 0x3c, 0x25, + 0xd1, 0x4c, 0x3f, 0xca, 0x56, 0x9e, 0x9d, 0xcc, 0x9e, 0x47, 0x5b, 0x7f, + 0x2c, 0x96, 0x86, 0xc5, + 0xd6, 0xc3, 0xfd, 0x78, 0xbc, 0x7a, 0xba, 0x65, 0xf4, 0x58, 0xf2, 0xb4, + 0xca, 0xe8, 0x1b, 0xb8, + 0x96, 0xeb, 0xbb, 0x70, 0x5e, 0xae, 0xd5, 0x9b, 0x36, 0x39, 0x58, 0x61, + 0x03, 0x7c, 0xcc, 0x62, + 0xb7, 0xf0, 0xae, 0xa5, 0x28, 0x28, 0x0f, 0x6e, 0x6b, 0x83, 0x8d, 0xfa, + 0x1c, 0x36, 0xc3, 0x68, + 0x94, 0x94, 0xda, 0xce, 0xd4, 0xfa, 0x03, 0x62, 0x1a, 0xec, 0x75, 0x8e, + 0x3a, 0xb4, 0xbc, 0x81, + 0x9d, 0x67, 0x63, 0x1b, 0xa8, 0x5d, 0xb7, 0x8e, 0x8c, 0x5d, 0x83, 0xb7, + 0xb8, 0x50, 0x83, 0x4d, + 0x86, 0xb2, 0xea, 0x66, 0x66, 0xcc, 0xc7, 0x63, 0xbd, 0x3d, 0x93, 0x58, + 0xf7, 0x31, 0x74, 0x5c, + 0xc0, 0xbe, 0x33, 0xc9, 0x32, 0x3e, 0x5f, 0x3f, 0x1b, 0xf6, 0xc0, 0xfa, + 0x04, 0xd6, 0x86, 0xb6, + 0x96, 0xb1, 0x82, 0x93, 0xba, 0x7f, 0x8a, 0x39, 0x63, 0x0a, 0x55, 0x89, + 0xf7, 0x37, 0x27, 0x27, + 0xb3, 0x09, 0xec, 0xa1, 0x6b, 0x68, 0x33, 0x7c, 0x56, 0xf3, 0xc7, 0x14, + 0x72, 0xea, 0x14, 0xbc, + 0x69, 0xa3, 0x96, 0x64, 0xa9, 0xbe, 0x17, 0x32, 0xd9, 0xec, 0xad, 0x23, + 0x27, 0x4d, 0xa0, 0x67, + 0x03, 0x5e, 0x6f, 0xe5, 0x7a, 0x32, 0x79, 0xb8, 0x37, 0x5c, 0x6c, 0x42, + 0x22, 0x75, 0x77, 0x2d, + 0xcf, 0x6f, 0x8d, 0x5a, 0xf7, 0xb3, 0x6d, 0x17, 0xef, 0x31, 0x50, 0xf9, + 0xb3, 0xfc, 0x0f, 0x7b, + 0x40, 0xb1, 0xae, 0x8e, 0x36, 0xe1, 0x4b, 0xe5, 0x50, 0xf0, 0xae, 0xa3, + 0xf2, 0x7d, 0x8c, 0xae, + 0xd3, 0x14, 0xc5, 0x55, 0xb4, 0xe4, 0xfb, 0xf4, 0x46, 0x41, 0x65, 0xad, + 0xae, 0xba, 0x94, 0xef, + 0x58, 0xf9, 0xa8, 0xa4, 0xbe, 0x5e, 0xaa, 0x69, 0xfa, 0xda, 0xa0, 0x09, + 0x3f, 0xc0, 0x42, 0x46, + 0xbd, 0x8c, 0xc1, 0x66, 0x61, 0x33, 0x1e, 0x8d, 0x72, 0xda, 0x6b, 0x1c, + 0x6a, 0xe6, 0x06, 0xf6, + 0xcd, 0xa6, 0x36, 0xd8, 0x0a, 0x85, 0xd9, 0xac, 0x52, 0xa1, 0xef, 0xe0, + 0x95, 0xeb, 0x3b, 0xb8, + 0x25, 0xc4, 0xd9, 0x62, 0xc6, 0xaf, 0xc5, 0x4b, 0xf2, 0x2c, 0x3d, 0xe5, + 0x50, 0x79, 0x82, 0x1c, + 0xa4, 0xee, 0xe2, 0x7b, 0x5b, 0x6b, 0x38, 0x45, 0xdd, 0xc2, 0x19, 0xe0, + 0x5e, 0xae, 0xbb, 0xf9, + 0x7c, 0x3b, 0xf8, 0xb3, 0xc6, 0x9d, 0x72, 0x0f, 0x5c, 0x2b, 0x9e, 0x56, + 0xe0, 0xb3, 0x25, 0x96, + 0x39, 0x95, 0x96, 0x4f, 0xf9, 0xd4, 0x35, 0x2b, 0xa8, 0xf3, 0x36, 0xe0, + 0x11, 0xbe, 0xab, 0x95, + 0x63, 0x03, 0xdf, 0xdf, 0xab, 0xa8, 0x08, 0x17, 0xc0, 0xf1, 0x56, 0x4d, + 0x53, 0xdd, 0x39, 0xf7, + 0xf6, 0x4f, 0xa4, 0x52, 0x9b, 0x4c, 0xcf, 0x16, 0x46, 0xd8, 0x7c, 0xe4, + 0x29, 0xe4, 0x1c, 0xbe, + 0x50, 0xfb, 0xf3, 0x16, 0x74, 0x66, 0xf8, 0xd1, 0xac, 0x93, 0x76, 0x70, + 0x7d, 0x0f, 0xb8, 0x9b, + 0xeb, 0x21, 0xa8, 0x24, 0x63, 0xc7, 0x75, 0xee, 0x8a, 0xbe, 0x09, 0x2d, + 0x4c, 0xf0, 0x91, 0x77, + 0x02, 0x36, 0xcb, 0xd6, 0xf7, 0x13, 0x95, 0xf6, 0xd6, 0xeb, 0xb8, 0xab, + 0xb4, 0x70, 0x98, 0x06, + 0x8f, 0xab, 0xe9, 0x5b, 0x8f, 0x3c, 0x36, 0x1f, 0x99, 0x0d, 0x72, 0xf4, + 0xba, 0x00, 0x56, 0xd8, + 0xc1, 0xc8, 0xc9, 0x52, 0x63, 0x4c, 0x93, 0xc4, 0x9a, 0xce, 0x89, 0xe1, + 0xce, 0x3b, 0x22, 0x6a, + 0xed, 0xea, 0x3e, 0x64, 0x25, 0xfe, 0xb2, 0x93, 0xde, 0xb6, 0xd8, 0x86, + 0x1c, 0xd9, 0x3e, 0xcf, + 0x7a, 0xca, 0x38, 0x29, 0x96, 0x22, 0x79, 0x83, 0xbe, 0xef, 0x6e, 0xed, + 0x29, 0x47, 0xfa, 0xe5, + 0xda, 0x33, 0xbd, 0xad, 0xa5, 0x8c, 0xce, 0x42, 0x27, 0xcb, 0xb0, 0xf3, + 0x6c, 0xd6, 0x2e, 0xd5, + 0x99, 0xb0, 0x50, 0xdf, 0xab, 0x99, 0xaf, 0x6b, 0xf0, 0x1d, 0x68, 0xab, + 0x82, 0x6a, 0xbb, 0x24, + 0xc0, 0xb3, 0xa3, 0x72, 0x62, 0x20, 0x1e, 0xbe, 0x5f, 0x46, 0x0b, 0x33, + 0x7d, 0xe8, 0x16, 0xc1, + 0xf3, 0x5f, 0xc9, 0xa2, 0x15, 0x96, 0x96, 0x12, 0x38, 0x2d, 0xd0, 0xfa, + 0xdc, 0x41, 0x5c, 0xaa, + 0xb3, 0x6c, 0xb1, 0x85, 0xd2, 0x33, 0x78, 0xf9, 0xcb, 0xf4, 0x2d, 0xc1, + 0xf6, 0xc5, 0x96, 0xa7, + 0x59, 0x25, 0xf4, 0x94, 0x93, 0xa7, 0x57, 0x61, 0xed, 0x15, 0xcc, 0xf1, + 0xe5, 0xa0, 0x42, 0x1e, + 0x81, 0xfb, 0xd5, 0xf4, 0xae, 0x06, 0xeb, 0xe1, 0x63, 0x07, 0x54, 0x5e, + 0x36, 0xf5, 0xb3, 0x11, + 0x99, 0xc4, 0x47, 0xde, 0xe1, 0xd0, 0xdf, 0xa6, 0x47, 0xa8, 0x53, 0xc2, + 0x62, 0x2a, 0x51, 0xab, + 0x64, 0xa5, 0xe4, 0x55, 0xb5, 0x6b, 0x2d, 0xa2, 0xd5, 0xe1, 0x33, 0x2f, + 0x92, 0xca, 0x76, 0xab, + 0x85, 0xb2, 0x07, 0x7b, 0xe0, 0x7b, 0x82, 0x4c, 0x34, 0xa6, 0x48, 0x5c, + 0x4d, 0xe7, 0x84, 0x6e, + 0xb3, 0xc2, 0x22, 0xc6, 0x4b, 0xb5, 0xbd, 0x0a, 0x9e, 0x1b, 0x39, 0xd5, + 0xed, 0x0e, 0x88, 0x8d, + 0x58, 0x26, 0xcf, 0xe7, 0x69, 0x77, 0x01, 0xb9, 0xcc, 0x0e, 0xf2, 0xfc, + 0x9e, 0x82, 0x8f, 0xc3, + 0x53, 0xd6, 0x63, 0xe3, 0x31, 0x70, 0x63, 0xfd, 0x89, 0xc6, 0x53, 0x54, + 0xad, 0x51, 0xa5, 0xdf, + 0x05, 0x70, 0x68, 0xb8, 0x7e, 0xd6, 0x41, 0x7f, 0x0f, 0x7c, 0x2e, 0xc1, + 0x32, 0x8e, 0x00, 0xcf, + 0xd5, 0xc7, 0x51, 0x7b, 0xcd, 0x64, 0xcc, 0x5e, 0x6c, 0xdb, 0xa8, 0xef, + 0xee, 0x7b, 0x7e, 0xf2, + 0x99, 0xd1, 0x81, 0x88, 0x1f, 0xeb, 0x33, 0xaf, 0x80, 0xb5, 0x1a, 0xf4, + 0xdf, 0x32, 0x6e, 0x44, + 0x0b, 0x63, 0x2d, 0x3d, 0x85, 0xf2, 0x34, 0x5c, 0xa8, 0x3b, 0x14, 0x2b, + 0xe0, 0xc2, 0xf7, 0x0d, + 0x0a, 0xf5, 0x54, 0xc9, 0x86, 0x2f, 0x2a, 0xbb, 0x14, 0xfa, 0xf5, 0x8d, + 0x93, 0x9e, 0xd8, 0x69, + 0x9f, 0xec, 0x35, 0xb1, 0xc7, 0x47, 0x3b, 0x4d, 0xe4, 0xe3, 0x5c, 0x1f, + 0x0e, 0x9e, 0x83, 0xfe, + 0x2e, 0xf7, 0xa8, 0x9d, 0xf0, 0x91, 0xeb, 0xd3, 0xef, 0x20, 0xd2, 0x32, + 0xf5, 0x53, 0x92, 0x5c, + 0x9f, 0x75, 0xc6, 0xcb, 0x7d, 0x5c, 0x7b, 0xfc, 0xa8, 0x2b, 0xbc, 0x42, + 0x14, 0x54, 0x48, 0x95, + 0x31, 0x49, 0x62, 0x6a, 0xbb, 0x24, 0x76, 0x9b, 0xd5, 0x39, 0x22, 0xa9, + 0xa0, 0x2a, 0xaf, 0x4c, + 0x3f, 0xe5, 0x69, 0x81, 0xb3, 0xb6, 0xd8, 0x8f, 0xb6, 0x1a, 0xd0, 0x44, + 0x9e, 0xcf, 0x4e, 0x94, + 0x1b, 0xf0, 0x0d, 0x21, 0x3b, 0xfb, 0xd3, 0x16, 0x7d, 0x3a, 0x1c, 0x63, + 0x19, 0x91, 0xab, 0xdf, + 0x99, 0xb2, 0x41, 0xc1, 0xfa, 0xb6, 0x52, 0x1e, 0xbc, 0x3f, 0x48, 0xc6, + 0x53, 0x2b, 0xec, 0xd5, + 0x92, 0xb5, 0x7d, 0xdf, 0x2b, 0x0f, 0xdf, 0xf8, 0x3b, 0xde, 0xbf, 0x1f, + 0xec, 0xc4, 0x3b, 0xd3, + 0x7c, 0xfa, 0x62, 0xe5, 0x79, 0xfd, 0xac, 0xd8, 0xee, 0xf7, 0x7e, 0x56, + 0x0a, 0x9a, 0xdf, 0xc5, + 0x8e, 0x51, 0x4e, 0xdd, 0xee, 0xcb, 0x5b, 0xbd, 0x96, 0x68, 0x9d, 0x7e, + 0x8f, 0x67, 0xac, 0x9f, + 0x3c, 0x79, 0xc4, 0xc7, 0x34, 0x3c, 0xae, 0xc8, 0xef, 0x9d, 0x2a, 0x97, + 0x4c, 0x07, 0x02, 0xea, + 0x46, 0x61, 0x3b, 0x9e, 0x90, 0xe9, 0x33, 0x7e, 0x20, 0xf2, 0xef, 0x85, + 0x63, 0x57, 0xff, 0xcb, + 0xd4, 0x0f, 0xa3, 0x7d, 0xb4, 0x97, 0xa7, 0xdf, 0xfc, 0xf2, 0xdf, 0xd9, + 0x53, 0x38, 0x5f, 0xae, + 0x34, 0x67, 0x59, 0xd1, 0xcc, 0x9e, 0x33, 0x5e, 0xca, 0x8c, 0x2a, 0x89, + 0xc2, 0x66, 0xed, 0xaa, + 0xbb, 0xa6, 0xf6, 0x2e, 0xa9, 0xcc, 0x2a, 0xd1, 0x4f, 0xe3, 0x76, 0x06, + 0xbc, 0x7b, 0x7a, 0x10, + 0x3a, 0x4d, 0xfa, 0xee, 0x6a, 0x46, 0x80, 0xb7, 0x34, 0xd5, 0xfb, 0x8c, + 0xde, 0xdf, 0xb2, 0xf0, + 0xe5, 0xed, 0xac, 0xb2, 0x06, 0x4d, 0xa6, 0x59, 0xc6, 0x67, 0x04, 0x98, + 0x6b, 0xc0, 0x63, 0x12, + 0xba, 0x70, 0xad, 0xb2, 0x8b, 0xbc, 0x19, 0xd9, 0x66, 0x54, 0x0e, 0xb9, + 0x36, 0x01, 0x3f, 0x3b, + 0x08, 0xf6, 0x92, 0xa1, 0x92, 0x2d, 0x7d, 0x99, 0x9c, 0x40, 0x63, 0xc9, + 0x41, 0xe3, 0x65, 0xa4, + 0x7e, 0x27, 0xd1, 0xbb, 0x56, 0x2c, 0x1e, 0xb8, 0x0d, 0x3d, 0x57, 0xe1, + 0x39, 0x5e, 0x8a, 0xd9, + 0xe4, 0x80, 0x06, 0xbd, 0x56, 0x13, 0x76, 0x49, 0x69, 0xc3, 0x4f, 0x36, + 0xb6, 0x99, 0x88, 0x7f, + 0x8c, 0x27, 0x97, 0xa5, 0xb7, 0x91, 0xe9, 0x60, 0xd0, 0xfb, 0xbb, 0x3b, + 0xf5, 0x5d, 0x01, 0x2b, + 0x9d, 0x7e, 0xc4, 0xea, 0x2b, 0xee, 0x19, 0x07, 0xf5, 0x5b, 0x5c, 0xe9, + 0x54, 0x25, 0x99, 0x41, + 0xdf, 0x74, 0x4d, 0xd7, 0xef, 0x7d, 0xa9, 0x7b, 0x45, 0x07, 0x02, 0xae, + 0x73, 0x84, 0xd3, 0x29, + 0x79, 0xdf, 0x28, 0x97, 0xc8, 0xda, 0x2e, 0x09, 0xed, 0xaa, 0xc3, 0x53, + 0xfe, 0x54, 0x51, 0x99, + 0x5a, 0xa8, 0xdf, 0x91, 0x99, 0xab, 0xef, 0x9e, 0xb6, 0x45, 0x0b, 0x56, + 0x9b, 0x43, 0xa5, 0x9c, + 0xae, 0x9f, 0xfc, 0x59, 0x91, 0xca, 0x6a, 0x03, 0xb0, 0x8e, 0xf7, 0xf7, + 0x7e, 0xfa, 0xce, 0xe8, + 0x7e, 0x3c, 0xb6, 0xa7, 0x7e, 0x4a, 0x96, 0x1c, 0x10, 0xea, 0x5e, 0xed, + 0xdf, 0xe5, 0x7e, 0xf6, + 0xef, 0xc3, 0xee, 0x35, 0x5e, 0x25, 0xd2, 0xd4, 0x73, 0x6c, 0xdf, 0x71, + 0x59, 0xd4, 0x2b, 0x33, + 0xf4, 0x98, 0xc3, 0xfa, 0xdd, 0x87, 0x31, 0x96, 0x11, 0xea, 0x3d, 0xc4, + 0x44, 0xfc, 0x63, 0x33, + 0x36, 0x4b, 0xf4, 0xe3, 0x6c, 0x34, 0xf9, 0x6f, 0x33, 0xde, 0x19, 0x6f, + 0x69, 0x4b, 0xc3, 0x66, + 0xf3, 0xe0, 0xed, 0x10, 0xd9, 0xa7, 0x11, 0x7b, 0xfb, 0xf3, 0x96, 0x06, + 0xc7, 0xb5, 0xe8, 0xb7, + 0x42, 0x3f, 0xb9, 0x4c, 0xf6, 0x93, 0xe9, 0x70, 0x40, 0xcd, 0x28, 0xec, + 0x45, 0x37, 0x49, 0x3e, + 0x74, 0xfa, 0x60, 0xf7, 0x66, 0xcb, 0x8c, 0x03, 0x44, 0xf6, 0x20, 0xea, + 0xc5, 0xb6, 0xfa, 0xf3, + 0xcc, 0xc8, 0xa5, 0x4a, 0x7b, 0x9a, 0x88, 0x0c, 0xbc, 0xc2, 0x09, 0x5d, + 0x89, 0x15, 0x1a, 0x25, + 0x32, 0x4a, 0xc5, 0x99, 0x7a, 0xef, 0x6a, 0x52, 0x4a, 0x72, 0x81, 0xe1, + 0xd0, 0xf7, 0x60, 0x8f, + 0xb6, 0x79, 0xb2, 0xe4, 0xc2, 0x6b, 0xac, 0x5b, 0x23, 0xff, 0xa4, 0xe2, + 0x49, 0x32, 0xff, 0xe6, + 0x25, 0x41, 0x3f, 0x85, 0xf8, 0x03, 0x3b, 0x74, 0x9a, 0x65, 0xfd, 0xe7, + 0x18, 0x79, 0x54, 0x8f, + 0x9f, 0xce, 0x59, 0x6d, 0x28, 0x2d, 0x49, 0x8c, 0x8c, 0xb7, 0xcc, 0x4a, + 0x42, 0x0b, 0x51, 0xd2, + 0x89, 0x2a, 0x6c, 0x05, 0x94, 0x8f, 0x9a, 0x2b, 0xec, 0x23, 0x2e, 0x22, + 0x7d, 0x64, 0x51, 0x6f, + 0xaa, 0x3f, 0x84, 0x24, 0x47, 0xf5, 0xb8, 0x16, 0xf2, 0xa8, 0x7a, 0x56, + 0xe5, 0xed, 0x7d, 0x1e, + 0x8f, 0x79, 0x0d, 0xcf, 0x9c, 0x23, 0x43, 0x7c, 0xb4, 0x96, 0x0c, 0x9f, + 0x45, 0x44, 0x5a, 0x3d, + 0x19, 0xdd, 0xaa, 0xfb, 0xde, 0x9c, 0xc2, 0x8e, 0x6a, 0x4a, 0x3b, 0xe1, + 0x64, 0x84, 0x7e, 0x47, + 0xc2, 0xf3, 0x57, 0x20, 0x49, 0xd0, 0xeb, 0xcd, 0xce, 0xa9, 0xf6, 0xfb, + 0x68, 0x3f, 0x9d, 0xba, + 0x64, 0x3a, 0x12, 0x10, 0xea, 0xf9, 0xd4, 0x0a, 0x1f, 0x6f, 0x4b, 0xa5, + 0xb2, 0xac, 0xb6, 0x48, + 0xa6, 0x64, 0x6b, 0xa1, 0x32, 0x53, 0x7f, 0x77, 0x9e, 0xc8, 0xb8, 0x44, + 0x1f, 0x6d, 0xa8, 0xb7, + 0x34, 0x86, 0x72, 0x76, 0x18, 0x80, 0x8f, 0x05, 0x5b, 0xe3, 0x0c, 0x3b, + 0xad, 0x5d, 0x1c, 0x46, + 0xa1, 0xbc, 0xa8, 0xe2, 0x4c, 0xfd, 0x9d, 0xe0, 0xb4, 0xee, 0x31, 0x85, + 0x76, 0x9b, 0x43, 0xbd, + 0xc5, 0xb9, 0x5a, 0xce, 0x62, 0xd5, 0x40, 0x50, 0xbc, 0x55, 0xa3, 0xc1, + 0x1e, 0x44, 0xb9, 0x4b, + 0xc6, 0x68, 0xe2, 0xe4, 0x77, 0xc8, 0x93, 0xcd, 0x09, 0xf2, 0x2e, 0x5d, + 0xc7, 0xdf, 0xcd, 0xff, + 0xf1, 0x70, 0x78, 0x52, 0x8f, 0x57, 0xcf, 0x5f, 0x9e, 0xa5, 0x9e, 0xef, + 0x81, 0xd7, 0x7b, 0xfe, + 0xc2, 0x63, 0x0c, 0x9f, 0x9f, 0x92, 0xce, 0xf2, 0xbf, 0xe8, 0x7b, 0x8d, + 0x0f, 0xfd, 0xe3, 0xf8, + 0xe5, 0x26, 0x22, 0xe7, 0x2e, 0x93, 0x96, 0xaa, 0xac, 0xbb, 0xe0, 0x47, + 0x47, 0x4c, 0x0e, 0xf6, + 0xe1, 0x8f, 0xf7, 0x59, 0xfa, 0xef, 0xc2, 0x32, 0xa7, 0xe4, 0x18, 0x51, + 0x5d, 0x8a, 0x7f, 0x78, + 0xdb, 0x55, 0xcf, 0x20, 0xe2, 0x76, 0x35, 0xff, 0xde, 0x69, 0xb6, 0xdd, + 0x29, 0x8f, 0xd2, 0xa6, + 0x78, 0x3b, 0xc6, 0x5a, 0x6b, 0xb1, 0xf3, 0xed, 0xcc, 0xea, 0xa5, 0xff, + 0x8e, 0x7f, 0x00, 0xa7, + 0xd9, 0xee, 0xf2, 0x00, 0xb5, 0xdc, 0x21, 0xb4, 0xdb, 0xd3, 0x32, 0xcb, + 0x2a, 0x53, 0x60, 0xbc, + 0x86, 0x57, 0x45, 0x5b, 0xf8, 0xbe, 0x4b, 0xfe, 0xc2, 0x19, 0xd8, 0x77, + 0xfc, 0x31, 0x46, 0x6d, + 0xc1, 0x93, 0xd4, 0x59, 0x61, 0xa8, 0xe9, 0x27, 0x63, 0xf0, 0xc9, 0x27, + 0xf4, 0x1b, 0x2b, 0xc9, + 0xfa, 0x39, 0x52, 0x30, 0x9c, 0xd7, 0x6f, 0x69, 0xd8, 0x88, 0xab, 0x11, + 0xb5, 0x5d, 0x13, 0x5c, + 0xef, 0x11, 0x87, 0x8d, 0xca, 0x34, 0x72, 0x0d, 0xf5, 0xde, 0x73, 0x36, + 0xfd, 0x67, 0x7c, 0x9e, + 0xac, 0x7b, 0x71, 0x12, 0xad, 0x6d, 0x60, 0xbd, 0x7b, 0x24, 0x0c, 0xad, + 0xb7, 0x97, 0x9b, 0xf1, + 0x9c, 0x3a, 0x72, 0x80, 0xaa, 0x38, 0x5c, 0x3b, 0x96, 0x7a, 0xb3, 0x76, + 0xb5, 0xf9, 0xdc, 0xfe, + 0x14, 0x9f, 0x0e, 0xea, 0xea, 0xe5, 0x3e, 0xc6, 0x87, 0x11, 0x59, 0x1d, + 0xe5, 0x46, 0xfe, 0x7d, + 0x8c, 0x91, 0x4b, 0xb1, 0xd1, 0xeb, 0x7e, 0x2b, 0x9d, 0x82, 0xfe, 0x72, + 0x76, 0xb0, 0x74, 0xf7, + 0x3b, 0xd9, 0x8a, 0x5e, 0x11, 0x7e, 0xef, 0xed, 0x3f, 0x46, 0x85, 0x60, + 0x33, 0xfb, 0xb3, 0xc8, + 0xff, 0x4d, 0x50, 0x39, 0x0d, 0xad, 0x83, 0xec, 0x44, 0x19, 0x26, 0x32, + 0xf5, 0xb3, 0x4b, 0xf5, + 0xd4, 0xae, 0xde, 0xa7, 0x6d, 0x2a, 0xb6, 0xf2, 0xd0, 0x3a, 0xce, 0x8e, + 0x53, 0x8f, 0xae, 0xfa, + 0xcb, 0xe3, 0xd8, 0xf2, 0x51, 0xec, 0x34, 0x80, 0xda, 0x60, 0x1f, 0x3d, + 0x2d, 0xfa, 0x59, 0x92, + 0x97, 0x07, 0xab, 0x4c, 0x81, 0xa0, 0x9e, 0x9c, 0x2f, 0xd6, 0xbb, 0xba, + 0x67, 0x46, 0x25, 0xf9, + 0xf2, 0x4c, 0xc0, 0x71, 0x6b, 0xd0, 0xf0, 0x13, 0xd2, 0x15, 0x74, 0x46, + 0x13, 0x37, 0x92, 0x11, + 0x7b, 0xb0, 0xea, 0x26, 0xe8, 0xbf, 0x1e, 0x94, 0xfe, 0x69, 0x79, 0x1b, + 0x3d, 0x64, 0xc9, 0x58, + 0xc3, 0x26, 0xc3, 0xdc, 0x36, 0x53, 0x75, 0x48, 0x9f, 0xa2, 0xbc, 0x9c, + 0x2c, 0xfd, 0xf6, 0xfd, + 0x62, 0x79, 0x57, 0xce, 0x06, 0xc1, 0xeb, 0xfa, 0xfd, 0x8c, 0xdd, 0x68, + 0x76, 0x0e, 0x1e, 0xd9, + 0x84, 0xef, 0xb8, 0x5a, 0xcf, 0xb8, 0x39, 0x54, 0xfd, 0x67, 0xf5, 0xe5, + 0x9d, 0x71, 0x06, 0x4d, + 0xef, 0x45, 0xd7, 0xf3, 0xf5, 0x9d, 0xc3, 0xe5, 0xfa, 0x29, 0xb1, 0x7a, + 0x97, 0xe3, 0x8d, 0x00, + 0xf4, 0xcf, 0x58, 0x68, 0x9d, 0xd6, 0xbf, 0x9d, 0xf5, 0xa1, 0x77, 0xc6, + 0x0d, 0x57, 0xef, 0x19, + 0x68, 0x78, 0x56, 0xb4, 0xce, 0x73, 0xf5, 0xf9, 0x8e, 0xf6, 0x50, 0x7b, + 0xdd, 0x4f, 0x1a, 0xa5, + 0xc7, 0x66, 0xbd, 0xef, 0x1f, 0xc2, 0x63, 0x4e, 0xb9, 0xe9, 0x58, 0x69, + 0xb5, 0x95, 0xa9, 0xad, + 0x56, 0xac, 0x7c, 0xab, 0xcf, 0x6f, 0x04, 0x19, 0xaf, 0x68, 0x29, 0x3f, + 0xde, 0xe2, 0x7e, 0x5a, + 0xb9, 0x4c, 0x3f, 0xf3, 0x3b, 0x13, 0x50, 0x17, 0x56, 0xbc, 0x47, 0xb5, + 0x41, 0x2d, 0x44, 0x54, + 0x0d, 0x31, 0x6d, 0xd6, 0x2d, 0xa5, 0x6b, 0x55, 0x46, 0x6a, 0xba, 0x91, + 0xa6, 0xdf, 0x1e, 0x3a, + 0x8a, 0x5d, 0xcf, 0x07, 0xc4, 0x05, 0x0d, 0xf5, 0xde, 0xc9, 0x3b, 0xfa, + 0x0d, 0x95, 0xb7, 0xdc, + 0x2d, 0x6f, 0x5a, 0x70, 0x41, 0xbf, 0xe1, 0x63, 0x1d, 0xff, 0xa6, 0x7e, + 0x8b, 0xc7, 0x35, 0x47, + 0xfd, 0xff, 0x96, 0xdf, 0x28, 0x5f, 0xfa, 0x6f, 0x06, 0xa5, 0x76, 0x3e, + 0xe0, 0x5a, 0x17, 0x7c, + 0xd6, 0xf1, 0xef, 0xbb, 0x12, 0xde, 0xde, 0x72, 0x23, 0xd8, 0xac, 0x60, + 0xdc, 0xb6, 0xa5, 0x74, + 0xb9, 0xf1, 0xde, 0x15, 0x5d, 0xda, 0x78, 0x47, 0x6b, 0xe3, 0xc2, 0x65, + 0xe8, 0x9f, 0x97, 0x0f, + 0xc9, 0x64, 0x54, 0x2a, 0x46, 0xa6, 0x0c, 0xf6, 0xd8, 0xcc, 0xbd, 0xa7, + 0x65, 0xda, 0x93, 0x1d, + 0xc9, 0xd8, 0xcc, 0x2e, 0x9f, 0x6a, 0x5a, 0x21, 0xfc, 0x56, 0xf0, 0x29, + 0xf5, 0x21, 0xb5, 0x17, + 0x31, 0x35, 0xb0, 0xc6, 0x6b, 0xb3, 0x6e, 0xb3, 0xba, 0x46, 0x8c, 0x74, + 0x8c, 0xb1, 0xab, 0x9d, + 0x31, 0x82, 0xea, 0xe9, 0x22, 0xf1, 0xf8, 0xf3, 0xe1, 0x03, 0xf9, 0x38, + 0xf4, 0x4d, 0x11, 0xd7, + 0x80, 0xef, 0xd8, 0xc5, 0xe3, 0x24, 0xd1, 0x18, 0x23, 0x03, 0x2c, 0x71, + 0xa6, 0xce, 0x69, 0xb7, + 0x97, 0x8f, 0x49, 0x8b, 0x33, 0xe2, 0xe8, 0x7d, 0x41, 0x56, 0xc9, 0xd7, + 0xf2, 0x2f, 0x74, 0xfd, + 0x73, 0xe0, 0x13, 0x72, 0xc0, 0x0a, 0x7d, 0xaf, 0x2e, 0x84, 0x9f, 0x86, + 0x4d, 0xfa, 0x6f, 0x3d, + 0xe3, 0x8c, 0x44, 0xe9, 0x67, 0xb5, 0x19, 0xe8, 0x3a, 0xed, 0xb1, 0x98, + 0x04, 0x7b, 0xb4, 0x43, + 0xfd, 0x65, 0xe4, 0x10, 0x2a, 0x8c, 0x6f, 0x88, 0x8e, 0x8f, 0xae, 0x19, + 0x17, 0xc9, 0xc6, 0x71, + 0x32, 0x8c, 0xda, 0x3e, 0x84, 0x9f, 0x8e, 0xd1, 0x54, 0xdf, 0xd1, 0xc4, + 0x53, 0x9f, 0xda, 0xb0, + 0x78, 0x9f, 0xef, 0x9a, 0x20, 0x3f, 0xf6, 0x2d, 0x88, 0xc9, 0x55, 0xdf, + 0xa4, 0x13, 0x81, 0x96, + 0xd7, 0x49, 0xab, 0x7c, 0x46, 0x2e, 0xbd, 0x16, 0xa8, 0x68, 0x4d, 0x22, + 0x6e, 0x23, 0x43, 0xb8, + 0x76, 0x18, 0xd1, 0xf2, 0x4c, 0x6d, 0x58, 0x82, 0xff, 0xf7, 0xff, 0x75, + 0x9d, 0x34, 0x78, 0x4c, + 0xa4, 0xe1, 0xfa, 0xe6, 0xaa, 0x7e, 0x9c, 0xad, 0xd4, 0x77, 0xc4, 0x7d, + 0xfe, 0x13, 0x71, 0x51, + 0x7e, 0xe4, 0x3c, 0x38, 0x44, 0x46, 0xb8, 0xbf, 0x0b, 0x2b, 0xd2, 0x1e, + 0xe9, 0x08, 0x5d, 0xd7, + 0x70, 0xd9, 0xa2, 0x1c, 0x6d, 0x6c, 0xa6, 0x63, 0x2d, 0x7c, 0xd4, 0x73, + 0x32, 0xca, 0xfe, 0x82, + 0x28, 0x0c, 0xe4, 0x04, 0xf8, 0xa5, 0xfe, 0x0b, 0xba, 0x2f, 0xae, 0x1a, + 0xdf, 0x32, 0x6f, 0x89, + 0x0c, 0xc6, 0x62, 0x8a, 0xd2, 0x8b, 0xf6, 0x91, 0xd2, 0xab, 0xac, 0x57, + 0x7a, 0xaf, 0xf2, 0x5f, + 0xfb, 0x7a, 0x2a, 0xbd, 0x7b, 0x45, 0xf7, 0xb4, 0xee, 0xe5, 0xbd, 0xd2, + 0x2e, 0x37, 0xb6, 0x67, + 0x39, 0xe3, 0x18, 0xdb, 0xd3, 0x6c, 0x7b, 0x32, 0xfd, 0x91, 0xca, 0x47, + 0x52, 0x1f, 0xa9, 0xe8, + 0xc1, 0xdc, 0x9e, 0xf4, 0xf7, 0xcc, 0xe8, 0xf9, 0x4b, 0xca, 0x54, 0xd6, + 0x3b, 0xfd, 0xe1, 0xba, + 0xf0, 0x98, 0x40, 0xdf, 0xb5, 0x19, 0x36, 0xe9, 0xd9, 0xa4, 0x17, 0xec, + 0xc3, 0x1d, 0xc3, 0x65, + 0xb8, 0x0c, 0x92, 0x01, 0xd4, 0x23, 0xea, 0xef, 0x51, 0xbf, 0xba, 0x0a, + 0xa8, 0xbf, 0x83, 0x3d, + 0x2b, 0x29, 0xd2, 0x87, 0x0c, 0x0b, 0x15, 0x03, 0xbb, 0x95, 0xdd, 0x93, + 0xde, 0xb5, 0x21, 0x2c, + 0x22, 0x2c, 0x74, 0x5d, 0xf3, 0x15, 0xf0, 0xfb, 0x36, 0x89, 0xb5, 0x5e, + 0x05, 0x2f, 0xd8, 0x86, + 0x1a, 0x43, 0xf5, 0x77, 0x04, 0x3c, 0xad, 0x9f, 0x98, 0xb4, 0xea, 0xbf, + 0x66, 0xfd, 0xe6, 0x32, + 0xf8, 0xd6, 0xfd, 0x2d, 0xaa, 0xd5, 0xd8, 0x6b, 0xa0, 0x0c, 0xd5, 0x18, + 0x0e, 0x9d, 0xbb, 0x66, + 0x86, 0x8f, 0x0e, 0x7d, 0x33, 0xe6, 0xf5, 0xfd, 0x5e, 0xdb, 0xae, 0x75, + 0xff, 0x88, 0x1b, 0x6a, + 0x1b, 0x22, 0xcf, 0x81, 0xc1, 0xc4, 0x5a, 0x0f, 0xf6, 0xb7, 0x55, 0x3a, + 0x4f, 0xba, 0x6c, 0xd7, + 0xf6, 0x1b, 0xa4, 0x3d, 0xdf, 0x4f, 0x7c, 0x58, 0xf2, 0x19, 0xdd, 0x97, + 0x59, 0x6a, 0xee, 0x73, + 0xf6, 0x61, 0x8e, 0xbe, 0x13, 0xc3, 0x93, 0xc2, 0xab, 0x43, 0xdf, 0x6f, + 0x7b, 0xdd, 0xbf, 0xdb, + 0x96, 0x58, 0xbb, 0xb3, 0xe2, 0xd9, 0xd4, 0x21, 0xf6, 0x41, 0x0e, 0xd7, + 0x37, 0x32, 0xf4, 0x97, + 0xa7, 0xa8, 0x4a, 0xb2, 0x65, 0x99, 0xbc, 0x1d, 0xf0, 0x6f, 0xf9, 0x2f, + 0xca, 0x3e, 0xa9, 0x60, + 0xf7, 0x7a, 0x52, 0x47, 0x98, 0x9e, 0x63, 0x0c, 0x96, 0xa1, 0xc5, 0x0f, + 0x67, 0x87, 0xcf, 0xea, + 0x36, 0x2a, 0xa4, 0xd1, 0x5f, 0x26, 0xd6, 0xc2, 0x67, 0x85, 0x47, 0x3c, + 0x58, 0x3c, 0x30, 0x7b, + 0xa0, 0x7d, 0x80, 0x0c, 0x70, 0x7f, 0xf7, 0xf0, 0x33, 0xd8, 0xe4, 0x31, + 0x79, 0x1c, 0xdb, 0x64, + 0x4a, 0x91, 0x4c, 0x90, 0x49, 0x52, 0xc6, 0x19, 0x3d, 0x9a, 0xfc, 0xf9, + 0x88, 0x74, 0x97, 0xde, + 0xc4, 0x97, 0x7b, 0xac, 0xf1, 0xac, 0x0c, 0xca, 0x7f, 0xca, 0x76, 0x9b, + 0x33, 0x3c, 0xa2, 0x5b, + 0x28, 0xc6, 0x7e, 0x59, 0xbb, 0x39, 0x6f, 0x8d, 0x78, 0xb4, 0x70, 0x60, + 0xee, 0xb3, 0xf6, 0xfe, + 0xe2, 0x85, 0x7a, 0x7a, 0xd7, 0x5b, 0x7a, 0x49, 0x4f, 0x62, 0xaf, 0x27, + 0x9f, 0x9e, 0xd1, 0xdf, + 0x28, 0x6d, 0x02, 0x1b, 0x0f, 0x32, 0x7a, 0x19, 0xf7, 0xcc, 0x08, 0x8f, + 0x0a, 0xd9, 0xeb, 0xd7, + 0x8a, 0xb7, 0x6e, 0xa3, 0x1e, 0x1c, 0xff, 0x74, 0x66, 0x7f, 0x5b, 0xbf, + 0xfc, 0xbe, 0x46, 0x5f, + 0x09, 0x0a, 0xfa, 0xfa, 0xd9, 0xfa, 0x3b, 0xfa, 0x16, 0x3e, 0x9e, 0x7b, + 0x47, 0x7d, 0xd8, 0xe8, + 0x50, 0x4e, 0xfc, 0xd5, 0xf3, 0xe4, 0xa8, 0x3b, 0x26, 0x3f, 0x9c, 0xd0, + 0xd3, 0x20, 0xca, 0xf2, + 0xfa, 0xe6, 0xf7, 0xb5, 0xf7, 0x71, 0xf4, 0x31, 0xfa, 0x88, 0xbe, 0xec, + 0x7d, 0x1d, 0x7d, 0x6d, + 0xfd, 0x1c, 0xfd, 0xed, 0xcf, 0x38, 0x9e, 0xa8, 0xbc, 0x2f, 0x45, 0xed, + 0x85, 0xa1, 0xf8, 0xfa, + 0x6d, 0xd8, 0x4d, 0xd9, 0x22, 0xac, 0xa1, 0xdb, 0xa8, 0x3b, 0x6a, 0xef, + 0x8f, 0x7f, 0xa8, 0xf4, + 0xb1, 0x8c, 0x7f, 0x16, 0xf6, 0x18, 0xdb, 0xa3, 0xb0, 0x7b, 0xee, 0xe3, + 0xe3, 0xff, 0x91, 0xf5, + 0xc0, 0xa4, 0xbb, 0x93, 0x6e, 0x65, 0xff, 0x53, 0x7b, 0x60, 0xb7, 0x50, + 0x7c, 0xfd, 0x26, 0x6d, + 0x17, 0xde, 0xc0, 0xd5, 0x88, 0x8d, 0xd4, 0xa5, 0x3e, 0x63, 0xa7, 0x90, + 0xad, 0x42, 0x08, 0x21, + 0x30, 0xfe, 0x1f, 0x7e, 0x26, 0xe7, 0x5b +}; diff --git a/source/ngc/dvd.cpp b/source/ngc/dvd.cpp new file mode 100644 index 0000000..e44c56c --- /dev/null +++ b/source/ngc/dvd.cpp @@ -0,0 +1,369 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube DVD + * + * softdev July 2006 + * svpe & crunchy2 June 2007 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "snes9xGx.h" + +/** DVD I/O Address base **/ +volatile unsigned long *dvd = (volatile unsigned long *) 0xCC006000; + + /** Due to lack of memory, we'll use this little 2k keyhole for all DVD operations **/ +unsigned char DVDreadbuffer[2048] ATTRIBUTE_ALIGN (32); +unsigned char dvdbuffer[2048]; + +/** + * dvd_driveid + * + * Gets and returns the dvd driveid +**/ +static unsigned char *inquiry=(unsigned char *)0x80000004; + +int dvd_driveid() +{ + dvd[0] = 0x2e; + dvd[1] = 0; + dvd[2] = 0x12000000; + dvd[3] = 0; + dvd[4] = 0x20; + dvd[5] = 0x80000000; + dvd[6] = 0x20; + dvd[7] = 3; + + while( dvd[7] & 1 ) + ; + DCFlushRange((void *)0x80000000, 32); + + return (int)inquiry[2]; +} + + /** + * dvd_read + * + * The only DVD function we need - you gotta luv gc-linux self-boots! + */ +int +dvd_read (void *dst, unsigned int len, u64 offset) +{ + + unsigned char *buffer = (unsigned char *) (unsigned int) DVDreadbuffer; + + if (len > 2048) + return 1; /*** We only allow 2k reads **/ + + DCInvalidateRange ((void *) buffer, len); + + if(offset < 0x57057C00 || (isWii == true && offset < 0x118244F00LL)) // don't read past the end of the DVD + { + offset >>= 2; + dvd[0] = 0x2E; + dvd[1] = 0; + dvd[2] = 0xA8000000; + dvd[3] = (u32)offset; + dvd[4] = len; + dvd[5] = (unsigned long) buffer; + dvd[6] = len; + dvd[7] = 3; /*** Enable reading with DMA ***/ + while (dvd[7] & 1); + memcpy (dst, buffer, len); + } + else // Let's not read past end of DVD + return 0; + + if (dvd[0] & 0x4) /* Ensure it has completed */ + return 0; + + return 1; + +} + +/** Minimal ISO Directory Definition **/ +#define RECLEN 0 /* Record length */ +#define EXTENT 6 /* Extent */ +#define FILE_LENGTH 14 /* File length (BIG ENDIAN) */ +#define FILE_FLAGS 25 /* File flags */ +#define FILENAME_LENGTH 32 /* Filename length */ +#define FILENAME 33 /* ASCIIZ filename */ + +/** Minimal Primary Volume Descriptor **/ +#define PVDROOT 0x9c +static int IsJoliet = 0; +u64 rootdir = 0; +int rootdirlength = 0; + +/** Global file entry table **/ +FILEENTRIES filelist[MAXFILES]; + +/** + * Primary Volume Descriptor + * + * The PVD should reside between sector 16 and 31. + * This is for single session DVD only. + */ +int +getpvd () +{ + int sector = 16; + u32 rootdir32; + + rootdir = rootdirlength = 0; + IsJoliet = -1; + + /** Look for Joliet PVD first **/ + while (sector < 32) + { + if (dvd_read (dvdbuffer, 2048, (u64)(sector << 11))) + { + if (memcmp (&dvdbuffer, "\2CD001\1", 8) == 0) + { + memcpy(&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); + rootdir = (u64)rootdir32; + rootdir <<= 11; + memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); + IsJoliet = 1; + break; + } + } + else + return 0; /*** Can't read sector! ***/ + + sector++; + } + + if (IsJoliet > 0) /*** Joliet PVD Found ? ***/ + return 1; + + sector = 16; + + /*** Look for standard ISO9660 PVD ***/ + while (sector < 32) + { + if (dvd_read (&dvdbuffer, 2048, sector << 11)) + { + if (memcmp (&dvdbuffer, "\1CD001\1", 8) == 0) + { + memcpy (&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); + rootdir = (u64)rootdir32; + rootdir <<= 11; + memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); + IsJoliet = 0; + break; + } + } + else + return 0; /*** Can't read sector! ***/ + + sector++; + + } + + return (IsJoliet == 0); + +} + +/** + * getentry + * + * Support function to return the next file entry, if any + * Declared static to avoid accidental external entry. + */ +static int diroffset = 0; +static int +getentry (int entrycount) +{ + char fname[512]; /* Huge, but experience has determined this */ + char *ptr; + char *filename; + char *filenamelength; + char *rr; + int j; + u32 offset32; + + /* Basic checks */ + if (entrycount >= MAXFILES) + return 0; + + if (diroffset >= 2048) + return 0; + + /** Decode this entry **/ + if (dvdbuffer[diroffset]) /* Record length available */ + { + /* Update offsets into sector buffer */ + ptr = (char *) &dvdbuffer[0]; + ptr += diroffset; + filename = ptr + FILENAME; + filenamelength = ptr + FILENAME_LENGTH; + + /* Check for wrap round - illegal in ISO spec, + * but certain crap writers do it! */ + if ((diroffset + dvdbuffer[diroffset]) > 2048) + return 0; + + if (*filenamelength) + { + memset (&fname, 0, 512); + + if (!IsJoliet) /*** Do ISO 9660 first ***/ + strcpy (fname, filename); + else + { /*** The more tortuous unicode joliet entries ***/ + + for (j = 0; j < (*filenamelength >> 1); j++) + { + fname[j] = filename[j * 2 + 1]; + } + + fname[j] = 0; + + if (strlen (fname) >= MAXJOLIET) + fname[MAXJOLIET] = 0; + + if (strlen (fname) == 0) + fname[0] = filename[0]; + } + + if (strlen (fname) == 0) + strcpy (fname, "ROOT"); + else + { + if (fname[0] == 1) + strcpy (fname, ".."); + else + { /* + * Move *filenamelength to t, + * Only to stop gcc warning for noobs :) + */ + int t = *filenamelength; + fname[t] = 0; + } + } + + /** Rockridge Check **/ + rr = strstr (fname, ";"); + if (rr != NULL) + *rr = 0; + + strcpy (filelist[entrycount].filename, fname); + fname[MAXDISPLAY] = 0; + strcpy (filelist[entrycount].displayname, fname); + + memcpy (&offset32, + &dvdbuffer[diroffset + EXTENT], 4); + filelist[entrycount].offset = (u64)offset32; + memcpy (&filelist[entrycount].length, + &dvdbuffer[diroffset + FILE_LENGTH], 4); + memcpy (&filelist[entrycount].flags, + &dvdbuffer[diroffset + FILE_FLAGS], 1); + + filelist[entrycount].offset <<= 11; + filelist[entrycount].flags = filelist[entrycount].flags & 2; + + /*** Prepare for next entry ***/ + diroffset += dvdbuffer[diroffset]; + + return 1; + + } + + } + + return 0; + +} + +/** + * parsedirectory + * + * This function will parse the directory tree. + * It relies on rootdir and rootdirlength being pre-populated by a call to + * getpvd, a previous parse or a menu selection. + * + * The return value is number of files collected, or 0 on failure. + */ +int +parsedirectory () +{ + int pdlength; + u64 pdoffset; + u64 rdoffset; + int len = 0; + int filecount = 0; + + pdoffset = rdoffset = rootdir; + pdlength = rootdirlength; + filecount = 0; + + /*** Clear any existing values ***/ + memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES); + + /*** Get as many files as possible ***/ + while (len < pdlength) + { + if (dvd_read (&dvdbuffer, 2048, pdoffset) == 0) + return 0; + + diroffset = 0; + + while (getentry (filecount)) + { + if (filecount < MAXFILES) + filecount++; + } + + len += 2048; + pdoffset = rdoffset + len; + } + + return filecount; +} +/**************************************************************************** + * uselessinquiry + * + * As the name suggests, this function is quite useless. + * It's only purpose is to stop any pending DVD interrupts while we use the + * memcard interface. + * + * libOGC tends to foul up if you don't, and sometimes does if you do! + ****************************************************************************/ +void uselessinquiry () +{ + + dvd[0] = 0; + dvd[1] = 0; + dvd[2] = 0x12000000; + dvd[3] = 0; + dvd[4] = 0x20; + dvd[5] = 0x80000000; + dvd[6] = 0x20; + dvd[7] = 1; + + while (dvd[7] & 1); +} + +void dvd_motor_off( ) +{ + dvd[0] = 0x2e; + dvd[1] = 0; + dvd[2] = 0xe3000000; + dvd[3] = 0; + dvd[4] = 0; + dvd[5] = 0; + dvd[6] = 0; + dvd[7] = 1; // Do immediate + while (dvd[7] & 1); + + /*** PSO Stops blackscreen at reload ***/ + dvd[0] = 0x14; + dvd[1] = 0; +} + diff --git a/source/ngc/dvd.h b/source/ngc/dvd.h new file mode 100644 index 0000000..f8033b2 --- /dev/null +++ b/source/ngc/dvd.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube DVD + * + * softdev July 2006 + * svpe & crunchy2 June 2007 + ****************************************************************************/ + +#ifndef _NGCDVD_ +#define _NGCDVD_ + +#define MAXJOLIET 255 +#define MAXDISPLAY 54 +typedef struct +{ + u64 offset; + unsigned int length; + char flags; + char filename[MAXJOLIET + 1]; + char displayname[MAXDISPLAY + 1]; +} FILEENTRIES; + +extern u64 rootdir; +extern int rootdirlength; +#define MAXFILES 2000 /** Restrict to 2000 files per dir **/ + +extern int getpvd (); +extern int parsedirectory (); +extern FILEENTRIES filelist[MAXFILES]; + +int dvd_driveid(); + +int dvd_read (void *dst, unsigned int len, u64 offset); +extern void dvd_motor_off (); + +#endif diff --git a/source/ngc/filesel.cpp b/source/ngc/filesel.cpp new file mode 100644 index 0000000..2fdadb8 --- /dev/null +++ b/source/ngc/filesel.cpp @@ -0,0 +1,474 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Filesel - borrowed from GPP + * + * softdev July 2006 + * svpe June 2007 + * crunchy2 May-July 2007 + ****************************************************************************/ +#include +#include +#include +#include + +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" +#include "controls.h" + +#include "snes9xGx.h" +#include "dvd.h" +#include "ftfont.h" +#include "video.h" +#include "aram.h" +#include "ngcunzip.h" +#include "filesel.h" +#include "smbload.h" +#include "sdload.h" +#include "mcsave.h" + +#define PAGESIZE 17 +static int maxfiles; +int havedir = 0; +int hasloaded = 0; +int loadtype = 0; +int LoadDVDFile (unsigned char *buffer); +int haveSDdir = 0; +extern unsigned long ARAM_ROMSIZE; +extern int screenheight; + +/** + * Showfile screen + * + * Display the file selection to the user + */ +static void +ShowFiles (int offset, int selection) +{ + int i, j; + char text[80]; + int ypos; + int w; + + clearscreen (); + + setfontsize (16); + + ypos = (screenheight - ((PAGESIZE - 1) * 20)) >> 1; + + if (screenheight == 480) + ypos += 24; + else + ypos += 10; + + j = 0; + for (i = offset; i < (offset + PAGESIZE) && (i < maxfiles); i++) + + { + if (filelist[i].flags) + + { + strcpy (text, "["); + strcat (text, filelist[i].displayname); + strcat (text, "]"); + } + + else + strcpy (text, filelist[i].displayname); + if (j == (selection - offset)) + + { + + /*** Highlighted text entry ***/ + for ( w = 0; w < 20; w++ ) + DrawLineFast( 30, 610, ( j * 20 ) + (ypos-16) + w, 0x80, 0x80, 0x80 ); + + setfontcolour (0x00, 0x00, 0xe0); + DrawText (-1, (j * 20) + ypos, text); + setfontcolour (0x00, 0x00, 0x00); + } + + else + + { + /*** Normal entry ***/ + DrawText (-1, (j * 20) + ypos, text); + } + j++; + } + showscreen (); + + setfontsize (24); + +} + +/** +* SNESROMSOffset +* +* Function to check for and return offset to a directory called SNESROMS, if +* any +*/ +int SNESROMSOffset() +{ + int i; + + for ( i = 0; i < maxfiles; i++ ) + if (strcmp(filelist[i].filename, "SNESROMS") == 0) + return i; + return 0; +} + +/** + * FileSelector + * + * Let user select a file from the DVD listing + */ +int offset = 0; +int selection = 0; + +#define PADCAL 40 +int +FileSelector () +{ + short p; + signed char a; + int haverom = 0; + int redraw = 1; + int selectit = 0; + + while (haverom == 0) + { + if (redraw) + ShowFiles (offset, selection); + redraw = 0; + p = PAD_ButtonsDown (0); + a = PAD_StickY (0); + if ((p & PAD_BUTTON_A) || selectit) + { + if ( selectit ) + selectit = 0; + if (filelist[selection].flags) /*** This is directory ***/ + { + if (loadtype == LOAD_SDC) + { + /* memorize last entries list, actual root directory and selection for next access */ + haveSDdir = 1; + + /* update current directory and set new entry list if directory has changed */ + int status = updateSDdirname(); + if (status == 1) + { + maxfiles = parseSDdirectory(); + if (!maxfiles) + { + WaitPrompt ("Error reading directory !"); + haverom = 1; // quit SD menu + haveSDdir = 0; // reset everything at next access + } + } + else if (status == -1) + { + haverom = 1; // quit SD menu + haveSDdir = 0; // reset everything at next access + } + } + else + { + if ( (strcmp (filelist[selection].filename, "..") == 0) + && ((unsigned int)rootdir == filelist[selection].offset) ) + return 0; + else + { + rootdir = filelist[selection].offset; + rootdirlength = filelist[selection].length; + offset = selection = 0; + maxfiles = parsedirectory (); + } + } + } + else + { + rootdir = filelist[selection].offset; + rootdirlength = filelist[selection].length; + + switch (loadtype) + { + case LOAD_DVD: + /*** Now load the DVD file to it's offset ***/ + ARAM_ROMSIZE = LoadDVDFile (Memory.ROM); + break; + + case LOAD_SMB: + /*** Load from SMB ***/ + ARAM_ROMSIZE = + LoadSMBFile (filelist[selection].filename, + filelist[selection].length); + break; + + case LOAD_SDC: + /*** Load from SD Card ***/ + /* memorize last entries list, actual root directory and selection for next access */ + haveSDdir = 1; + ARAM_ROMSIZE = LoadSDFile (filelist[selection].filename, + filelist[selection].length); + break; + } + + if (ARAM_ROMSIZE > 0) + { + hasloaded = 1; + Memory.LoadROM ("BLANK.SMC"); + + Memory.LoadSRAM ("BLANK"); + haverom = 1; + + return 1; + } + else + { + WaitPrompt("Error loading ROM!"); + } + } + redraw = 1; + } + if ( p & PAD_BUTTON_B ) + { + while ( PAD_ButtonsDown(0) & PAD_BUTTON_B ) + VIDEO_WaitVSync(); + if ((strcmp(filelist[1].filename,"..") == 0) && (strlen (filelist[0].filename) != 0)) + selection = selectit = 1; + else + return 0; + } + if ((p & PAD_BUTTON_DOWN) || (a < -PADCAL)) + { + selection++; + if (selection == maxfiles) + selection = offset = 0; + if ((selection - offset) >= PAGESIZE) + offset += PAGESIZE; + redraw = 1; + } // End of down + if ((p & PAD_BUTTON_UP) || (a > PADCAL)) + { + selection--; + if (selection < 0) + { + selection = maxfiles - 1; + offset = selection - PAGESIZE + 1; + } + if (selection < offset) + offset -= PAGESIZE; + if (offset < 0) + offset = 0; + redraw = 1; + } // End of Up + if (PAD_ButtonsHeld (0) & PAD_BUTTON_LEFT) + { + /*** Go back a page ***/ + selection -= PAGESIZE; + if (selection < 0) + { + selection = maxfiles - 1; + offset = selection - PAGESIZE + 1; + } + if (selection < offset) + offset -= PAGESIZE; + if (offset < 0) + offset = 0; + redraw = 1; + } + if (PAD_ButtonsHeld (0) & PAD_BUTTON_RIGHT) + { + /*** Go forward a page ***/ + selection += PAGESIZE; + if (selection > maxfiles - 1) + selection = offset = 0; + if ((selection - offset) >= PAGESIZE) + offset += PAGESIZE; + redraw = 1; + } + } + return 0; +} + +/** + * OpenDVD + * + * Function to load a DVD directory and display to user. + */ +int +OpenDVD () +{ + int romsdiroffset = 0; + + loadtype = LOAD_DVD; + + if (!getpvd()) + { + ShowAction("Mounting DVD ... Wait"); + DVD_Mount(); /* mount the DVD unit again */ + havedir = 0; /* this may be a new DVD: content need to be parsed again */ + if (!getpvd()) + return 0; /* no correct ISO9660 DVD */ + } + + if (havedir == 0) + { + offset = selection = 0; /* reset file selector */ + haveSDdir = 0; /* prevent conflicts with SDCARD file selector */ + + if ((maxfiles = parsedirectory ())) + { + if ( romsdiroffset = SNESROMSOffset() ) + { + rootdir = filelist[romsdiroffset].offset; + rootdirlength = filelist[romsdiroffset].length; + offset = selection = 0; + maxfiles = parsedirectory (); + } + + int ret = FileSelector (); + havedir = 1; + return ret; + } + } + + else + return FileSelector (); + + return 0; +} + +/** + * OpenSMB + * + * Function to load from an SMB share + */ +int +OpenSMB () +{ + loadtype = LOAD_SMB; + + if ((maxfiles = parseSMBDirectory ())) + { + char txt[80]; + sprintf(txt,"maxfiles = %d", maxfiles); + + return FileSelector (); + } + return 0; +} + +/** + * OpenSD + * + * Function to load from an SD Card + */ +int +OpenSD (int slot) +{ + char msg[80]; + + loadtype = LOAD_SDC; + + if (haveSDdir == 0) + { + /* don't mess with DVD entries */ + havedir = 0; + + /* Initialise libOGC SD functions */ + SDCARD_Init (); + + /* Reset SDCARD root directory */ + sprintf(rootSDdir,"dev%d:\\SNESROMS", slot); + + /* Parse initial root directory and get entries list */ + if ((maxfiles = parseSDdirectory ())) + { + /* Select an entry */ + return FileSelector (); + } + else + { + /* no entries found */ + sprintf (msg, "SNESROMS not found on SDCARD (slot %s)", slot ? "B" : "A"); + WaitPrompt (msg); + return 0; + } + } + /* Retrieve previous entries list and made a new selection */ + else + return FileSelector (); + + return 0; +} + + +/** + * LoadDVDFile + * + * This function will load a file from DVD, in BIN, SMD or ZIP format. + * The values for offset and length are inherited from rootdir and + * rootdirlength. + * + * The buffer parameter should re-use the initial ROM buffer. + */ +int +LoadDVDFile (unsigned char *buffer) +{ + int offset; + int blocks; + int i; + u64 discoffset; + char readbuffer[2048]; + + /*** SDCard Addition ***/ + if (rootdirlength == 0) + return 0; + + /*** How many 2k blocks to read ***/ + blocks = rootdirlength / 2048; + offset = 0; + discoffset = rootdir; + ShowAction ("Loading ... Wait"); + dvd_read (readbuffer, 2048, discoffset); + + if (!IsZipFile (readbuffer)) + + { + for (i = 0; i < blocks; i++) + + { + dvd_read (readbuffer, 2048, discoffset); + memcpy (buffer + offset, readbuffer, 2048); + offset += 2048; + discoffset += 2048; + } + + /*** And final cleanup ***/ + if (rootdirlength % 2048) + + { + i = rootdirlength % 2048; + dvd_read (readbuffer, 2048, discoffset); + memcpy (buffer + offset, readbuffer, i); + } + } + + else + + { + return UnZipBuffer (buffer, discoffset, rootdirlength); + } + return rootdirlength; +} diff --git a/source/ngc/filesel.h b/source/ngc/filesel.h new file mode 100644 index 0000000..79e1e8d --- /dev/null +++ b/source/ngc/filesel.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Filesel - borrowed from GPP + * + * softdev July 2006 + * crunchy2 May 2007 + ****************************************************************************/ + +#ifndef _NGCFILESEL_ +#define _NGCFILESEL_ + +int OpenDVD (); +int OpenSMB (); +int OpenSD (int slot); + +#define LOAD_DVD 1 +#define LOAD_SMB 2 +#define LOAD_SDC 4 +#define SNESROMDIR "SNESROMS" +#define SNESSAVEDIR "SNESSAVE" + +#endif diff --git a/source/ngc/fontface.s b/source/ngc/fontface.s new file mode 100644 index 0000000..d0d88ed --- /dev/null +++ b/source/ngc/fontface.s @@ -0,0 +1,12 @@ +# Fonts + +.rodata +.globl fontface +.balign 32 +fontface: +.incbin "../source/ngc/ttf/font.ttf" + + +.globl fontsize +fontsize: .long 28736 + diff --git a/source/ngc/ftfont.cpp b/source/ngc/ftfont.cpp new file mode 100644 index 0000000..2dfd453 --- /dev/null +++ b/source/ngc/ftfont.cpp @@ -0,0 +1,818 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Screen Font Driver + * + * Uses libfreetype 2.2.1 compiled for GC with TTF support only. + * TTF only reduces the library by some 900k bytes! + * + * Visit - http://www.freetype.org ! + * + * **WARNING*** + * + * ONLY USE GUARANTEED PATENT FREE FONTS. + * THOSE IN YOUR WINDOWS\FONTS DIRECTORY ARE COPYRIGHT + * AND MAY NOT BE DISTRIBUTED! + * + * softdev July 2006 + * crunchy2 June 2007 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include FT_FREETYPE_H +#include "video.h" +#include "ftfont.h" +#include "dkpro.h" +#include "tempgfx.h" + +#include "aram.h" +#include + +/*** Globals ***/ +FT_Library ftlibrary; +FT_Face face; +FT_GlyphSlot slot; +FT_UInt glyph_index; +static unsigned int fonthi, fontlo; + +extern char fontface[]; /*** From fontface.s ***/ +extern int fontsize; /*** From fontface.s ***/ +extern int screenheight; +extern unsigned int *xfb[2]; +extern int whichfb; + +/** + * Unpack the devkit pro logo + */ +static u32 *dkproraw; +static u32 *backdrop; /*** Permanent backdrop ***/ +static void unpackbackdrop (); +unsigned int getcolour (u8 r1, u8 g1, u8 b1); +void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b ); +u32 getrgb( u32 ycbr, u32 low ); + +/** + * Initialisation of libfreetype + */ +int +FT_Init () +{ + + int err; + + err = FT_Init_FreeType (&ftlibrary); + if (err) + return 1; + + err = + FT_New_Memory_Face (ftlibrary, (FT_Byte *) fontface, fontsize, 0, &face); + if (err) + return 1; + + setfontsize (16); + + slot = face->glyph; + + return 0; + +} + +/** + * setfontsize + * + * Set the screen font size in pixels + */ +void +setfontsize (int pixelsize) +{ + int err; + + err = FT_Set_Pixel_Sizes (face, 0, pixelsize); + + if (err) + printf ("Error setting pixel sizes!"); +} + +static void +DrawCharacter (FT_Bitmap * bmp, FT_Int x, FT_Int y) +{ + FT_Int i, j, p, q; + FT_Int x_max = x + bmp->width; + FT_Int y_max = y + bmp->rows; + int spos; + unsigned int pixel; + int c; + + for (i = x, p = 0; i < x_max; i++, p++) + { + for (j = y, q = 0; j < y_max; j++, q++) + { + if (i < 0 || j < 0 || i >= 640 || j >= screenheight) + continue; + + /*** Convert pixel position to GC int sizes ***/ + spos = (j * 320) + (i >> 1); + + pixel = xfb[whichfb][spos]; + c = bmp->buffer[q * bmp->width + p]; + + /*** Cool Anti-Aliasing doesn't work too well at hires on GC ***/ + if (c > 128) + { + if (i & 1) + pixel = (pixel & 0xffff0000) | fontlo; + else + pixel = ((pixel & 0xffff) | fonthi); + + xfb[whichfb][spos] = pixel; + } + } + } +} + +/** + * DrawText + * + * Place the font bitmap on the screen + */ +void +DrawText (int x, int y, char *text) +{ + int px, n; + int i; + int err; + int value, count; + + n = strlen (text); + if (n == 0) + return; + + /*** x == -1, auto centre ***/ + if (x == -1) + { + value = 0; + px = 0; + } + else + { + value = 1; + px = x; + } + + for (count = value; count < 2; count++) + { + /*** Draw the string ***/ + for (i = 0; i < n; i++) + { + err = FT_Load_Char (face, text[i], FT_LOAD_RENDER); + + if (err) + { + printf ("Error %c %d\n", text[i], err); + continue; /*** Skip unprintable characters ***/ + } + + if (count) + DrawCharacter (&slot->bitmap, px + slot->bitmap_left, + y - slot->bitmap_top); + + px += slot->advance.x >> 6; + } + + px = (640 - px) >> 1; + + } +} + +/** + * setfontcolour + * + * Uses RGB triple values. + */ +void +setfontcolour (u8 r, u8 g, u8 b) +{ + u32 fontcolour; + + fontcolour = getcolour (r, g, b); + fonthi = fontcolour & 0xffff0000; + fontlo = fontcolour & 0xffff; +} + +/** + * Licence Information + * + * THIS MUST NOT BE REMOVED IN ANY DERIVATIVE WORK. + */ +void +licence () +{ + + int ypos = ((screenheight - (282 + dkpro_HEIGHT)) >> 1); + + if (screenheight == 480) + ypos += 42; + else + ypos += 24; + + setfontcolour (0x00, 0x00, 0x00); + + DrawText (-1, ypos += 40, "Snes9x - Copyright (c) Snes9x Team 1996 - 2006"); + + DrawText (-1, ypos += 40, "This is free software, and you are welcome to"); + DrawText (-1, ypos += 20, "redistribute it under the conditions of the"); + DrawText (-1, ypos += 20, "GNU GENERAL PUBLIC LICENSE Version 2"); + DrawText (-1, ypos += + 20, "Additionally, the developers of this port disclaims"); + DrawText (-1, ypos += + 20, "all copyright interests in the Nintendo GameCube"); + DrawText (-1, ypos += + 20, "porting code. You are free to use it as you wish"); + + DrawText (-1, ypos += 40, "Developed with DevkitPPC and libOGC"); + DrawText (-1, ypos += 20, "http://www.devkitpro.org"); + +} + +/** + * dkunpack + * + * Support function to expand the DevkitPro logo + */ +int +dkunpack () +{ + unsigned long res, inbytes, outbytes; + + inbytes = dkpro_COMPRESSED; + outbytes = dkpro_RAW; + dkproraw = (u32 *) malloc (dkpro_RAW + 16); + + res = uncompress ((Bytef *) dkproraw, &outbytes, (Bytef *) dkpro, inbytes); + + if (res == Z_OK) + return 1; + + return 0; +} + +/** + * showdklogo + * + * Display the DevkitPro logo + */ +void +showdklogo () +{ + int w, h, p, dispoffset; + p = 0; + dispoffset = + ((screenheight != 480 ? 360 : 350) * 320) + ((640 - dkpro_WIDTH) >> 2); + + dkunpack (); + + for (h = 0; h < dkpro_HEIGHT; h++) + { + for (w = 0; w < dkpro_WIDTH >> 1; w++) + { + if (dkproraw[p] != 0x00800080) + xfb[whichfb][dispoffset + w] = dkproraw[p++]; + else + p++; + } + + dispoffset += 320; + } + + free (dkproraw); +} + +/** + * getcolour + * + * Simply converts RGB to Y1CbY2Cr format + * + * I got this from a pastebin, so thanks to whoever originally wrote it! + */ + +unsigned int +getcolour (u8 r1, u8 g1, u8 b1) +{ + int y1, cb1, cr1, y2, cb2, cr2, cb, cr; + u8 r2, g2, b2; + + r2 = r1; + g2 = g1; + b2 = b1; + + y1 = (299 * r1 + 587 * g1 + 114 * b1) / 1000; + cb1 = (-16874 * r1 - 33126 * g1 + 50000 * b1 + 12800000) / 100000; + cr1 = (50000 * r1 - 41869 * g1 - 8131 * b1 + 12800000) / 100000; + + y2 = (299 * r2 + 587 * g2 + 114 * b2) / 1000; + cb2 = (-16874 * r2 - 33126 * g2 + 50000 * b2 + 12800000) / 100000; + cr2 = (50000 * r2 - 41869 * g2 - 8131 * b2 + 12800000) / 100000; + + cb = (cb1 + cb2) >> 1; + cr = (cr1 + cr2) >> 1; + + return ((y1 << 24) | (cb << 16) | (y2 << 8) | cr); +} + +/** + * Unpackbackdrop + */ +void +unpackbackdrop () +{ + unsigned long res, inbytes, outbytes; + unsigned int colour; + int offset; + int i; + + backdrop = (unsigned int *) malloc (screenheight * 1280); + colour = getcolour (0x00, 0x00, 0x00); + + /*** Fill with black for now ***/ + for (i = 0; i < (320 * screenheight); i++) + backdrop[i] = colour; + + /*** If it's PAL50, need to move down a few lines ***/ + offset = ((screenheight - 480) >> 1) * 320; + inbytes = tempgfx_COMPRESSED; + outbytes = tempgfx_RAW; + + res = + uncompress ((Bytef *) backdrop + offset, &outbytes, (Bytef *) tempgfx, + inbytes); + + /*** Now store the backdrop in ARAM ***/ + ARAMPut ((char *) backdrop, (char *) AR_BACKDROP, 640 * screenheight * 2); + + free (backdrop); + +} + +/** + * Display legal copyright and licence + */ +void +legal () +{ + unpackbackdrop (); + clearscreen (); + licence (); + showdklogo (); + showscreen (); +} + +/** + * Wait for user to press A + */ +void +WaitButtonA () +{ + while (PAD_ButtonsDown (0) & PAD_BUTTON_A); + while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A)); +} + +/** + * Wait for user to press A or B. Returns 0 = B; 1 = A + */ +int +WaitButtonAB () +{ + int btns; + + while ( (PAD_ButtonsDown (0) & (PAD_BUTTON_A | PAD_BUTTON_B)) ); + + while ( TRUE ) + { + btns = PAD_ButtonsDown (0); + if ( btns & PAD_BUTTON_A ) + return 1; + else if ( btns & PAD_BUTTON_B ) + return 0; + } +} + +/** + * Show a prompt + */ +void +WaitPrompt (char *msg) +{ + int ypos = (screenheight - 64) >> 1; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + clearscreen (); + DrawText (-1, ypos, msg); + ypos += 30; + DrawText (-1, ypos, "Press A to continue"); + showscreen (); + WaitButtonA (); +} + +/** + * Show a prompt with choice of two options. Returns 1 if A button was pressed + and 0 if B button was pressed. + */ +int +WaitPromptChoice (char *msg, char *bmsg, char *amsg) +{ + int ypos = (screenheight - 64) >> 1; + + if (screenheight == 480) + ypos += 37; + else + ypos += 17; + + clearscreen (); + DrawText (-1, ypos, msg); + ypos += 60; + char txt[80]; + sprintf (txt, "B = %s : A = %s", bmsg, amsg); + DrawText (-1, ypos, txt); + showscreen (); + return WaitButtonAB (); +} + +/** + * Show an action in progress + */ +void +ShowAction (char *msg) +{ + int ypos = (screenheight - 30) >> 1; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + clearscreen (); + DrawText (-1, ypos, msg); + showscreen (); +} + +/**************************************************************************** + * Generic Menu Routines + ****************************************************************************/ +void +DrawMenu (char items[][20], char *title, int maxitems, int selected) +{ + int i, w; + int ypos; + +#if 0 + int bounding[] = { 80, 40, 600, 40, 560, 94, 40, 94 }; + int base[] = { 80, screenheight - 90, 600, screenheight - 90, + 560, screenheight - 40, 40, screenheight - 40 + }; +#endif + + ypos = (screenheight - (maxitems * 32)) >> 1; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + clearscreen (); + +#if 0 + DrawPolygon (4, bounding, 0x00, 0x00, 0xc0); + DrawPolygon (4, base, 0x00, 0x00, 0xc0); + setfontsize (32); + DrawText (-1, 80, title); + DrawText (-1, screenheight - 50, "Snes9x - GX 2.0"); +#endif + + setfontsize (24); + setfontcolour (0, 0, 0); + + for (i = 0; i < maxitems; i++) + { + if (i == selected) + { + for( w = 0; w < 32; w++ ) + DrawLineFast( 30, 610, (i << 5) + (ypos-26) + w, 0x80, 0x80, 0x80 ); + + setfontcolour (0xff, 0xff, 0xff); + DrawText (-1, (i << 5) + ypos, items[i]); + setfontcolour (0x00, 0x00, 0x00); + } + else + DrawText (-1, i * 32 + ypos, items[i]); + } + + showscreen (); + +} + +/**************************************************************************** + * RunMenu + * + * Call this with the menu array defined in menu.cpp + * It's here to keep all the font / interface stuff together. + ****************************************************************************/ +int menu = 0; +int +RunMenu (char items[][20], int maxitems, char *title) +{ + int redraw = 1; + int quit = 0; + short p; + int ret = 0; + signed char a; + + //while (!(PAD_ButtonsDown (0) & PAD_BUTTON_B) && (quit == 0)) + while (quit == 0) + { + if (redraw) + { + DrawMenu (&items[0], title, maxitems, menu); + redraw = 0; + } + + p = PAD_ButtonsDown (0); + a = PAD_StickY (0); + + /*** Look for up ***/ + if ((p & PAD_BUTTON_UP) || (a > 70)) + { + redraw = 1; + menu--; + } + + /*** Look for down ***/ + if ((p & PAD_BUTTON_DOWN) || (a < -70)) + { + redraw = 1; + menu++; + } + + if (p & PAD_BUTTON_A) + { + quit = 1; + ret = menu; + } + + if (p & PAD_BUTTON_B) + { + quit = -1; + ret = -1; + } + + if (menu == maxitems) + menu = 0; + + if (menu < 0) + menu = maxitems - 1; + } + + if (PAD_ButtonsDown (0) & PAD_BUTTON_B) + { + /*** Wait for B button to be released before proceeding ***/ + while (PAD_ButtonsDown (0) & PAD_BUTTON_B) + VIDEO_WaitVSync(); + return -1; + } + + return ret; + +} + +/**************************************************************************** + * DrawLine + * + * Quick'n'Dirty Bresenham line drawing routine. + ****************************************************************************/ +#define SIGN(x) ((x<0)?-1:((x>0)?1:0)) + +void +DrawLine (int x1, int y1, int x2, int y2, u8 r, u8 g, u8 b) +{ + u32 colour, pixel; + u32 colourhi, colourlo; + int i, dx, dy, sdx, sdy, dxabs, dyabs, x, y, px, py; + int sp; + + colour = getcolour (r, g, b); + colourhi = colour & 0xffff0000; + colourlo = colour & 0xffff; + + dx = x2 - x1; /*** Horizontal distance ***/ + dy = y2 - y1; /*** Vertical distance ***/ + + dxabs = abs (dx); + dyabs = abs (dy); + sdx = SIGN (dx); + sdy = SIGN (dy); + x = dyabs >> 1; + y = dxabs >> 1; + px = x1; + py = y1; + + sp = (py * 320) + (px >> 1); + pixel = xfb[whichfb][sp]; + /*** Plot this pixel ***/ + if (px & 1) + xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo; + else + xfb[whichfb][sp] = (pixel & 0xffff) | colourhi; + + if (dxabs >= dyabs) /*** Mostly horizontal ***/ + { + for (i = 0; i < dxabs; i++) + { + y += dyabs; + if (y >= dxabs) + { + y -= dxabs; + py += sdy; + } + + px += sdx; + + sp = (py * 320) + (px >> 1); + pixel = xfb[whichfb][sp]; + + if (px & 1) + xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo; + else + xfb[whichfb][sp] = (pixel & 0xffff) | colourhi; + } + } + else + { + for (i = 0; i < dyabs; i++) + { + x += dxabs; + if (x >= dyabs) + { + x -= dyabs; + px += sdx; + } + + py += sdy; + + sp = (py * 320) + (px >> 1); + pixel = xfb[whichfb][sp]; + + if (px & 1) + xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo; + else + xfb[whichfb][sp] = (pixel & 0xffff) | colourhi; + } + } +} + +/**************************************************************************** + * Progress Bar + * + * Show the user what's happening + ****************************************************************************/ +void +ShowProgress (char *msg, int done, int total) +{ + int ypos = (screenheight - 30) >> 1; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + int xpos; + int i; + + clearscreen (); + DrawText (-1, ypos, msg); + + /*** Draw a white outline box ***/ + for (i = 380; i < 401; i++) + DrawLine (100, i, 540, i, 0xff, 0xff, 0xff); + + /*** Show progess ***/ + xpos = (int) (((float) done / (float) total) * 438); + + for (i = 381; i < 400; i++) + DrawLine (101, i, 101 + xpos, i, 0x00, 0x00, 0x80); + + showscreen (); +} + +/**************************************************************************** + * DrawPolygon + ****************************************************************************/ +void +DrawPolygon (int vertices, int varray[], u8 r, u8 g, u8 b) +{ + int i; + + for (i = 0; i < vertices - 1; i++) + { + DrawLine (varray[(i << 1)], varray[(i << 1) + 1], varray[(i << 1) + 2], + varray[(i << 1) + 3], r, g, b); + } + + DrawLine (varray[0], varray[1], varray[(vertices << 1) - 2], + varray[(vertices << 1) - 1], r, g, b); +} + +/***************************************************************************** + * Draw Line Fast + * + * This routine requires that start and endx are 32bit aligned. + * It tries to perform a semi-transparency over the existing image. + *****************************************************************************/ + +#define SRCWEIGHT 0.7f +#define DSTWEIGHT (1.0f - SRCWEIGHT) + +static inline u8 c_adjust( u8 c , float weight ) +{ + return (u8)((float)c * weight); +} + +void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b ) +{ + int width; + u32 offset; + int i; + u32 colour, clo, chi; + u32 lo,hi; + u8 *s, *d; + + //colour = getcolour(r, g, b); + colour = ( r << 16 | g << 8 | b ); + d = (u8 *)&colour; + d[1] = c_adjust(d[1], DSTWEIGHT); + d[2] = c_adjust(d[2], DSTWEIGHT); + d[3] = c_adjust(d[3], DSTWEIGHT); + + width = ( endx - startx ) >> 1; + offset = ( y << 8 ) + ( y << 6 ) + ( startx >> 1 ); + + for ( i = 0; i < width; i++ ) + { + lo = getrgb(xfb[whichfb][offset], 0); + hi = getrgb(xfb[whichfb][offset], 1); + + s = (u8 *)&hi; + s[1] = ( ( c_adjust(s[1],SRCWEIGHT) ) + d[1] ); + s[2] = ( ( c_adjust(s[2],SRCWEIGHT) ) + d[2] ); + s[3] = ( ( c_adjust(s[3],SRCWEIGHT) ) + d[3] ); + + s = (u8 *)&lo; + s[1] = ( ( c_adjust(s[1],SRCWEIGHT) ) + d[1] ); + s[2] = ( ( c_adjust(s[2],SRCWEIGHT) ) + d[2] ); + s[3] = ( ( c_adjust(s[3],SRCWEIGHT) ) + d[3] ); + + clo = getcolour( s[1], s[2], s[3] ); + s = (u8 *)&hi; + chi = getcolour( s[1], s[2], s[3] ); + + xfb[whichfb][offset++] = (chi & 0xffff0000 ) | ( clo & 0xffff) ; + } +} + +/** + * Ok, I'm useless with Y1CBY2CR colour. + * So convert back to RGB so I can work with it -;) + */ +u32 getrgb( u32 ycbr, u32 low ) +{ + u8 r,g,b; + u32 y; + s8 cb,cr; + + if ( low ) + y = ( ycbr & 0xff00 ) >> 8; + else + y = ( ycbr & 0xff000000 ) >> 24; + + cr = ycbr & 0xff; + cb = ( ycbr & 0xff0000 ) >> 16; + + cr -= 128; + cb -= 128; + + r = (u8)((float)y + 1.371 * (float)cr); + g = (u8)((float)y - 0.698 * (float)cr - 0.336 * (float)cb); + b = (u8)((float)y + 1.732 * (float)cb); + + return (u32)( r << 16 | g << 8 | b ); + +} + + diff --git a/source/ngc/ftfont.h b/source/ngc/ftfont.h new file mode 100644 index 0000000..8b1936c --- /dev/null +++ b/source/ngc/ftfont.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Screen Font Driver + * + * Uses libfreetype 2.2.1 compiled for GC with TTF support only. + * TTF only reduces the library by some 900kbytes! + * + * Visit - http://www.freetype.org ! + * + * **WARNING*** + * + * ONLY USE GUARANTEED PATENT FREE FONTS. + * THOSE IN YOUR WINDOWS\FONTS DIRECTORY ARE COPYRIGHT + * AND MAY NOT BE DISTRIBUTED! + * + * softdev July 2006 + * crunchy2 June 2007 + ****************************************************************************/ +#ifndef _TTFFONTS_ +#define _TTFFONTS_ + +int FT_Init (); +void setfontsize (int pixelsize); +void DrawText (int x, int y, char *text); +void legal (); +void highlight (int on); +void WaitButtonA (); +void setfontcolour (u8 r, u8 g, u8 b); +int RunMenu (char items[][20], int maxitems, char *title); +void WaitPrompt (char *msg); +int WaitPromptChoice (char *msg, char* bmsg, char* amsg); +void ShowAction (char *msg); +void ShowProgress (char *msg, int done, int total); +void DrawPolygon (int vertices, int *varray, u8 r, u8 g, u8 b); +void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b ); + +#endif diff --git a/source/ngc/gcglobals.cpp b/source/ngc/gcglobals.cpp new file mode 100644 index 0000000..b4cb1df --- /dev/null +++ b/source/ngc/gcglobals.cpp @@ -0,0 +1,281 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "snes9xGx.h" +START_EXTERN_C +struct SGCSettings GCSettings; +bool8 isWii; + +unsigned short saveicon[1024] = { + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xE73F, + 0xFFFF, 0xFFFF, 0xB5BF, 0x801F, 0xFFFF, 0xD29F, 0x801F, 0x801F, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xA11E, 0x843C, 0x8439, 0x9CF7, + 0x801F, 0x801F, 0x801C, 0x8018, 0x801F, 0x801F, 0x801C, 0x8018, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEB5C, 0xFFFF, 0xFFFF, 0xFFFF, + 0x800F, 0xB9D3, 0xFFFF, 0xFFFF, 0x8013, 0x8008, 0xDAD7, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0x801F, 0x801F, 0x885F, 0xFFFF, 0x98D6, 0x801F, 0x801F, + 0xFFFF, 0xFFFF, 0xFFFF, 0x843C, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFBDF, 0x801E, 0x801B, 0x8017, 0x801E, 0x801B, 0x8018, 0x8015, + 0x801A, 0x8018, 0x8015, 0x8011, 0x8016, 0x8014, 0x8011, 0x800D, + 0x8012, 0x800B, 0x8848, 0xFFFF, 0x8010, 0x8009, 0x8003, 0xFFFF, + 0x800C, 0x8007, 0x8006, 0xFFFF, 0x8008, 0x8005, 0xA52E, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFBBD, 0xF1EF, 0xFFFF, 0xF508, 0xF000, 0xEC00, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xE56B, 0xE16B, 0xE673, 0xFFFF, 0xE800, 0xDC00, 0xCC00, 0xB400, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDE94, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEBBA, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xEFBA, 0xE378, 0xB2EB, 0x9AA4, 0x9AA5, 0x9AA5, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xE778, 0xF3BC, 0xFFFF, 0xFFFF, 0x9A84, 0x9623, 0x91E3, 0xB66C, + 0xD6BB, 0x800E, 0x800C, 0x8008, 0xFFFF, 0x8C6A, 0x8004, 0x8004, + 0xFFFF, 0xFFFF, 0xB191, 0xDAD8, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x8006, 0x8004, 0xFFFF, 0xFFFF, 0x8006, 0xF39D, 0xFFFF, 0xFA94, + 0xFFFF, 0xFFFF, 0xFFFF, 0xEC21, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xF484, 0xF800, 0xF800, 0xF000, 0xF800, 0xF800, 0xFD6B, 0xF8C6, + 0xF400, 0xF400, 0xFDEF, 0xF4A5, 0xFF18, 0xEC63, 0xE400, 0xE000, + 0xE800, 0xE000, 0xD400, 0xC400, 0xE400, 0xE000, 0xD000, 0xC400, + 0xE000, 0xD800, 0xCC00, 0xC000, 0xD800, 0xD000, 0xC400, 0xB800, + 0xA400, 0xD673, 0xFFFF, 0xFFFF, 0xB400, 0x9000, 0xFFFF, 0xFFFF, + 0xB000, 0x9000, 0xFFFF, 0xFFFF, 0xA800, 0x9000, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xDB75, 0x9AE4, 0xFFFF, 0xFFFF, 0x9A84, 0xA6E7, + 0xFFFF, 0xFFFF, 0xA1E7, 0x9604, 0xFFFF, 0xFFFF, 0xFFFF, 0x8D03, + 0xA707, 0xA708, 0xAF2A, 0xAF2A, 0xA6E7, 0xA2C7, 0xBF4E, 0xCB71, + 0x9E46, 0x9E26, 0x9A25, 0x9604, 0x80E0, 0x8922, 0x8D22, 0x8D22, + 0xA2C7, 0xA2A7, 0x9E66, 0x95E4, 0xA2A6, 0x9E46, 0x9E25, 0x95C4, + 0x99E5, 0x95C4, 0x9163, 0x8D02, 0x88E2, 0x84A1, 0x8060, 0x8020, + 0x8500, 0xF7BD, 0xFFFF, 0xFFFF, 0x8901, 0xA148, 0xFFFF, 0xFFFF, + 0x8040, 0xB9ED, 0xFFFF, 0xFFFF, 0x9926, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xE529, 0xD400, 0xFFFF, 0xFFFF, 0xFFFF, 0xD4C6, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xD000, 0xC400, 0xBC00, 0xB000, 0xC000, 0xB800, 0xAC00, 0xA000, + 0xA800, 0xA800, 0x9C00, 0x9400, 0xC18C, 0x8C00, 0x8C00, 0x8C00, + 0x9C00, 0x8C00, 0xFFFF, 0xFFFF, 0x9400, 0x8C00, 0xFFFF, 0xFFFF, + 0x8800, 0xDEB5, 0xFFFF, 0xFFFF, 0xE2D6, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xD6D5, 0xAD8A, 0x8CC3, 0x8060, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0x8060, 0x90E4, 0xB1CC, 0xE759, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF, 0xF7AF, + 0xFFFF, 0xFFFF, 0xFBDC, 0xF7B1, 0xFFFB, 0xFFE2, 0xFFE0, 0xFFE0, + 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE0, 0xFFE5, + 0xF38C, 0xEF6A, 0xEB4B, 0xEB4F, 0xFFE0, 0xFBC0, 0xF7A0, 0xEB40, + 0xFFE0, 0xFFE0, 0xFBC0, 0xF7A0, 0xFFF5, 0xFFE4, 0xF380, 0xEF60, + 0xEF76, 0xFFFF, 0xFFFF, 0xFFFF, 0xE300, 0xCE60, 0xD6AB, 0xFFFF, + 0xEB40, 0xE300, 0xCE60, 0xB180, 0xE720, 0xDEE0, 0xCE60, 0xB180, + 0xF7BD, 0xB96B, 0xDAB4, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB9CA, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xF399, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xD280, 0xEB40, 0xEB40, 0xEB40, 0xDAD1, 0xAD60, 0xC200, 0xCA40, + 0xFFFF, 0xF7BE, 0xBDEB, 0x98C0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xEB40, 0xE720, 0xE300, 0xDAC0, 0xCA40, 0xC620, 0xC200, 0xBDE0, + 0x9080, 0x94A0, 0x94A0, 0x9080, 0xFBDD, 0xE738, 0xE337, 0xE738, + 0xD280, 0xCA40, 0xB5A0, 0x98C0, 0xB180, 0xA100, 0x94A0, 0x9080, + 0x8C60, 0x9080, 0xC20C, 0xFFFF, 0xF7BD, 0xFFFF, 0xFFFF, 0xFFFF, + 0xB9C9, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, +}; + +END_EXTERN_C + diff --git a/source/ngc/gctime.cpp b/source/ngc/gctime.cpp new file mode 100644 index 0000000..0f45cf6 --- /dev/null +++ b/source/ngc/gctime.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** + * gctime.cpp + ****************************************************************************/ +#include "gctime.h" + +#define TB_CLOCK 40500000 + + +unsigned long tb_diff_msec(tb_t *end, tb_t *start) +{ + unsigned long upper, lower; + upper = end->u - start->u; + if (start->l > end->l) + upper--; + lower = end->l - start->l; + return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2000))) + (lower/(TB_CLOCK/1000))); +} + +unsigned long tb_diff_usec(tb_t *end, tb_t *start) +{ + unsigned long upper, lower; + upper = end->u - start->u; + if (start->l > end->l) + upper--; + lower = end->l - start->l; + return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2000000))) + (lower/(TB_CLOCK/1000000))); +} + +void udelay(unsigned int us) +{ + tb_t start, end; + mftb(&start); + while (1) + { + mftb(&end); + if (tb_diff_usec(&end, &start) >= us) + break; + } +} + +void mdelay(unsigned int ms) +{ + tb_t start, end; + mftb(&start); + while (1) + { + mftb(&end); + if (tb_diff_msec(&end, &start) >= ms) + break; + } +} diff --git a/source/ngc/gctime.h b/source/ngc/gctime.h new file mode 100644 index 0000000..11a3bbf --- /dev/null +++ b/source/ngc/gctime.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * gctime.h + ****************************************************************************/ + +#define mftb(rval) ({unsigned long u; do { \ + asm volatile ("mftbu %0" : "=r" (u)); \ + asm volatile ("mftb %0" : "=r" ((rval)->l)); \ + asm volatile ("mftbu %0" : "=r" ((rval)->u)); \ + } while(u != ((rval)->u)); }) + +typedef struct +{ + unsigned long l, u; +} tb_t; + +unsigned long tb_diff_msec(tb_t *end, tb_t *start); +unsigned long tb_diff_usec(tb_t *end, tb_t *start); +void udelay(unsigned int us); +void mdelay(unsigned int ms); + + diff --git a/source/ngc/mcsave.cpp b/source/ngc/mcsave.cpp new file mode 100644 index 0000000..0af4ebc --- /dev/null +++ b/source/ngc/mcsave.cpp @@ -0,0 +1,565 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May-June 2007 + * + * mcsave.cpp + * + * Memory Card Save Routines. + ****************************************************************************/ +#include +#include +#include +#include +#include + +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" + +#include "snes9xGX.h" +#include "video.h" +#include "ftfont.h" +#include "s9xconfig.h" +#include "audio.h" +#include "menu.h" +#include "sram.h" +#include "preferences.h" +#include "mcsave.h" + +#define VERIFBUFFERSIZE 65536 +static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32); +unsigned char savebuffer[SAVEBUFFERSIZE] ATTRIBUTE_ALIGN (32); +unsigned char verifbuffer[VERIFBUFFERSIZE] ATTRIBUTE_ALIGN (32); +card_dir CardDir; +card_file CardFile; +card_stat CardStatus; + + +/**************************************************************************** + * Clear the savebuffer + ****************************************************************************/ +void +ClearSaveBuffer () +{ + memset (savebuffer, 0, SAVEBUFFERSIZE); +} + + +/**************************************************************************** + * CardFileExists + * + * Wrapper to search through the files on the card. + * Returns TRUE if found. + ****************************************************************************/ +int +CardFileExists (char *filename, int slot) +{ + int CardError; + + CardError = CARD_FindFirst (slot, &CardDir, TRUE); + while (CardError != CARD_ERROR_NOFILE) + { + CardError = CARD_FindNext (&CardDir); + + if (strcmp ((char *) CardDir.filename, filename) == 0) + return 1; + } + + return 0; +} + +/**************************************************************************** + * MountCard + * + * Mounts the memory card in the given slot. Error checking is done and + * workarounds implemented for when the mount fails. + * Returns the result of the last attempted CARD_Mount command. + ****************************************************************************/ +int MountCard(int cslot) +{ + int ret; + int tries; + + EXI_ProbeReset(); + + /*** Mount the card ***/ + ret = CARD_Mount (cslot, SysArea, NULL); + + tries = 0; + while ( tries < 3 && ret == CARD_ERROR_IOERROR ) + { + if (cslot == CARD_SLOTA) + WaitPrompt("Replug card in slot A!"); + else + WaitPrompt("Replug card in slot B!"); + + ShowAction(""); + ret = CARD_Mount (cslot, SysArea, NULL); + tries++; + } + + tries = 0; + while ( tries < 5 && ret == CARD_ERROR_NOCARD ) + { + ShowAction("Mounting card..."); + CARD_Unmount (cslot); + usleep(500000); // wait half second + ShowAction(""); + usleep(500000); // wait half second + ret = CARD_Mount (cslot, SysArea, NULL); + tries++; + } + + tries = 0; + while ( tries < 5 && ret == CARD_ERROR_UNLOCKED ) + { + ShowAction("Waiting for unlock..."); + usleep(500000); // wait half second + ShowAction(""); + usleep(500000); // wait half second + ret = CARD_Probe(cslot); + tries++; + } + + return ret; +} + + +/**************************************************************************** + * Verify Memory Card file against buffer + ****************************************************************************/ +int +VerifyMCFile (unsigned char *buf, int slot, char *filename, int datasize) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + char msg[80]; + int bytesleft = 0; + int bytesread = 0; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (!CardFileExists (filename, slot)) + { + CARD_Unmount (slot); + WaitPrompt ("Unable to open file for verify!"); + return 0; + } + + memset (&CardFile, 0, sizeof (CardFile)); + CardError = CARD_Open (slot, filename, &CardFile); + + blocks = CardFile.len; + + if (blocks < SectorSize) + blocks = SectorSize; + + if (blocks % SectorSize) + blocks += SectorSize; + + if (blocks > (unsigned int)datasize) + blocks = datasize; + + memset (verifbuffer, 0, VERIFBUFFERSIZE); + bytesleft = blocks; + bytesread = 0; + while (bytesleft > 0) + { + CARD_Read (&CardFile, verifbuffer, SectorSize, bytesread); + if ( memcmp (buf + bytesread, verifbuffer, (unsigned int)bytesleft < SectorSize ? bytesleft : SectorSize) ) + { + CARD_Close (&CardFile); + CARD_Unmount (slot); + WaitPrompt ("File did not verify!"); + return 0; + } + + bytesleft -= SectorSize; + bytesread += SectorSize; + + sprintf (msg, "Verified %d of %d bytes", bytesread, blocks); + ShowProgress (msg, bytesread, blocks); + } + CARD_Close (&CardFile); + CARD_Unmount (slot); + + return 1; + } + else + if (slot == CARD_SLOTA) + WaitPrompt ("Unable to Mount Slot A Memory Card!"); + else + WaitPrompt ("Unable to Mount Slot B Memory Card!"); + + return 0; +} + + +/**************************************************************************** + * Load savebuffer from Memory Card file + ****************************************************************************/ +int +LoadBufferFromMC (unsigned char *buf, int slot, char *filename, bool8 silent) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + char msg[80]; + int bytesleft = 0; + int bytesread = 0; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (!CardFileExists (filename, slot)) + { + if ( !silent ) + WaitPrompt ("Unable to open file"); + return 0; + } + + memset (&CardFile, 0, sizeof (CardFile)); + CardError = CARD_Open (slot, filename, &CardFile); + + blocks = CardFile.len; + + if (blocks < SectorSize) + blocks = SectorSize; + + if (blocks % SectorSize) + blocks += SectorSize; + + memset (buf, 0, 0x22000); + + bytesleft = blocks; + bytesread = 0; + while (bytesleft > 0) + { + CARD_Read (&CardFile, buf + bytesread, SectorSize, bytesread); + bytesleft -= SectorSize; + bytesread += SectorSize; + + sprintf (msg, "Read %d of %d bytes", bytesread, blocks); + ShowProgress (msg, bytesread, blocks); + } + CARD_Close (&CardFile); + CARD_Unmount (slot); + } + else + if (slot == CARD_SLOTA) + WaitPrompt ("Unable to Mount Slot A Memory Card!"); + else + WaitPrompt ("Unable to Mount Slot B Memory Card!"); + + return bytesread; +} + + +/**************************************************************************** + * Write savebuffer to Memory Card file + ****************************************************************************/ +int +SaveBufferToMC (unsigned char *buf, int slot, char *filename, int datasize, bool8 silent) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + char msg[80]; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (datasize) + { + /*** Calculate number of blocks required ***/ + blocks = (datasize / SectorSize) * SectorSize; + if (datasize % SectorSize) + blocks += SectorSize; + + /*** Does this file exist ? ***/ + if (CardFileExists (filename, slot)) + { + /*** Try to open the file ***/ + CardError = CARD_Open (slot, filename, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt ("Unable to open card file!"); + return 0; + } + +// if ( (s32)blocks < CardFile.len ) /*** new data is shorter ***/ +// { +// CARD_Close (&CardFile); +// +// /*** Delete the existing longer file ***/ +// CardError = CARD_Delete(slot, filename); +// if (CardError) +// { +// CARD_Unmount (slot); +// WaitPrompt ("Unable to delete existing file!"); +// return 0; +// } +// +// /*** Create new, shorter file ***/ +// CardError = CARD_Create (slot, filename, blocks, &CardFile); +// if (CardError) +// { +// CARD_Unmount (slot); +// WaitPrompt ("Unable to create updated card file!"); +// return 0; +// } +// +// } +// else + + if ( (s32)blocks > CardFile.len ) /*** new data is longer ***/ + { + CARD_Close (&CardFile); + + /*** Try to create temp file to check available space ***/ + CardError = CARD_Create (slot, "TEMPFILESNES9XGX201", blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt ("Not enough space to update file!"); + return 0; + } + + /*** Delete the temporary file ***/ + CARD_Close (&CardFile); + CardError = CARD_Delete(slot, "TEMPFILESNES9XGX201"); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt ("Unable to delete temporary file!"); + return 0; + } + + /*** Delete the existing shorter file ***/ + CardError = CARD_Delete(slot, filename); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt ("Unable to delete existing file!"); + return 0; + } + + /*** Create new, longer file ***/ + CardError = CARD_Create (slot, filename, blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt ("Unable to create updated card file!"); + return 0; + } + } + } + else /*** no file existed, create new one ***/ + { + /*** Create new file ***/ + CardError = CARD_Create (slot, filename, blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + if ( CardError = CARD_ERROR_INSSPACE ) + WaitPrompt ("Not enough space to create file!"); + else + WaitPrompt ("Unable to create card file!"); + return 0; + } + } + + /*** Now, have an open file handle, ready to send out the data ***/ + CARD_GetStatus (slot, CardFile.filenum, &CardStatus); + CardStatus.icon_addr = 0x0; + CardStatus.icon_fmt = 2; + CardStatus.icon_speed = 1; + CardStatus.comment_addr = 2048; + CARD_SetStatus (slot, CardFile.filenum, &CardStatus); + + int byteswritten = 0; + int bytesleft = blocks; + while (bytesleft > 0) + { + CardError = + CARD_Write (&CardFile, buf + byteswritten, + SectorSize, byteswritten); + bytesleft -= SectorSize; + byteswritten += SectorSize; + + sprintf (msg, "Wrote %d of %d bytes", byteswritten, blocks); + ShowProgress (msg, byteswritten, blocks); + } + + CARD_Close (&CardFile); + CARD_Unmount (slot); + + if ( GCSettings.VerifySaves ) + { + /*** Verify the written file, but only up to the length we wrote + because the file could be longer due to past writes ***/ + if ( VerifyMCFile (buf, slot, filename, byteswritten) ) + return byteswritten; + else + return 0; + } + else + return byteswritten; + } + else + if ( !silent ) + WaitPrompt ("This game does not appear to use SRAM"); + } + else + if (slot == CARD_SLOTA) + WaitPrompt ("Unable to Mount Slot A Memory Card!"); + else + WaitPrompt ("Unable to Mount Slot B Memory Card!"); + + return 0; + +} + +/**************************************************************************** + * Memory Card SRAM Load + ****************************************************************************/ +void +LoadSRAMFromMC (int slot, int silent) +{ + char filename[128]; + + ShowAction ("Loading SRAM from MC..."); + + /*** Build SRAM filename ***/ + sprintf (filename, "%s.srm", Memory.ROMName); + + int offset = LoadBufferFromMC (savebuffer, slot, filename, silent); + + if ( offset > 0 ) + { + decodesavedata (offset); + if ( !silent ) + { + sprintf (filename, "Loaded %d bytes", offset); + WaitPrompt (filename); + } + S9xSoftReset(); + } +} + + +/**************************************************************************** + * Memory Card SRAM Save + ****************************************************************************/ +void +SaveSRAMToMC (int slot, int silent) +{ + char filename[128]; + int datasize; + int offset; + + ShowAction ("Saving SRAM to MC..."); + + /*** Build SRAM filename ***/ + sprintf (filename, "%s.srm", Memory.ROMName); + + datasize = prepareMCsavedata (); + offset = SaveBufferToMC (savebuffer, slot, filename, datasize, silent); + + if ( (offset > 0) && (!silent)) + { + sprintf (filename, "Wrote %d bytes", offset); + WaitPrompt (filename); + } +} + + +/**************************************************************************** + * Memory Card Preferences Load + ****************************************************************************/ +void +LoadPrefsFromMC (int slot, int silent) +{ + int offset; + char msg[80]; + + ShowAction ("Loading Prefs from MC..."); + + offset = LoadBufferFromMC (savebuffer, slot, PREFS_FILE_NAME, silent); + + if ( offset > 0 ) + { + decodePrefsData (); + if ( !silent ) + { + sprintf (msg, "Loaded %d bytes", offset); + WaitPrompt (msg); + } + } +} + + +/**************************************************************************** + * Memory Card Preferences Save + ****************************************************************************/ +void +SavePrefsToMC (int slot, int silent) +{ + int datasize; + int offset; + char msg[80]; + + ShowAction ("Saving Prefs to MC..."); + + datasize = preparePrefsData (); + offset = SaveBufferToMC (savebuffer, slot, PREFS_FILE_NAME, datasize, silent); + + if ( offset > 0 && !silent) + { + sprintf (msg, "Wrote %d bytes", offset); + WaitPrompt (msg); + } +} + + diff --git a/source/ngc/mcsave.h b/source/ngc/mcsave.h new file mode 100644 index 0000000..811383d --- /dev/null +++ b/source/ngc/mcsave.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * mcsave.cpp + * + * Memory Card Save Routines. + ****************************************************************************/ + +#ifndef _NGCMCSAVE_ +#define _NGCMCSAVE_ + +#define SAVEBUFFERSIZE ((512 * 1024) + 2048 + 64 + 4 + 4) + +void ClearSaveBuffer (); + +int VerifyMCFile (unsigned char *buf, int slot, char *filename, int datasize); + +int LoadBufferFromMC (unsigned char *buf, int slot, char *filename, bool8 silent); +int SaveBufferToMC (unsigned char *buf, int slot, char *filename, int datasize, bool8 silent); + +void LoadSRAMFromMC (int slot, int silent); +void SaveSRAMToMC (int slot, int silent); + +void LoadPrefsFromMC (int slot, int silent); +void SavePrefsToMC (int slot, int silent); + +#endif diff --git a/source/ngc/memfile.cpp b/source/ngc/memfile.cpp new file mode 100644 index 0000000..f2cc0c0 --- /dev/null +++ b/source/ngc/memfile.cpp @@ -0,0 +1,488 @@ +/**************************************************************************** + * Snes9x 1.50 - GX 2.0 + * + * NGC Snapshots Memory File System + * + * This is a single global memory file controller. Don't even think of opening two + * at the same time ! + * + * There's just enough here to do SnapShots - you should add anything else you + * need. + * + * softdev July 2006 + * crunchy2 May 2007-July 2007 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "memfile.h" +#include "snes9x.h" +#include "memmap.h" +#include "soundux.h" +#include "snapshot.h" +#include "srtc.h" + +#include "Snes9xGx.h" +#include "filesel.h" +#include "ftfont.h" +#include "smbload.h" +#include "mcsave.h" + +extern "C" +{ +#include "smb.h" +} + +#define MEMBUFFER (512 * 1024) + +extern void S9xSRTCPreSaveState (); +extern void NGCFreezeStruct (); +extern bool8 S9xUnfreezeGame (const char *filename); +extern unsigned char savebuffer[]; + +static int bufoffset; +static char membuffer[MEMBUFFER]; + +char freezecomment[2][32] = { {"Snes9x GX 2.0.1b8 Freeze"}, {"Freeze"} }; + + +/** + * GetMem + * + * Return x bytes from memory buffer + */ +int +GetMem (char *buffer, int len) +{ + memcpy (buffer, membuffer + bufoffset, len); + bufoffset += len; + + return len; +} + +/** + * PutMem + * + * Put some values in memory buffer + */ +static void +PutMem (char *buffer, int len) +{ + memcpy (membuffer + bufoffset, buffer, len); + bufoffset += len; +} + +void +NGCFreezeBlock (char *name, uint8 * block, int size) +{ + char buffer[512]; + +// char msg[90]; +// sprintf (msg, "name=%s", name); +// WaitPrompt(msg); + + sprintf (buffer, "%s:%06d:", name, size); + PutMem (buffer, strlen (buffer)); + PutMem ((char *) block, size); +} + +/** + * NGCFreezeMembuffer + */ +static int +NGCFreezeMemBuffer () +{ + int i; + char buffer[1024]; + + bufoffset = 0; + + S9xUpdateRTC (); + S9xSRTCPreSaveState (); + + for (i = 0; i < 8; i++) + { + SoundData.channels[i].previous16[0] = + (int16) SoundData.channels[i].previous[0]; + SoundData.channels[i].previous16[1] = + (int16) SoundData.channels[i].previous[1]; + } + + sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION); + PutMem (buffer, strlen (buffer)); + sprintf (buffer, "NAM:%06d:%s%c", (int) strlen (Memory.ROMFilename) + 1, + Memory.ROMFilename, 0); + + PutMem (buffer, strlen (buffer) + 1); + + NGCFreezeStruct (); + + return 0; +} + + +/** + * NGCFreezeGame + * + * Do freeze game for Nintendo Gamecube + */ +int +NGCFreezeGame (int where, bool8 silent) +{ + char filename[1024]; + SMBFILE smbfile; + sd_file *handle; + int len = 0; + int wrote = 0; + int offset = 0; + char msg[100]; + + if (where == 4) + { + /*** Freeze to SMB ***/ + sprintf (filename, "\\%s\\%s.frz", SNESSAVEDIR, Memory.ROMName); + } + else if (where == 2 || where == 3) + { + /*** Freeze to SDCard in slot A or slot B ***/ + SDCARD_Init (); + +#ifdef SDUSE_LFN + sprintf (filename, "dev%d:\\%s\\%s.frz", where-2, SNESSAVEDIR, Memory.ROMName); +#else + /*** Until we have LFN on SD ... ***/ + sprintf (filename, "dev%d:\\%s\\%08x.frz", where-2, SNESSAVEDIR, Memory.ROMCRC32); +#endif + } + else + { + /*** Freeze to MC in slot A or slot B ***/ + sprintf (filename, "%s.snz", Memory.ROMName); + } + + S9xSetSoundMute (TRUE); + S9xPrepareSoundForSnapshotSave (FALSE); + + NGCFreezeMemBuffer (); + + S9xPrepareSoundForSnapshotSave (TRUE); + S9xSetSoundMute (FALSE); + + if (where == 4) /*** SMB ***/ + { + ConnectSMB (); + + smbfile = SMB_Open (filename, SMB_OPEN_WRITING | SMB_DENY_NONE, + SMB_OF_CREATE | SMB_OF_TRUNCATE); + + if (smbfile) + { + ShowAction ("Saving freeze game..."); + + len = bufoffset; + offset = 0; + while (len > 0) + { + if (len > 1024) + wrote = + SMB_Write ((char *) membuffer + offset, 1024, offset, + smbfile); + else + wrote = + SMB_Write ((char *) membuffer + offset, len, offset, + smbfile); + + offset += wrote; + len -= wrote; + } + + SMB_Close (smbfile); + + if ( !silent ) + { + sprintf (filename, "Written %d bytes", bufoffset); + WaitPrompt (filename); + } + } + else + { + char msg[100]; + sprintf(msg, "Couldn't save to SMB:\\%s\\", SNESSAVEDIR); + WaitPrompt (msg); + } + } + else if (where == 2 || where == 3) /*** SDCard slot A or slot B ***/ + { + handle = SDCARD_OpenFile (filename, "wb"); + + if (handle > 0) + { + ShowAction ("Saving freeze game..."); + + len = SDCARD_WriteFile (handle, membuffer, bufoffset); + SDCARD_CloseFile (handle); + + if (len != bufoffset) + WaitPrompt ("Error writing freeze file"); + else if ( !silent ) + { + sprintf (filename, "Written %d bytes", bufoffset); + WaitPrompt (filename); + } + + } + else + { + sprintf(msg, "Couldn't save to dev%d:\\%s\\", where-2, SNESSAVEDIR); + WaitPrompt (msg); + } + } + else /*** MC in slot A or slot B ***/ + { + ShowAction ("Saving freeze game..."); + + ClearSaveBuffer (); + + /*** Copy in save icon ***/ + int offset = sizeof (saveicon); + memcpy (savebuffer, saveicon, offset); + + /*** And the freezecomment ***/ + sprintf (freezecomment[1], "%s", Memory.ROMName); + memcpy (savebuffer + offset, freezecomment, 64); + offset += 64; + + /*** Zip and copy in the freeze ***/ + uLongf DestBuffSize = (uLongf) SAVEBUFFERSIZE; + int err= compress2((Bytef*)(savebuffer+offset+8), (uLongf*)&DestBuffSize, (const Bytef*)membuffer, (uLongf)bufoffset, Z_BEST_COMPRESSION); + + if(err!=Z_OK) + { + sprintf (msg, "zip error %s ",zError(err)); + WaitPrompt (msg); + return 0; + } + + int zippedsize = (int)DestBuffSize; + memcpy (savebuffer + offset, &zippedsize, 4); + offset += 4; + + int decompressedsize = (int)bufoffset; + memcpy (savebuffer + offset, &decompressedsize, 4); + offset += 4; + + offset += zippedsize; + + int ret = SaveBufferToMC ( savebuffer, where, filename, offset, SILENT ); + if ( ret && !silent ) + { + sprintf (filename, "Written %d bytes", ret); + WaitPrompt (filename); + } + } + + return 0; +} + +/** + * NGCUnFreezeBlock + */ +int +NGCUnFreezeBlock (char *name, uint8 * block, int size) +{ + char buffer[20], *e; + int len = 0; + int rem = 0; + + GetMem (buffer, 11); + + if (strncmp (buffer, name, 3) != 0 || buffer[3] != ':' || + buffer[10] != ':' || (len = strtol (&buffer[4], &e, 10)) == 0 || + e != buffer + 10) + { + return WRONG_FORMAT; + } + + if (len > size) + { + rem = len - size; + len = size; + } + + ZeroMemory (block, size); + + GetMem ((char *) block, len); + + if (rem) + { + bufoffset += rem; + } + + return SUCCESS; +} + +/** + * NGCUnfreezeGame + */ +int +NGCUnfreezeGame (int from, bool8 silent) +{ + char filename[1024]; + SMBFILE smbfile; + sd_file *handle; + int read = 0; + int offset = 0; + char msg[80]; + + bufoffset = 0; + + if (from == 4) + { + /*** From SMB ***/ + sprintf (filename, "\\%s\\%s.frz", SNESSAVEDIR, Memory.ROMName); + ConnectSMB (); + + /*** Read the file into memory ***/ + smbfile = + SMB_Open (filename, SMB_OPEN_READING | SMB_DENY_NONE, SMB_OF_OPEN); + + if (smbfile) + { + ShowAction ("Loading freeze file..."); + while ((read = + SMB_Read ((char *) membuffer + offset, 1024, offset, + smbfile)) > 0) + offset += read; + + SMB_Close (smbfile); + + ShowAction ("Unpacking freeze file"); + if (S9xUnfreezeGame ("AGAME") != SUCCESS) + { + WaitPrompt ("Error thawing"); + return 0; + } + } + else if ( !silent ) + { + WaitPrompt ("No freeze file found"); + return 0; + } + } + else if (from == 2 || from == 3) /*** From SD slot A or slot B ***/ + { + SDCARD_Init (); + +#ifdef SDUSE_LFN + sprintf (filename, "dev%d:\\%s\\%s.frz", from-2, SNESSAVEDIR, Memory.ROMName); +#else + /*** From SDCard ***/ + sprintf (filename, "dev%d:\\%s\\%08x.frz", from-2, SNESSAVEDIR, Memory.ROMCRC32); +#endif + + handle = SDCARD_OpenFile (filename, "rb"); + + if (handle > 0) + { + ShowAction ("Loading freeze file..."); + + offset = 0; + /*** Usual chunks into memory ***/ + while ((read = SDCARD_ReadFile (handle, membuffer + offset, 2048)) > + 0) + offset += read; + + SDCARD_CloseFile (handle); + + ShowAction ("Unpacking freeze file"); + + if (S9xUnfreezeGame ("AGAME") != SUCCESS) + { + WaitPrompt ("Error thawing"); + return 0; + } + } + else if ( !silent ) + { + WaitPrompt ("No freeze file found"); + return 0; + } + } + else /*** From MC in slot A or slot B ***/ + { + ShowAction ("Loading freeze file..."); + + sprintf (filename, "%s.snz", Memory.ROMName); + + int ret = LoadBufferFromMC ( savebuffer, from, filename, silent ); + if ( ret ) + { + ShowAction ("Unpacking freeze file"); + + // skip the saveicon and comment + offset = (sizeof(saveicon) + 64); + uLongf zipsize = 0; + uLongf decompressedsize = 0; + + memcpy (&zipsize, savebuffer+offset, 4); + offset += 4; + + memcpy (&decompressedsize, savebuffer+offset, 4); + offset += 4; + + memset(membuffer, 0, MEMBUFFER); + + uLongf DestBuffSize = MEMBUFFER; + int err= uncompress((Bytef*)membuffer, (uLongf*)&DestBuffSize, (const Bytef*)(savebuffer + offset), zipsize); + + if ( err!=Z_OK ) + { + sprintf (msg, "unzip error %s ",zError(err)); + WaitPrompt (msg); + return 0; + } + + if ( DestBuffSize != decompressedsize ) + { + WaitPrompt ("Unzipped size doesn't match expected size!"); + return 0; + } + + if (S9xUnfreezeGame ("AGAME") != SUCCESS) + { + WaitPrompt ("Error thawing"); + return 0; + } + } + else if ( !silent ) + { + sprintf(msg, "Couldn't load from MC slot %s", (from ? "B" : "A")); + WaitPrompt (msg); + return 0; + } + + } + + return 1; + +} + + +void quickLoadFreeze (bool8 silent) +{ + if ( QUICK_SAVE_SLOT >= 0 ) + NGCUnfreezeGame ( QUICK_SAVE_SLOT, silent ); +} + + +void quickSaveFreeze (bool8 silent) +{ + if ( QUICK_SAVE_SLOT >= 0 ) + NGCFreezeGame ( QUICK_SAVE_SLOT, silent ); +} + + diff --git a/source/ngc/memfile.h b/source/ngc/memfile.h new file mode 100644 index 0000000..8da54bf --- /dev/null +++ b/source/ngc/memfile.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * Snes9x 1.50 - GX 2.0 + * + * NGC Snapshots Memory File System + * + * This is a single global memory file controller. Don't even think of opening two + * at the same time ! + * + * There's just enough here to do SnapShots - you should add anything else you + * need. + ****************************************************************************/ +#include "snes9x.h" + +#ifndef _NGCMEMFILE_ +#define _NGCMEMFILE_ + +typedef struct +{ + char filename[512]; /*** Way over size - but who cares -;) ***/ + int filehandle; + int currpos; + int length; + int mode; + char *buffer; /*** Memspace for read / write ***/ +} +MEMFILE; + +int NGCFreezeGame (int where, bool8 silent); +int NGCUnfreezeGame (int from, bool8 silent); + +void quickLoadFreeze (bool8 silent); +void quickSaveFreeze (bool8 silent); + +#endif diff --git a/source/ngc/menu.cpp b/source/ngc/menu.cpp new file mode 100644 index 0000000..0063351 --- /dev/null +++ b/source/ngc/menu.cpp @@ -0,0 +1,666 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Menu + * + * softdev July 2006 + * crunchy2 May-June 2007 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "snes9x.h" +#include "snes9xGx.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" +#include "controls.h" +#include "aram.h" +#include "ftfont.h" +#include "video.h" +#include "mcsave.h" +#include "filesel.h" +#include "ngcunzip.h" +#include "smbload.h" +#include "mcsave.h" +#include "sdload.h" +#include "memfile.h" +#include "dvd.h" +#include "s9xconfig.h" +#include "sram.h" +#include "preferences.h" + +#define PSOSDLOADID 0x7c6000a6 +extern int menu; +extern unsigned long ARAM_ROMSIZE; + +#define SOFTRESET_ADR ((volatile u32*)0xCC003024) + + +/**************************************************************************** + * Freeze Manager + ****************************************************************************/ +int freezecountwii = 9; +char freezemenuwii[][20] = { "Freeze to MC Slot A", "Thaw from MC Slot A", + "Freeze to MC Slot B", "Thaw from MC Slot B", + "Freeze to SD Slot A", "Thaw from SD Slot A", + "Freeze to SD Slot B", "Thaw from SD Slot B", + "Return to previous" +}; +int freezecount = 11; +char freezemenu[][20] = { "Freeze to MC Slot A", "Thaw from MC Slot A", + "Freeze to MC Slot B", "Thaw from MC Slot B", + "Freeze to SD Slot A", "Thaw from SD Slot A", + "Freeze to SD Slot B", "Thaw from SD Slot B", + "Freeze to SMB", "Thaw from SMB", + "Return to previous" +}; +int +FreezeManager () +{ + int ret; + int loaded = 0; + int quit = 0; + int oldmenu = menu; + menu = 0; + + + while (quit == 0) + { + if ( isWii ) /* Wii menu */ + { + ret = RunMenu (freezemenuwii, freezecountwii, "Freeze Manager"); + if (ret >= freezecountwii-1) + ret = freezecount-1; + } + else /* Gamecube menu */ + ret = RunMenu (freezemenu, freezecount, "Freeze Manager"); + + switch (ret) + { + case 0:/*** Freeze to MC in slot A ***/ + NGCFreezeGame (0, NOTSILENT); + break; + + case 1:/*** Thaw from MC in slot A ***/ + quit = loaded = NGCUnfreezeGame (0, NOTSILENT); + break; + + case 2:/*** Freeze to MC in slot B ***/ + NGCFreezeGame (1, NOTSILENT); + break; + + case 3:/*** Thaw from MC in slot B ***/ + quit = loaded = NGCUnfreezeGame (1, NOTSILENT); + break; + + case 4:/*** Freeze to SDCard in slot A ***/ + NGCFreezeGame (2, NOTSILENT); + break; + + case 5:/*** Thaw from SDCard in slot A ***/ + quit = loaded = NGCUnfreezeGame (2, NOTSILENT); + break; + + case 6:/*** Freeze to SDCard in slot B ***/ + NGCFreezeGame (3, NOTSILENT); + break; + + case 7:/*** Thaw from SDCard in slot B ***/ + quit = loaded = NGCUnfreezeGame (3, NOTSILENT); + break; + + case 8:/*** Freeze to SMB ***/ + if ( !isWii ) + NGCFreezeGame (4, NOTSILENT); + break; + + case 9:/*** Thaw from SMB ***/ + if ( !isWii ) + quit = loaded = NGCUnfreezeGame (4, NOTSILENT); + break; + + case -1: /*** Button B ***/ + case 10: + quit = 1; + break; + } + + } + + menu = oldmenu; + return loaded; +} + +/**************************************************************************** + * Load Manager + ****************************************************************************/ +int loadmancountwii = 4; +char loadmanwii[][20] = { "Load from DVD", "Load from SD Slot A", + "Load from SD Slot B", "Return to previous" +}; +int loadmancount = 5; +char loadman[][20] = { "Load from DVD", "Load from SD Slot A", + "Load from SD Slot B", "Load from SMB", "Return to previous" +}; +int +LoadManager () +{ + int ret; + int quit = 0; + int oldmenu = menu; + int retval = 0; + menu = 0; + + while (quit == 0) + { + if ( LOAD_TYPE ) + ret = LOAD_TYPE-1; + else + { + if ( isWii ) /* Wii menu */ + { + ret = RunMenu (loadmanwii, loadmancountwii, "Load Manager"); + if (ret >= loadmancountwii-1) + ret = loadmancount-1; + } + else /* Gamecube menu */ + ret = RunMenu (loadman, loadmancount, "Load Manager"); + } + + switch (ret) + { + case 0: + /*** Load from DVD ***/ + retval = OpenDVD (); + if ( LOAD_TYPE ) + quit = 1; + else + quit = retval; + break; + + case 1: + retval = OpenSD (CARD_SLOTA); + if ( LOAD_TYPE ) + quit = 1; + else + quit = retval; + break; + + case 2: + retval = OpenSD (CARD_SLOTB); + if ( LOAD_TYPE ) + quit = 1; + else + quit = retval; + break; + + case 3: + retval = OpenSMB (); + if ( LOAD_TYPE ) + quit = 1; + else + quit = retval; + break; + + case -1: /*** Button B ***/ + case 4: + retval = 0; + quit = 1; + break; + } + } + + menu = oldmenu; + return retval; +} + +/**************************************************************************** + * Save Manager + ****************************************************************************/ +int savecountwii = 9; +char savemenuwii[][20] = { "Save to MC SLOT A", "Load from MC SLOT A", + "Save to MC SLOT B", "Load from MC SLOT B", + "Save to SD Slot A", "Load from SD Slot A", + "Save to SD Slot B", "Load from SD Slot B", + "Return to previous" +}; +int savecount = 11; +char savemenu[][20] = { "Save to MC SLOT A", "Load from MC SLOT A", + "Save to MC SLOT B", "Load from MC SLOT B", + "Save to SD Slot A", "Load from SD Slot A", + "Save to SD Slot B", "Load from SD Slot B", + "Save to SMB", "Load from SMB", + "Return to previous" +}; +void +SaveManager () +{ + int ret; + int quit = 0; + int oldmenu = menu; + menu = 0; + + while (quit == 0) + { + if ( isWii ) /* Wii menu */ + { + ret = RunMenu (savemenuwii, savecountwii, "Save Manager"); + if (ret >= savecountwii-1) + ret = savecount-1; + } + else /* Gamecube menu */ + ret = RunMenu (savemenu, savecount, "Save Manager"); + + switch (ret) + { + case 0: + /*** Save to MC slot A ***/ + SaveSRAMToMC (CARD_SLOTA, NOTSILENT); + break; + + case 1: + /*** Load from MC slot A ***/ + LoadSRAMFromMC (CARD_SLOTA, NOTSILENT); + break; + + case 2: + /*** Save to MC slot B ***/ + SaveSRAMToMC (CARD_SLOTB, NOTSILENT); + break; + + case 3: + /*** Load from MC slot B ***/ + LoadSRAMFromMC (CARD_SLOTB, NOTSILENT); + break; + + case 4: + /*** Save to SD slot A ***/ + SaveSRAMToSD (CARD_SLOTA, NOTSILENT); + break; + + case 5: + /*** Load from SD slot A ***/ + LoadSRAMFromSD (CARD_SLOTA, NOTSILENT); + break; + + case 6: + /*** Save to SD slot B ***/ + SaveSRAMToSD (CARD_SLOTB, NOTSILENT); + break; + + case 7: + /*** Load from SD slot B ***/ + LoadSRAMFromSD (CARD_SLOTB, NOTSILENT); + break; + + case 8: + /*** Save to SMB **/ + SaveSRAMToSMB (NOTSILENT); + break; + + case 9: + /*** Load from SMB ***/ + LoadSRAMFromSMB (NOTSILENT); + break; + + case -1: /*** Button B ***/ + case 10: + /*** Return ***/ + quit = 1; + break; + } + } + + menu = oldmenu; +} + +/**************************************************************************** + * Emulator Options + ****************************************************************************/ +static int emuCount = 11; +static char emulatorOptions[][20] = { "Reverse Stereo OFF", + "Interp. Sound ON", "Transparency ON", "FPS Display OFF", + "MultiTap 5 OFF", "C-Stick Zoom OFF", + "Auto Load OFF", "Auto Save OFF", "Verify MC Saves OFF", + "Save Prefs Now", "Return to previous" +}; + +void +EmulatorOptions () +{ + int ret = 0; + int quit = 0; + int oldmenu = menu; + menu = 0; + + while (quit == 0) + { + sprintf (emulatorOptions[0], "Reverse Stereo %s", + Settings.ReverseStereo == true ? " ON" : "OFF"); + + sprintf (emulatorOptions[1], "Interp. Sound %s", + Settings.InterpolatedSound == true ? " ON" : "OFF"); + + sprintf (emulatorOptions[2], "Transparency %s", + Settings.Transparency == true ? " ON" : "OFF"); + + sprintf (emulatorOptions[3], "FPS Display %s", + Settings.DisplayFrameRate == true ? " ON" : "OFF"); + + sprintf (emulatorOptions[4], "MultiTap 5 %s", + Settings.MultiPlayer5Master == true ? " ON" : "OFF"); + + sprintf (emulatorOptions[5], "C-Stick Zoom %s", + GCSettings.NGCZoom == true ? " ON" : "OFF"); + + if (GCSettings.AutoLoad == 0) sprintf (emulatorOptions[6],"Auto Load OFF"); + else if (GCSettings.AutoLoad == 1) sprintf (emulatorOptions[6],"Auto Load SRAM"); + else if (GCSettings.AutoLoad == 2) sprintf (emulatorOptions[6],"Auto Load FREEZE"); + + if (GCSettings.AutoSave == 0) sprintf (emulatorOptions[7],"Auto Save OFF"); + else if (GCSettings.AutoSave == 1) sprintf (emulatorOptions[7],"Auto Save SRAM"); + else if (GCSettings.AutoSave == 2) sprintf (emulatorOptions[7],"Auto Save FREEZE"); + else if (GCSettings.AutoSave == 3) sprintf (emulatorOptions[7],"Auto Save BOTH"); + + sprintf (emulatorOptions[8], "Verify MC Saves %s", + GCSettings.VerifySaves == true ? " ON" : "OFF"); + + ret = RunMenu (emulatorOptions, emuCount, "Emulator Options"); + + switch (ret) + { + case 0: + Settings.ReverseStereo = + (Settings.ReverseStereo == false ? true : false); + break; + + case 1: + Settings.InterpolatedSound = + (Settings.InterpolatedSound == false ? true : false); + break; + + case 2: + Settings.Transparency = + (Settings.Transparency == false ? true : false); + break; + + case 3: + Settings.DisplayFrameRate = + (Settings.DisplayFrameRate == false ? true : false); + break; + + case 4: + Settings.MultiPlayer5Master = + (Settings.MultiPlayer5Master == false ? true : false); + + if (Settings.MultiPlayer5Master) + { + S9xSetController (1, CTL_MP5, 1, 2, 3, -1); + } + else + { + S9xSetController (1, CTL_JOYPAD, 1, 0, 0, 0); + } + break; + + case 5: + GCSettings.NGCZoom = + (GCSettings.NGCZoom == false ? true : false); + break; + + case 6: + GCSettings.AutoLoad ++; + if (GCSettings.AutoLoad > 2) + GCSettings.AutoLoad = 0; + break; + + case 7: + GCSettings.AutoSave ++; + if (GCSettings.AutoSave > 3) + GCSettings.AutoSave = 0; + break; + + case 8: + GCSettings.VerifySaves = + (GCSettings.VerifySaves == false ? true : false); + break; + + case 9: + quickSavePrefs(NOTSILENT); + break; + + case -1: /*** Button B ***/ + case 10: + quit = 1; + break; + + } + } + + menu = oldmenu; +} + +/**************************************************************************** + * Configure Joypads + * + * Snes9x 1.50 uses a cmd system to work out which button has been pressed. + * Here, I simply move the designated value to the gcpadmaps array, which saves + * on updating the cmd sequences. + ****************************************************************************/ +int padcount = 7; +char padmenu[][20] = { "SNES BUTTON A - A", + "SNES BUTTON B - B", + "SNES BUTTON X - X", + "SNES BUTTON Y - Y", + "ANALOG CLIP - 70", + "Save SRAM/Config", + "Return to previous" +}; + +unsigned short padmap[4] = { PAD_BUTTON_A, + PAD_BUTTON_B, + PAD_BUTTON_X, + PAD_BUTTON_Y +}; +int currconfig[4] = { 0, 1, 2, 3 }; +static char *padnames = "ABXY"; + +extern unsigned short gcpadmap[]; +extern int padcal; + +void +ConfigureJoyPads () +{ + int quit = 0; + int ret = 0; + int oldmenu = menu; + menu = 0; + + while (quit == 0) + { + /*** Update the menu information ***/ + for (ret = 0; ret < 4; ret++) + padmenu[ret][16] = padnames[currconfig[ret]]; + + sprintf (padmenu[4], "ANALOG CLIP - %d", padcal); + + ret = RunMenu (padmenu, padcount, "Configure Joypads"); + + switch (ret) + { + case 0: + /*** Configure Button A ***/ + currconfig[0]++; + currconfig[0] &= 3; + gcpadmap[0] = padmap[currconfig[0]]; + break; + + case 1: + /*** Configure Button B ***/ + currconfig[1]++; + currconfig[1] &= 3; + gcpadmap[1] = padmap[currconfig[1]]; + break; + + case 2: + /*** Configure Button X ***/ + currconfig[2]++; + currconfig[2] &= 3; + gcpadmap[2] = padmap[currconfig[2]]; + break; + + case 3: + /*** Configure Button Y ***/ + currconfig[3]++; + currconfig[3] &= 3; + gcpadmap[3] = padmap[currconfig[3]]; + break; + + case 4: + /*** Pad Calibration ***/ + padcal += 5; + if (padcal > 80) + padcal = 40; + break; + + case 5: + /*** Quick Save SRAM ***/ + if ( ARAM_ROMSIZE > 0 ) + quickSaveSRAM(NOTSILENT); + else + WaitPrompt ("No ROM loaded - can't save SRAM"); + + break; + + case -1: /*** Button B ***/ + case 6: + /*** Return ***/ + quit = 1; + break; + } + } + + menu = oldmenu; +} + +/**************************************************************************** + * Main Menu + ****************************************************************************/ +int menucount = 10; +char menuitems[][20] = { "Choose Game", + "SRAM Manager", "Freeze Manager", + "Configure Joypads", "Emulator Options", + "Reset Game", "Stop DVD Drive", "PSO Reload", + "Reset Gamecube", "Return to Game" +}; + +void +mainmenu () +{ + int quit = 0; + int ret; + int *psoid = (int *) 0x80001800; + void (*PSOReload) () = (void (*)()) 0x80001800; + + if ( isWii ) + sprintf (menuitems[8],"Reset Wii"); + else + sprintf (menuitems[8],"Reset Gamecube"); + + VIDEO_WaitVSync (); + + while (quit == 0) + { + ret = RunMenu (menuitems, menucount, "Main Menu"); + + switch (ret) + { + case 0: + /*** Load ROM Menu ***/ + quit = LoadManager (); + if ( quit ) // if ROM was loaded, load the SRAM & settings + { + if ( GCSettings.AutoLoad == 1 ) + quickLoadSRAM ( SILENT ); + else if ( GCSettings.AutoLoad == 2 ) + { + /*** load SRAM first in order to get joypad config ***/ + quickLoadSRAM ( SILENT ); + quickLoadFreeze ( SILENT ); + } + } + break; + + case 1: + /*** SRAM Manager Menu ***/ + if ( ARAM_ROMSIZE > 0 ) + SaveManager (); + else + WaitPrompt ("No ROM is loaded!"); + break; + + case 2: + /*** Do Freeze / Thaw Menu ***/ + if ( ARAM_ROMSIZE > 0 ) + quit = FreezeManager (); + else + WaitPrompt ("No ROM is loaded!"); + break; + + case 3: + /*** Configure Joypads ***/ + ConfigureJoyPads (); + break; + + case 4: + /*** Emulator Options ***/ + EmulatorOptions (); + break; + + case 5: + /*** Soft reset ***/ + S9xSoftReset (); + quit = 1; + break; + + case 6: + /*** Turn off DVD motor ***/ + dvd_motor_off(); + break; + + case 7: + /*** PSO Reload ***/ + if (psoid[0] == PSOSDLOADID) + PSOReload (); + break; + + case 8: + /*** Reset the Gamecube ***/ + *SOFTRESET_ADR = 0x00000000; + break; + + case -1: /*** Button B ***/ + case 9: + /*** Return to Game ***/ + quit = 1; + break; + + } + + } + + /*** Remove any still held buttons ***/ + while( PAD_ButtonsHeld(0) ) + VIDEO_WaitVSync(); + +} diff --git a/source/ngc/menu.h b/source/ngc/menu.h new file mode 100644 index 0000000..62c825f --- /dev/null +++ b/source/ngc/menu.h @@ -0,0 +1,15 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Menu + * + * softdev July 2006 + ****************************************************************************/ + +#ifndef _NGCMENU_ + +#define _NGCMENU_ + +void mainmenu (); + +#endif diff --git a/source/ngc/ngc-missing.cpp b/source/ngc/ngc-missing.cpp new file mode 100644 index 0000000..d387d34 --- /dev/null +++ b/source/ngc/ngc-missing.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * + * ngc_missing.cpp + * + * This file contains the missing low-level file I/O function definitions. + * Note that these are DUMMY functions, and only allow Snes9x to + * compile. Where possible, they will return an error signal. + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ + +#include +#include +#include +#include + +/*** splitpath function ***/ +void +_splitpath (char const *buffer, char *drive, char *dir, char *fname, + char *ext) +{ + return; /*** Do nothing - NGC code should NEVER call a function which relies on it ***/ +} + +void +_makepath (char *filename, const char *drive, const char *dir, + const char *fname, const char *ext) +{ + return; /*** Do nothing - NGC code should NEVER call a function which relies on it ***/ +} + +char * +S9xBasename (char *name) +{ + return name; +} diff --git a/source/ngc/ngcunzip.cpp b/source/ngc/ngcunzip.cpp new file mode 100644 index 0000000..23089ea --- /dev/null +++ b/source/ngc/ngcunzip.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Unzip - borrowed from the GPP + * + * softdev July 2006 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "dvd.h" +#include "video.h" +#include "ftfont.h" +#include "ngcunzip.h" + +/* + * PKWare Zip Header - adopted into zip standard + */ +#define PKZIPID 0x504b0304 +#define MAXROM 0x500000 +#define ZIPCHUNK 2048 + +/* + * Zip files are stored little endian + * Support functions for short and int types + */ +u32 +FLIP32 (u32 b) +{ + unsigned int c; + + c = (b & 0xff000000) >> 24; + c |= (b & 0xff0000) >> 8; + c |= (b & 0xff00) << 8; + c |= (b & 0xff) << 24; + + return c; +} + +u16 +FLIP16 (u16 b) +{ + u16 c; + + c = (b & 0xff00) >> 8; + c |= (b & 0xff) << 8; + + return c; +} + +/**************************************************************************** + * IsZipFile + * + * Returns TRUE when PKZIPID is first four characters of buffer + ****************************************************************************/ +int +IsZipFile (char *buffer) +{ + unsigned int *check; + + check = (unsigned int *) buffer; + + if (check[0] == PKZIPID) + return 1; + + return 0; +} + + /***************************************************************************** + * unzip + * + * It should be noted that there is a limit of 5MB total size for any ROM + ******************************************************************************/ +int +UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length) +{ + PKZIPHEADER pkzip; + int zipoffset = 0; + int zipchunk = 0; + char out[ZIPCHUNK]; + z_stream zs; + int res; + int bufferoffset = 0; + int have = 0; + char readbuffer[2048]; + char msg[128]; + + /*** Read Zip Header ***/ + dvd_read (readbuffer, 2048, discoffset); + + /*** Copy PKZip header to local, used as info ***/ + memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER)); + + sprintf (msg, "Unzipping %d bytes ... Wait", + FLIP32 (pkzip.uncompressedSize)); + ShowAction (msg); + + /*** Prepare the zip stream ***/ + memset (&zs, 0, sizeof (z_stream)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + res = inflateInit2 (&zs, -MAX_WBITS); + + if (res != Z_OK) + return 0; + + /*** Set ZipChunk for first pass ***/ + zipoffset = + (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + zipchunk = ZIPCHUNK - zipoffset; + + /*** Now do it! ***/ + do + { + zs.avail_in = zipchunk; + zs.next_in = (Bytef *) & readbuffer[zipoffset]; + + /*** Now inflate until input buffer is exhausted ***/ + do + { + zs.avail_out = ZIPCHUNK; + zs.next_out = (Bytef *) & out; + + res = inflate (&zs, Z_NO_FLUSH); + + if (res == Z_MEM_ERROR) + { + inflateEnd (&zs); + return 0; + } + + have = ZIPCHUNK - zs.avail_out; + if (have) + { + /*** Copy to normal block buffer ***/ + memcpy (&outbuffer[bufferoffset], &out, have); + bufferoffset += have; + } + + } + while (zs.avail_out == 0); + + /*** Readup the next 2k block ***/ + zipoffset = 0; + zipchunk = ZIPCHUNK; + discoffset += 2048; + + dvd_read (readbuffer, 2048, discoffset); + } + while (res != Z_STREAM_END); + + inflateEnd (&zs); + + if (res == Z_STREAM_END) + { + if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) + return bufferoffset; + else + return FLIP32 (pkzip.uncompressedSize); + } + + return 0; + +} diff --git a/source/ngc/ngcunzip.h b/source/ngc/ngcunzip.h new file mode 100644 index 0000000..946c136 --- /dev/null +++ b/source/ngc/ngcunzip.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Unzip - borrowed from the GPP + * + * softdev July 2006 + ****************************************************************************/ +#ifndef _NGCUNZIP_ +#define _NGCUNZIP_ + +extern int IsZipFile (char *buffer); +int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length); +/* + * Zip file header definition + */ +typedef struct +{ + unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50 + unsigned short zipversion __attribute__ ((__packed__)); + unsigned short zipflags __attribute__ ((__packed__)); + unsigned short compressionMethod __attribute__ ((__packed__)); + unsigned short lastmodtime __attribute__ ((__packed__)); + unsigned short lastmoddate __attribute__ ((__packed__)); + unsigned int crc32 __attribute__ ((__packed__)); + unsigned int compressedSize __attribute__ ((__packed__)); + unsigned int uncompressedSize __attribute__ ((__packed__)); + unsigned short filenameLength __attribute__ ((__packed__)); + unsigned short extraDataLength __attribute__ ((__packed__)); +} +PKZIPHEADER; + +u32 FLIP32 (u32 b); +u16 FLIP16 (u16 b); + +#endif diff --git a/source/ngc/preferences.cpp b/source/ngc/preferences.cpp new file mode 100644 index 0000000..7cfd5fa --- /dev/null +++ b/source/ngc/preferences.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * crunchy2 April 2007-July 2007 + * + * preferences.cpp + * + * Preferences save/load preferences utilities + ****************************************************************************/ +#include +#include +#include +#include + +#include "snes9x.h" +#include "snes9xGx.h" +#include "memmap.h" +#include "srtc.h" +#include "ftfont.h" +#include "mcsave.h" +#include "sdload.h" +#include "smbload.h" + +extern unsigned char savebuffer[]; +extern int currconfig[4]; + +#define PREFSVERSTRING "Snes9x GX 2.0.1b8 Prefs" + +char prefscomment[2][32] = { {PREFSVERSTRING}, {"Preferences"} }; + +/**************************************************************************** + * Prepare Preferences Data + * + * This sets up the save buffer for saving to a memory card. + ****************************************************************************/ +int +preparePrefsData () +{ + int offset = sizeof (saveicon); + int size; + + memset (savebuffer, 0, 0x22000); + + /*** Copy in save icon ***/ + memcpy (savebuffer, saveicon, offset); + + /*** And the prefscomments ***/ + memcpy (savebuffer + offset, prefscomment, 64); + offset += 64; + + /*** Save all settings ***/ + size = sizeof (Settings); + memcpy (savebuffer + offset, &Settings, size); + offset += size; + + /*** Save GC specific settings ***/ + size = sizeof (GCSettings); + memcpy (savebuffer + offset, &GCSettings, size); + offset += size; + + return offset; +} + + +/**************************************************************************** + * Decode Preferences Data + ****************************************************************************/ +void +decodePrefsData () +{ + int offset; + char prefscomment[32]; + + offset = sizeof (saveicon); + memcpy (prefscomment, savebuffer + offset, 32); + + if ( strcmp (prefscomment, PREFSVERSTRING) == 0 ) + { + offset += 64; + memcpy (&Settings, savebuffer + offset, sizeof (Settings)); + offset += sizeof (Settings); + memcpy (&GCSettings, savebuffer + offset, sizeof (GCSettings)); + } + else + WaitPrompt("Preferences reset - check settings!"); +} + +void quickLoadPrefs (bool8 silent) +{ + switch ( QUICK_SAVE_SLOT ) + { + case CARD_SLOTA: + case CARD_SLOTB: + LoadPrefsFromMC(QUICK_SAVE_SLOT, silent); + break; + + case CARD_SLOTA+2: + case CARD_SLOTB+2: + LoadPrefsFromSD(QUICK_SAVE_SLOT-2, silent); + break; + + case CARD_SLOTA+4: + LoadPrefsFromSMB(silent); + break; + } +} + +void quickSavePrefs (bool8 silent) +{ + switch ( QUICK_SAVE_SLOT ) + { + case CARD_SLOTA: + case CARD_SLOTB: + SavePrefsToMC(QUICK_SAVE_SLOT, silent); + break; + case CARD_SLOTA+2: + case CARD_SLOTB+2: + SavePrefsToSD(QUICK_SAVE_SLOT-2, silent); + break; + case CARD_SLOTA+4: + SavePrefsToSMB(silent); + break; + } +} diff --git a/source/ngc/preferences.h b/source/ngc/preferences.h new file mode 100644 index 0000000..75eb511 --- /dev/null +++ b/source/ngc/preferences.h @@ -0,0 +1,18 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * crunchy2 April 2007 + * + * preferences.cpp + * + * Preferences save/load preferences utilities + ****************************************************************************/ + +#define PREFS_FILE_NAME "snes9xGx.prf" + +int preparePrefsData (); +void decodePrefsData (); + +void quickLoadPrefs (bool8 silent); +void quickSavePrefs (bool8 silent); diff --git a/source/ngc/s9xconfig.cpp b/source/ngc/s9xconfig.cpp new file mode 100644 index 0000000..206cb7d --- /dev/null +++ b/source/ngc/s9xconfig.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * s9xconfig.cpp + * + * Configuration parameters have been moved here for easier maintenance. + * Refer to Snes9x.h for all combinations. + * The defaults used here are taken directly from porting.html + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ +#include +#include "snes9x.h" +#include "snes9xGX.h" +#include "smbload.h" + +void +DefaultSettings () +{ + /*** Default ALL to false ***/ + memset (&Settings, 0, sizeof (Settings)); + + /*** General ***/ + Settings.MouseMaster = true; + Settings.SuperScopeMaster = true; + Settings.MultiPlayer5Master = false; + Settings.JustifierMaster = true; + Settings.ShutdownMaster = false; + Settings.CyclesPercentage = 100; // snes9x 1.50 and earlier + + /* Eke-Eke: specific to snes9x 1.51 */ +// Settings.BlockInvalidVRAMAccess = true; +// Settings.HDMATimingHack = 100; + + /*** Sound defaults. On GC this is 32Khz/16bit/Stereo/InterpolatedSound ***/ + Settings.APUEnabled = true; + Settings.NextAPUEnabled = true; + Settings.SoundPlaybackRate = 32000; + Settings.Stereo = true; + Settings.SixteenBitSound = true; + Settings.SoundEnvelopeHeightReading = true; + Settings.DisableSampleCaching = true; + Settings.InterpolatedSound = true; + Settings.ReverseStereo = false; + + /*** Graphics ***/ + Settings.Transparency = true; + Settings.SupportHiRes = true; + Settings.SkipFrames = 10; + Settings.TurboSkipFrames = 19; + Settings.DisplayFrameRate = false; +// Settings.AutoDisplayMessages = 1; /*** eke-eke snes9x 1.51 ***/ + + /* Eke-Eke: frame timings in 50hz and 60hz cpu mode */ + Settings.FrameTimePAL = 20000; + Settings.FrameTimeNTSC = 16667; + + /*** SDD1 - Star Ocean Returns -;) ***/ + Settings.SDD1Pack = true; + + GCSettings.AutoLoad = 0; + GCSettings.AutoSave = 0; + + strncpy (GCSettings.gcip, GC_IP, 15); + strncpy (GCSettings.gwip, GW_IP, 15); + strncpy (GCSettings.mask, MASK, 15); + strncpy (GCSettings.smbip, SMB_IP, 15); + strncpy (GCSettings.smbuser, SMB_USER, 19); + strncpy (GCSettings.smbpwd, SMB_PWD, 19); + strncpy (GCSettings.smbgcid, SMB_GCID, 19); + strncpy (GCSettings.smbsvid, SMB_SVID, 19); + strncpy (GCSettings.smbshare, SMB_SHARE, 19); + + GCSettings.NGCZoom = 0; + GCSettings.VerifySaves = 0; + + Settings.ForceNTSC = 0; + Settings.ForcePAL = 0; + Settings.ForceHiROM = 0; + Settings.ForceLoROM = 0; + Settings.ForceHeader = 0; + Settings.ForceNoHeader = 0; + Settings.ForceTransparency = 0; + Settings.ForceInterleaved = 0; + Settings.ForceInterleaved2 = 0; + Settings.ForceInterleaveGD24 = 0; + Settings.ForceNotInterleaved = 0; + Settings.ForceNoSuperFX = 0; + Settings.ForceSuperFX = 0; + Settings.ForceDSP1 = 0; + Settings.ForceNoDSP1 = 0; + +} + diff --git a/source/ngc/s9xconfig.h b/source/ngc/s9xconfig.h new file mode 100644 index 0000000..946b7f5 --- /dev/null +++ b/source/ngc/s9xconfig.h @@ -0,0 +1,162 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * + * s9xconfig.h + * + * Configuration parameters have been moved here for easier maintenance. + * Refer to Snes9x.h for all combinations. + * The defaults used here are taken directly from porting.html + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ +#ifndef _S9XCONFIG_ + +#define _S9XCONFIG_ + +void DefaultSettings (); + +#endif diff --git a/source/ngc/s9xsupport.cpp b/source/ngc/s9xsupport.cpp new file mode 100644 index 0000000..a948644 --- /dev/null +++ b/source/ngc/s9xsupport.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * s9xsupport.cpp + * + * This file contains the supporting functions defined in porting.html, with + * others taken from unix/x11.cpp and unix/unix.cpp + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ +#include +#include +#include +#include +#include + +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" +#include "controls.h" +#include "gctime.h" +#include "snes9xGx.h" + + +#include "video.h" +#include "audio.h" + +extern u32 FrameTimer; + +tb_t prev; +tb_t now; + + +/*** Miscellaneous Functions ***/ +void +S9xMessage (int /*type */ , int /*number */ , const char *message) +{ +#define MAX_MESSAGE_LEN (36 * 3) + + static char buffer[MAX_MESSAGE_LEN + 1]; + strncpy (buffer, message, MAX_MESSAGE_LEN); + buffer[MAX_MESSAGE_LEN] = 0; + S9xSetInfoString (buffer); +} + +void +S9xExit () +{ + /*** Nintendo Gamecube will NEVER get here ... unless + something major went wrong !! + + In which case, I'll settle for a reboot first -;) + ***/ +} + +/*** File based functions ***/ +const char * +S9xChooseFilename (bool8 read_only) +{ + return NULL; +} + +const char * +S9xChooseMovieFilename (bool8 read_only) +{ + return NULL; +} + +const char * +S9xGetDirectory (enum s9x_getdirtype dirtype) +{ + return NULL; +} + +const char * +S9xGetFilename (const char *ex, enum s9x_getdirtype dirtype) +{ + return NULL; +} + +const char * +S9xGetFilenameInc (const char *e, enum s9x_getdirtype dirtype) +{ + return NULL; +} + +/*** Memory based functions ***/ +void +S9xAutoSaveSRAM () +{ + //Memory.SaveSRAM (S9xGetFilename (".srm", SRAM_DIR)); +} + +/*** Sound based functions ***/ +void +S9xToggleSoundChannel (int c) +{ + if (c == 8) + so.sound_switch = 255; + else + so.sound_switch ^= 1 << c; + S9xSetSoundControl (so.sound_switch); +} + +/**************************************************************************** + * OpenSoundDevice + * + * Main initialisation for NGC sound system + ****************************************************************************/ +bool8 +S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size) +{ + so.stereo = TRUE; + so.playback_rate = 32000; + so.sixteen_bit = TRUE; + so.encoded = 0; + so.buffer_size = 4096; + so.sound_switch = 255; + S9xSetPlaybackRate (so.playback_rate); + + InitGCAudio (); + return TRUE; +} + +/*** Deprecated function. NGC uses threaded sound ***/ +void +S9xGenerateSound () +{ +} + +/* eke-eke */ +void S9xInitSync() +{ + FrameTimer = 0; + mftb(&prev); +} + +/*** Synchronisation ***/ +void +S9xSyncSpeed () +{ + uint32 skipFrms = Settings.SkipFrames; + + if ( Settings.TurboMode ) + skipFrms = Settings.TurboSkipFrames; + + if ( !Settings.PAL ) /* use NGC vertical sync (VSYNC) with NTSC roms */ + { + while (FrameTimer == 0) + { + usleep (50); + } + + if (FrameTimer > skipFrms) + FrameTimer = skipFrms; + + if ((FrameTimer > 1) && (IPPU.SkippedFrames < skipFrms)) + { + IPPU.SkippedFrames++; + IPPU.RenderThisFrame = FALSE; + } + else + { + IPPU.SkippedFrames = 0; + IPPU.RenderThisFrame = TRUE; + } + } + else /* use internal timer for PAL roms */ + { + unsigned int timediffallowed = Settings.TurboMode ? 0 : Settings.FrameTime; + + mftb(&now); + + if (tb_diff_usec(&now, &prev) > timediffallowed) + { + /*while ( tb_diff_usec(&now, &prev) < timediffallowed * 2) { + mftb(&now); + }*/ + + /* Timer has already expired */ + if (IPPU.SkippedFrames < skipFrms) + { + IPPU.SkippedFrames++; + IPPU.RenderThisFrame = FALSE; + } + else + { + IPPU.SkippedFrames = 0; + IPPU.RenderThisFrame = TRUE; + } + } + else + { + /*** Ahead - so hold up ***/ + while (tb_diff_usec(&now, &prev) < timediffallowed) mftb(&now); + IPPU.RenderThisFrame = TRUE; + IPPU.SkippedFrames = 0; + } + + memcpy(&prev, &now, sizeof(tb_t)); + } + + if ( !Settings.TurboMode ) + FrameTimer--; + return; + +} + +/*** Video / Display related functions ***/ +bool8 +S9xInitUpdate () +{ + /*** + * Is this necessary in 1.50 ? + * memset (GFX.Screen, 0, IMAGE_WIDTH * IMAGE_HEIGHT * 2); + */ + return (TRUE); +} + +bool8 +S9xDeinitUpdate (int Width, int Height) +{ + update_video (Width, Height); + return (TRUE); +} + +bool8 +S9xContinueUpdate (int Width, int Height) +{ + return (TRUE); +} + +void +S9xSetPalette () +{ + return; +} + +/*** Input functions ***/ +void +S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2) +{ + return; +} + +bool +S9xPollButton (uint32 id, bool * pressed) +{ + return 0; +} + +bool +S9xPollAxis (uint32 id, int16 * value) +{ + return 0; +} + +bool +S9xPollPointer (uint32 id, int16 * x, int16 * y) +{ + return 0; +} + +void +S9xLoadSDD1Data () +{ + + Memory.FreeSDD1Data (); + + Settings.SDD1Pack = FALSE; + + if (strncmp (Memory.ROMName, "Star Ocean", 10) == 0) + Settings.SDD1Pack = TRUE; + + if (strncmp (Memory.ROMName, "STREET FIGHTER ALPHA2", 21) == 0) + Settings.SDD1Pack = TRUE; + + return; + +} diff --git a/source/ngc/sdload.cpp b/source/ngc/sdload.cpp new file mode 100644 index 0000000..893c18a --- /dev/null +++ b/source/ngc/sdload.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * sdload.cpp + * + * Load ROMS from SD Card + ****************************************************************************/ +#include +#include +#include +#include +#include "sdcard.h" +#include "ngcunzip.h" +#include "memmap.h" +#include "video.h" +#include "ftfont.h" +#include "dvd.h" +#include "filesel.h" +#include "sram.h" +#include "preferences.h" + +#include +extern unsigned char savebuffer[]; +extern char output[16384]; +char rootSDdir[SDCARD_MAX_PATH_LEN]; +extern int offset; +extern int selection; + + +/*************************************************************************** + * Update SDCARD curent directory name + ***************************************************************************/ +int updateSDdirname() +{ + int size=0; + char *test; + char temp[1024]; + + /* current directory doesn't change */ + if (strcmp(filelist[selection].filename,".") == 0) return 0; + + /* go up to parent directory */ + else if (strcmp(filelist[selection].filename,"..") == 0) + { + /* determine last subdirectory namelength */ + sprintf(temp,"%s",rootSDdir); + test= strtok(temp,"\\"); + while (test != NULL) + { + size = strlen(test); + test = strtok(NULL,"\\"); + } + + /* remove last subdirectory name */ + size = strlen(rootSDdir) - size - 1; + rootSDdir[size] = 0; + + /* handles root name */ + if (strcmp(rootSDdir,"dev0:") == 0) + { + sprintf(rootSDdir,"dev0:\\SNESROMS"); + return -1; + } + + return 1; + } + else + { + /* test new directory namelength */ + if ((strlen(rootSDdir)+1+strlen(filelist[selection].filename)) < SDCARD_MAX_PATH_LEN) + { + /* handles root name */ + if (strcmp(rootSDdir,"dev0:\\SNESROMS\\..") == 0) sprintf(rootSDdir,"dev0:"); + + /* update current directory name */ + sprintf(rootSDdir, "%s\\%s",rootSDdir, filelist[selection].filename); + return 1; + } + else + { + WaitPrompt ("Dirname is too long !"); + return -1; + } + } +} + +/*************************************************************************** + * Browse SDCARD subdirectories + ***************************************************************************/ +int parseSDdirectory() +{ + int entries = 0; + int nbfiles = 0; + DIR *sddir = NULL; + char tname[1024]; + + offset = selection = 0; + + /* Get a list of files from the actual root directory */ + entries = SDCARD_ReadDir (rootSDdir, &sddir); + + if (entries < 0) entries = 0; + if (entries > MAXFILES) entries = MAXFILES; + + /* Move to DVD structure - this is required for the file selector */ + while (entries) + { + memcpy (tname, &sddir[nbfiles].fname, 1024); + memset (&filelist[nbfiles], 0, sizeof (FILEENTRIES)); + strncpy(filelist[nbfiles].filename,tname,MAXJOLIET+1); + filelist[nbfiles].filename[MAXJOLIET] = 0; + strncpy(filelist[nbfiles].displayname,tname,MAXDISPLAY+1); + filelist[nbfiles].filename[MAXDISPLAY] = 0; + filelist[nbfiles].length = sddir[nbfiles].fsize; + filelist[nbfiles].flags = (char)(sddir[nbfiles].fattr & SDCARD_ATTR_DIR); + nbfiles++; + entries--; + } + + /*** Release memory ***/ + free(sddir); + + return nbfiles; +} + +/**************************************************************************** + * LoadSDFile + ****************************************************************************/ +extern int haveSDdir; +int +LoadSDFile (char *filename, int length) +{ + char zipbuffer[2048]; + char filepath[SDCARD_MAX_PATH_LEN]; + sd_file *handle; + char *rbuffer; + PKZIPHEADER pkzip; + z_stream zs; + int res, outbytes = 0; + int size; + int have; + + rbuffer = (char *) Memory.ROM; + + /* Check filename length */ + if ((strlen(rootSDdir)+1+strlen(filelist[selection].filename)) < SDCARD_MAX_PATH_LEN) + sprintf(filepath, "%s\\%s",rootSDdir,filelist[selection].filename); + else + { + WaitPrompt ("Maximum Filename Length reached !"); + haveSDdir = 0; // reset everything before next access + return -1; + } + + handle = SDCARD_OpenFile (filepath, "rb"); + if (handle > 0) + { + SDCARD_ReadFile (handle, zipbuffer, 2048); + + if (IsZipFile (zipbuffer)) + { + /*** Unzip the ROM ***/ + memcpy (&pkzip, zipbuffer, sizeof (PKZIPHEADER)); + pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize); + memset (&zs, 0, sizeof (zs)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + + res = inflateInit2 (&zs, -MAX_WBITS); + + if (res != Z_OK) + { + SDCARD_CloseFile (handle); + return 0; + } + + size = (sizeof (PKZIPHEADER) + + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + + do + { + zs.avail_in = 2048 - size; + zs.next_in = (Bytef *) zipbuffer + size; + + do + { + zs.avail_out = 16384; + zs.next_out = (Bytef *) output; + + res = inflate (&zs, Z_NO_FLUSH); + + have = 16384 - zs.avail_out; + + if (have) + { + memcpy (rbuffer + outbytes, output, have); + outbytes += have; + } + + } + while (zs.avail_out == 0); + + sprintf (filepath, "Read %d bytes of %d", outbytes, + pkzip.uncompressedSize); + //ShowAction (filepath); + ShowProgress (filepath, outbytes, pkzip.uncompressedSize); + + size = 0; + SDCARD_ReadFile (handle, zipbuffer, 2048); + + } + while (res != Z_STREAM_END + && (u32) outbytes < pkzip.uncompressedSize); + + inflateEnd (&zs); + + SDCARD_CloseFile (handle); + return pkzip.uncompressedSize; + + } + else + { + /*** Just load the file up ***/ + length = SDCARD_GetFileSize (handle); + sprintf (filepath, "Loading %d bytes", length); + ShowAction (filepath); + memcpy (rbuffer, zipbuffer, 2048); + SDCARD_ReadFile (handle, rbuffer + 2048, length - 2048); + SDCARD_CloseFile (handle); + return length; + } + } + else + { + WaitPrompt ("Error opening file"); + return 0; + } + + return 0; +} + + + +/**************************************************************************** + * Load savebuffer from SD card file + ****************************************************************************/ +int +LoadBufferFromSD (char *filepath, bool8 silent) +{ + sd_file *handle; + int offset = 0; + int read = 0; + + SDCARD_Init (); + + handle = SDCARD_OpenFile (filepath, "rb"); + + if (handle <= 0) + { + if ( !silent ) + { + char msg[100]; + sprintf(msg, "Couldn't open %s", filepath); + WaitPrompt (msg); + } + return 0; + } + + memset (savebuffer, 0, 0x22000); + + /*** This is really nice, just load the file and decode it ***/ + while ((read = SDCARD_ReadFile (handle, savebuffer + offset, 1024)) > 0) + { + offset += read; + } + + SDCARD_CloseFile (handle); + + return offset; +} + + +/**************************************************************************** + * Write savebuffer to SD card file + ****************************************************************************/ +int +SaveBufferToSD (char *filepath, int datasize, bool8 silent) +{ + sd_file *handle; + + SDCARD_Init (); + + if (datasize) + { + handle = SDCARD_OpenFile (filepath, "wb"); + + if (handle <= 0) + { + char msg[100]; + sprintf(msg, "Couldn't save %s", filepath); + WaitPrompt (msg); + return 0; + } + + SDCARD_WriteFile (handle, savebuffer, datasize); + SDCARD_CloseFile (handle); + } + + return datasize; +} + + +/**************************************************************************** + * Save SRAM to SD Card + ****************************************************************************/ +void +SaveSRAMToSD (uint8 slot, bool8 silent) +{ + char filepath[1024]; + int datasize; + int offset; + + ShowAction ("Saving SRAM to SD..."); + +#ifdef SDUSE_LFN + sprintf (filepath, "dev%d:\\%s\\%s.srm", slot, SNESSAVEDIR, Memory.ROMName); +#else + sprintf (filepath, "dev%d:\\SNESSAVE\\%08x.srm", slot, Memory.ROMCRC32); +#endif + + datasize = prepareEXPORTsavedata (); + + if ( datasize ) + { + offset = SaveBufferToSD (filepath, datasize, silent); + + if ( (offset > 0) && (!silent) ) + { + sprintf (filepath, "Wrote %d bytes", offset); + WaitPrompt (filepath); + } + } +} + + +/**************************************************************************** + * Load SRAM From SD Card + ****************************************************************************/ +void +LoadSRAMFromSD (uint8 slot, bool8 silent) +{ + char filepath[1024]; + int offset = 0; + + ShowAction ("Loading SRAM from SD..."); + +#ifdef SDUSE_LFN + sprintf (filepath, "dev%d:\\%s\\%s.srm", slot, SNESSAVEDIR, Memory.ROMName); + // sprintf (filepath, "dev%d:\\%s.srm", Memory.ROMName); +#else + sprintf (filepath, "dev%d:\\SNESSAVE\\%08x.srm", slot, Memory.ROMCRC32); + // sprintf (filepath, "dev0:\\%08x.srm", Memory.ROMCRC32); +#endif + + offset = LoadBufferFromSD (filepath, silent); + + if (offset > 0) + { + decodesavedata (offset); + if ( !silent ) + { + sprintf (filepath, "Loaded %d bytes", offset); + WaitPrompt(filepath); + } + S9xSoftReset(); + } +} + + +/**************************************************************************** + * Save Preferences to SD Card + ****************************************************************************/ +void +SavePrefsToSD (uint8 slot, bool8 silent) +{ + char filepath[1024]; + int datasize; + int offset; + + ShowAction ("Saving prefs to SD..."); + +#ifdef SDUSE_LFN + sprintf (filepath, "dev%d:\\%s\\%s", slot, SNESSAVEDIR, PREFS_FILE_NAME); +#else + sprintf (filepath, "dev%d:\\SNESSAVE\\%s", slot, PREFS_FILE_NAME); +#endif + + datasize = preparePrefsData (); + offset = SaveBufferToSD (filepath, datasize, silent); + + if ( (offset > 0) && (!silent) ) + { + sprintf (filepath, "Wrote %d bytes", offset); + WaitPrompt (filepath); + } +} + + +/**************************************************************************** + * Load Preferences from SD Card + ****************************************************************************/ +void +LoadPrefsFromSD (uint8 slot, bool8 silent) +{ + char filepath[1024]; + int offset = 0; + + ShowAction ("Loading prefs from SD..."); + +#ifdef SDUSE_LFN + sprintf (filepath, "dev%d:\\%s\\%s", slot, SNESSAVEDIR, PREFS_FILE_NAME); + // sprintf (filepath, "dev%d:\\%s.srm", Memory.ROMName); +#else + sprintf (filepath, "dev%d:\\SNESSAVE\\%s", slot, PREFS_FILE_NAME); + // sprintf (filepath, "dev0:\\%08x.srm", Memory.ROMCRC32); +#endif + + offset = LoadBufferFromSD (filepath, silent); + + if (offset > 0) + { + decodePrefsData (); + if ( !silent ) + { + sprintf (filepath, "Loaded %d bytes", offset); + WaitPrompt(filepath); + } + } +} diff --git a/source/ngc/sdload.h b/source/ngc/sdload.h new file mode 100644 index 0000000..cadc02b --- /dev/null +++ b/source/ngc/sdload.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * sdload.cpp + * + * Load ROMS from SD Card + ****************************************************************************/ + +#ifndef _LOADFROMSDC_ +#define _LOADFROMSDC_ +#include + +int updateSDdirname(); +int parseSDdirectory(); +int LoadSDFile (char *filename, int length); +void SaveSRAMToSD (uint8 slot, bool8 silent); +void LoadSRAMFromSD (uint8 slot, bool8 silent); +void SavePrefsToSD (uint8 slot, bool8 silent); +void LoadPrefsFromSD (uint8 slot, bool8 silent); + +extern char rootSDdir[SDCARD_MAX_PATH_LEN]; + +#endif diff --git a/source/ngc/smbload.cpp b/source/ngc/smbload.cpp new file mode 100644 index 0000000..783737a --- /dev/null +++ b/source/ngc/smbload.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * smbload.cpp + * + * Load ROMS from a Network share. + ****************************************************************************/ +#include +#include +#include +#include +#include +extern "C" +{ +#include "smb.h" +} +#include "ngcunzip.h" +#include "memmap.h" +#include "video.h" +#include "ftfont.h" +#include "dvd.h" +#include "filesel.h" +#include "sram.h" +#include "preferences.h" +#include "smbload.h" +#include "Snes9xGx.h" +#include + +static int connected = 0; +static int netinited = 0; + +char output[16384]; +unsigned int SMBTimer = 0; +extern unsigned char savebuffer[]; + +#define ZIPCHUNK 16384 +#define SMBTIMEOUT ( 3600 ) /*** Some implementations timeout in 10 minutes ***/ +SMBINFO smbinfo = + { GC_IP, GW_IP, MASK, SMB_IP, + SMB_USER, SMB_PWD, SMB_GCID, SMB_SVID, SMB_SHARE +}; + +/**************************************************************************** + * Mount SMB Share + ****************************************************************************/ +void +ConnectSMB () +{ + int ret; + + if (SMBTimer > SMBTIMEOUT) + { + connected = 0; + SMBTimer = 0; + } + + if (connected == 0) + { + + if (netinited == 0) + { + ShowAction ("Setting up network interface ..."); + ret = if_config (smbinfo.gcip, smbinfo.gwip, smbinfo.mask, 0); + netinited = 1; + } + + ShowAction ("Connecting to share ..."); + SMB_Destroy (); + + if (SMB_Init (smbinfo.smbuser, smbinfo.smbpwd, + smbinfo.smbgcid, smbinfo.smbsvid, smbinfo.smbshare, + smbinfo.smbip) != SMB_SUCCESS) + { + WaitPrompt ("Failed to connect to SMB share"); + connected = 0; + return; + } + } + + connected = 1; + +} + +/**************************************************************************** + * parseSMBDirectory + * + * Load the share directory and put in the filelist array + *****************************************************************************/ +int +parseSMBDirectory () +{ + char searchpath[1024]; + int filecount = 0; + SMBDIRENTRY smbdir; + + ConnectSMB (); + + strcpy (searchpath, SNESROMDIR); + strcat (searchpath, "\\*.*"); + + if (SMB_FindFirst + (searchpath, SMB_SRCH_READONLY | SMB_SRCH_SYSTEM | SMB_SRCH_HIDDEN, + &smbdir) != SMB_SUCCESS) + { + return 0; + } + + do + { + memset (&filelist[filecount], 0, sizeof (FILEENTRIES)); + filelist[filecount].length = smbdir.size_low; + smbdir.name[MAXJOLIET] = 0; + + /*** Update display name ***/ + memcpy (&filelist[filecount].displayname, smbdir.name, MAXDISPLAY); + filelist[filecount].displayname[MAXDISPLAY] = 0; + + strcpy (filelist[filecount].filename, smbdir.name); + filecount++; + + } + while (SMB_FindNext (&smbdir) == SMB_SUCCESS); + + SMB_FindClose (); + + return filecount; +} + +/**************************************************************************** + * Load SMB file + ****************************************************************************/ +int +LoadSMBFile (char *filename, int length) +{ + char buffer[128]; + int offset = 0; + int bytesread = 0; + int total = 0; + char filepath[1024]; + SMBFILE smbfile; + char *rbuffer; + char zipbuffer[16384]; + int pass = 0; + int zip = 0; + PKZIPHEADER pkzip; + z_stream zs; + int res, outbytes; + + strcpy (filepath, SNESROMDIR); + strcat (filepath, "\\"); + strcat (filepath, filename); + rbuffer = (char *) Memory.ROM; + outbytes = 0; + int have = 0; + + ConnectSMB (); + + if ( connected ) + { + + /*** Open the file for reading ***/ + smbfile = + SMB_Open (filepath, SMB_OPEN_READING | SMB_DENY_NONE, SMB_OF_OPEN); + if (smbfile) + { + while (total < length) + { + bytesread = SMB_Read (zipbuffer, 16384, offset, smbfile); + + if (pass == 0) + { + /*** Is this a Zip file ? ***/ + zip = IsZipFile (zipbuffer); + if (zip) + { + memcpy (&pkzip, zipbuffer, sizeof (PKZIPHEADER)); + pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize); + memset (&zs, 0, sizeof (zs)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + res = inflateInit2 (&zs, -MAX_WBITS); + + if (res != Z_OK) + { + SMB_Close (smbfile); + return 0; + } + + zs.avail_in = + 16384 - (sizeof (PKZIPHEADER) + + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + zs.next_in = + (Bytef *) zipbuffer + (sizeof (PKZIPHEADER) + + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + } + } + + if (zip) + { + if (pass) + { + zs.avail_in = bytesread; + zs.next_in = (Bytef *) zipbuffer; + } + + do + { + zs.avail_out = ZIPCHUNK; + zs.next_out = (Bytef *) output; + + res = inflate (&zs, Z_NO_FLUSH); + + have = ZIPCHUNK - zs.avail_out; + + if (have) + { + memcpy (rbuffer + outbytes, output, have); + outbytes += have; + } + } + while (zs.avail_out == 0); + } + else + memcpy (rbuffer + offset, zipbuffer, bytesread); + + total += bytesread; + offset += bytesread; + + if (!zip) + { + sprintf (buffer, "Read %d of %d bytes", total, length); + ShowProgress (buffer, total, length); + } + else + { + sprintf (buffer, "Unzipped %d of %d", outbytes, + pkzip.uncompressedSize); + ShowProgress (buffer, outbytes, pkzip.uncompressedSize); + } + //ShowAction (buffer); + + pass++; + + } + + if (zip) + { + inflateEnd (&zs); + total = outbytes; + } + + SMB_Close (smbfile); + + return total; + } + else + { + WaitPrompt ("SMB Reading Failed!"); + //while (1); + return 0; + } + } + + return 0; +} + + +/**************************************************************************** + * Write savebuffer to SMB file + ****************************************************************************/ +int +SaveBufferToSMB (char *filepath, int datasize, bool8 silent) +{ + SMBFILE smbfile; + int dsize = datasize; + int wrote = 0; + int offset = 0; + + ConnectSMB (); + + if ( connected ) + { + smbfile = + SMB_Open (filepath, SMB_OPEN_WRITING | SMB_DENY_NONE, + SMB_OF_CREATE | SMB_OF_TRUNCATE); + + if (smbfile) + { + while (dsize > 0) + { + if (dsize > 1024) + wrote = + SMB_Write ((char *) savebuffer + offset, 1024, offset, smbfile); + else + wrote = + SMB_Write ((char *) savebuffer + offset, dsize, offset, smbfile); + + offset += wrote; + dsize -= wrote; + } + + SMB_Close (smbfile); + SMBTimer = 0; + + return offset; + } + else + { + char msg[100]; + sprintf(msg, "Couldn't save SMB:%s", filepath); + WaitPrompt (msg); + } + } + + return 0; +} + + +/**************************************************************************** + * Load savebuffer from SMB file + ****************************************************************************/ +int +LoadBufferFromSMB (char *filepath, bool8 silent) +{ + SMBFILE smbfile; + int ret; + int offset = 0; + + ConnectSMB (); + + if ( connected ) + { + smbfile = + SMB_Open (filepath, SMB_OPEN_READING | SMB_DENY_NONE, SMB_OF_OPEN); + + if (!smbfile) + { + if (!silent) + { + char msg[100]; + sprintf(msg, "Couldn't open SMB:%s", filepath); + WaitPrompt (msg); + } + return 0; + } + + memset (savebuffer, 0, 0x22000); + + while ((ret = + SMB_Read ((char *) savebuffer + offset, 1024, offset, + smbfile)) > 0) + offset += ret; + + SMB_Close (smbfile); + + return offset; + } + + return 0; +} + + +/**************************************************************************** + * Save SRAM to SMB + ****************************************************************************/ +void +SaveSRAMToSMB (bool8 silent) +{ + char filepath[1024]; + int datasize; + int offset; + + sprintf (filepath, "%s\\%s.srm", SNESSAVEDIR, Memory.ROMName); + ShowAction ("Saving SRAM to SMB..."); + + datasize = prepareEXPORTsavedata (); + + if ( datasize ) + { + offset = SaveBufferToSMB (filepath, datasize, silent); + + if ( (offset > 0) && (!silent) ) + { + sprintf (filepath, "Wrote %d bytes", offset); + WaitPrompt (filepath); + } + } +} + +/**************************************************************************** + * Load SRAM from SMB + ****************************************************************************/ +void +LoadSRAMFromSMB (bool8 silent) +{ + char filepath[1024]; + int offset; + + sprintf (filepath, "%s\\%s.srm", SNESSAVEDIR, Memory.ROMName); + ShowAction ("Loading SRAM from SMB..."); + + offset = LoadBufferFromSMB (filepath, silent); + + if (offset > 0) + { + decodesavedata (offset); + if ( !silent ) + { + sprintf (filepath, "Loaded %d bytes", offset); + WaitPrompt(filepath); + } + S9xSoftReset(); + } +} + + +/**************************************************************************** + * Save Preferences to SMB + ****************************************************************************/ +void +SavePrefsToSMB (bool8 silent) +{ + char filepath[1024]; + int datasize; + int offset; + + sprintf (filepath, "%s\\%s", SNESSAVEDIR, PREFS_FILE_NAME); + ShowAction ("Saving preferences to SMB..."); + + datasize = preparePrefsData (); + + if ( datasize ) + { + offset = SaveBufferToSMB (filepath, datasize, silent); + + if ( (offset > 0) && (!silent) ) + { + sprintf (filepath, "Wrote %d bytes", offset); + WaitPrompt (filepath); + } + } +} + + +/**************************************************************************** + * Load Preferences from SMB + ****************************************************************************/ +void +LoadPrefsFromSMB (bool8 silent) +{ + char filepath[1024]; + int offset; + + ShowAction ("Loading preferences from SMB..."); + + sprintf (filepath, "%s\\%s", SNESSAVEDIR, PREFS_FILE_NAME); + + offset = LoadBufferFromSMB (filepath, silent); + + if (offset > 0) + { + decodePrefsData (); + if ( !silent ) + { + sprintf (filepath, "Loaded %d bytes", offset); + WaitPrompt(filepath); + } + } +} diff --git a/source/ngc/smbload.h b/source/ngc/smbload.h new file mode 100644 index 0000000..c4f1eba --- /dev/null +++ b/source/ngc/smbload.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007 + * + * smbload.cpp + * + * Load ROMS from a Network share. + ****************************************************************************/ + +#ifndef _NGCSMB_ + +#define _NGCSMB_ + +void ConnectSMB (); +int parseSMBDirectory (); +int LoadSMBFile (char *filename, int length); +void SaveSRAMToSMB (bool8 silent); +void LoadSRAMFromSMB (bool8 silent); +void SavePrefsToSMB (bool8 silent); +void LoadPrefsFromSMB (bool8 silent); + +typedef struct +{ + char gcip[16]; + char gwip[16]; + char mask[16]; + char smbip[16]; + char smbuser[20]; + char smbpwd[20]; + char smbgcid[20]; + char smbsvid[20]; + char smbshare[20]; +} +SMBINFO; + + +#endif diff --git a/source/ngc/snes9xGX.cpp b/source/ngc/snes9xGX.cpp new file mode 100644 index 0000000..3978310 --- /dev/null +++ b/source/ngc/snes9xGX.cpp @@ -0,0 +1,612 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007-July 2007 + * + * snes9xGX.cpp + * + * This file controls overall program flow. Most things start and end here! + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ +#include +#include +#include +#include + +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "cpuexec.h" +#include "ppu.h" +#include "apu.h" +#include "display.h" +#include "gfx.h" +#include "soundux.h" +#include "spc700.h" +#include "spc7110.h" +#include "controls.h" + +#include "snes9xGX.h" +#include "dvd.h" +#include "video.h" +#include "ftfont.h" +#include "s9xconfig.h" +#include "audio.h" +#include "menu.h" +#include "sram.h" +#include "memfile.h" +#include "preferences.h" +#include "gctime.h" + +unsigned long ARAM_ROMSIZE = 0; +int ConfigRequested = 0; +extern int FrameTimer; + +extern tb_t prev; +extern unsigned int timediffallowed; + +/**************************************************************************** + * Controller Functions + * + * The following map the NGC Pads to the *NEW* controller system. + ****************************************************************************/ +#define ASSIGN_BUTTON_TRUE( keycode, snescmd ) \ + S9xMapButton( keycode, cmd = S9xGetCommandT(snescmd), true) + +#define ASSIGN_BUTTON_FALSE( keycode, snescmd ) \ + S9xMapButton( keycode, cmd = S9xGetCommandT(snescmd), false) + +#define MAXJP 12 +int padcal = 50; +unsigned short gcpadmap[] = { PAD_BUTTON_A, PAD_BUTTON_B, + PAD_BUTTON_X, PAD_BUTTON_Y, + PAD_TRIGGER_L, PAD_TRIGGER_R, + PAD_TRIGGER_Z, PAD_BUTTON_START, + PAD_BUTTON_UP, PAD_BUTTON_DOWN, + PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT +}; + +#if 0 +/**************************************************************************** + * decodepad + * Called per pad with offset + ****************************************************************************/ +void +decodepadold (int pad) +{ + int i, offset; + signed char x, y; + unsigned short jp; + + /*** Do analogue updates ***/ + x = PAD_StickX (pad); + y = PAD_StickY (pad); + jp = PAD_ButtonsHeld (pad); + + /*** Recalc left / right ***/ + if (x < -padcal) + jp |= PAD_BUTTON_LEFT; + if (x > padcal) + jp |= PAD_BUTTON_RIGHT; + + /*** Recalc up / down ***/ + if (y > padcal) + jp |= PAD_BUTTON_UP; + if (y < -padcal) + jp |= PAD_BUTTON_DOWN; + + /*** Fix offset to pad ***/ + offset = ((pad + 1) << 4); + + for (i = 0; i < MAXJP; i++) + { + if (jp & gcpadmap[i]) + S9xReportButton (offset + i, true); + else + S9xReportButton (offset + i, false); + } +} +#endif + +/**************************************************************************** + * This is the joypad algorithm submitted by Krullo. + ****************************************************************************/ +void +decodepad (int pad) +{ + int i, offset; + signed char x, y; + unsigned short jp; + float t; + + /*** Do analogue updates ***/ + x = PAD_StickX (pad); + y = PAD_StickY (pad); + jp = PAD_ButtonsHeld (pad); + +/*** Is XY inside the "zone"? ***/ + if (x * x + y * y > padcal * padcal) + { + +/*** we don't want division by ZERO ***/ + if (x > 0 && y == 0) + jp |= PAD_BUTTON_RIGHT; + if (x < 0 && y == 0) + jp |= PAD_BUTTON_LEFT; + if (x == 0 && y > 0) + jp |= PAD_BUTTON_UP; + if (x == 0 && y < 0) + jp |= PAD_BUTTON_DOWN; + + if (x != 0 && y != 0) + { + +/*** Recalc left / right ***/ + t = (float) y / x; + if (t >= -2.41421356237 && t < 2.41421356237) + { + if (x >= 0) + jp |= PAD_BUTTON_RIGHT; + else + jp |= PAD_BUTTON_LEFT; + } + +/*** Recalc up / down ***/ + t = (float) x / y; + if (t >= -2.41421356237 && t < 2.41421356237) + { + if (y >= 0) + jp |= PAD_BUTTON_UP; + else + jp |= PAD_BUTTON_DOWN; + } + } + } + + /*** Fix offset to pad ***/ + offset = ((pad + 1) << 4); + + for (i = 0; i < MAXJP; i++) + { + if (jp & gcpadmap[i]) + S9xReportButton (offset + i, true); + else + S9xReportButton (offset + i, false); + } + +} + +/**************************************************************************** + * NGCReportButtons + * Called on each rendered frame + ****************************************************************************/ +void +NGCReportButtons () +{ + s8 px = PAD_SubStickX (0); + s8 py = PAD_SubStickY (0); + u16 pb = PAD_ButtonsHeld (0); + + /*** Check for video zoom ***/ + if (GCSettings.NGCZoom) + { + if (py < -18 || py > 18) + zoom ((float) py / -18); + } + + Settings.TurboMode = (px > 70); + + /*** Check for menu: + CStick left + OR "L+R+X+Y" (eg. Hombrew/Adapted SNES controllers) ***/ + + if ((px < -70) || + ((pb & PAD_TRIGGER_L) && + (pb & PAD_TRIGGER_R ) && + (pb & PAD_BUTTON_X) && + (pb & PAD_BUTTON_Y )) + ) + { + ConfigRequested = 1; + + VIDEO_WaitVSync (); + + if ( GCSettings.AutoSave == 1 ) + { + if ( WaitPromptChoice ("Save SRAM?", "Don't Save", "Save") ) + quickSaveSRAM ( SILENT ); + } + else if ( GCSettings.AutoSave == 2 ) + { + if ( WaitPromptChoice ("Save Freeze State?", "Don't Save", "Save") ) + quickSaveFreeze ( SILENT ); + } + else if ( GCSettings.AutoSave == 3 ) + { + if ( WaitPromptChoice ("Save SRAM and Freeze State?", "Don't Save", "Save") ) + { + quickSaveSRAM ( SILENT ); + quickSaveFreeze ( SILENT ); + } + } + + mainmenu (); + FrameTimer = 0; + ConfigRequested = 0; + } + else + { + int j = (Settings.MultiPlayer5Master == true ? 4 : 2); + for (int i = 0; i < j; i++) + decodepad (i); + } +} + +/**************************************************************************** + * Set the default mapping for NGC + ****************************************************************************/ +void +SetDefaultButtonMap () +{ + int maxcode = 0x10; + s9xcommand_t cmd; + + /*** Joypad 1 ***/ + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 A"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 B"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 X"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Y"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 L"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 R"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Select"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Start"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Up"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Down"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Left"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad1 Right"); + + maxcode = 0x20; + /*** Joypad 2 ***/ + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 A"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 B"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 X"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Y"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 L"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 R"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Select"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Start"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Up"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Down"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Left"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad2 Right"); + + maxcode = 0x30; + /*** Joypad 3 ***/ + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 A"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 B"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 X"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Y"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 L"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 R"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Select"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Start"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Up"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Down"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Left"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad3 Right"); + + maxcode = 0x40; + /*** Joypad 4 ***/ + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 A"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 B"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 X"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Y"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 L"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 R"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Select"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Start"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Up"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Down"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Left"); + ASSIGN_BUTTON_FALSE (maxcode++, "Joypad4 Right"); + + if (Settings.MultiPlayer5Master == false) + { + /*** Plugin 2 Joypads by default ***/ + S9xSetController (0, CTL_JOYPAD, 0, 0, 0, 0); + S9xSetController (1, CTL_JOYPAD, 1, 0, 0, 0); + } + else + { + S9xSetController (0, CTL_JOYPAD, 0, 0, 0, 0); + S9xSetController (1, CTL_MP5, 1, 2, 3, -1); + } + +} + +/**************************************************************************** + * Emulation loop + * + * The 'clock' timer is long gone. + * System now only uses vbl as hardware clock, so force PAL50 if you need 50hz + ****************************************************************************/ +/* Eke-Eke: initialize frame Sync */ +extern void S9xInitSync(); + +void +emulate () +{ + + S9xSetSoundMute (TRUE); +// FrameTimer = 0; + AudioStart (); + S9xInitSync(); + + while (1) + { + S9xMainLoop (); + NGCReportButtons (); + } +} + +/**************************************************************************** + * MAIN + * + * Steps to Snes9x Emulation : + * 1. Initialise GC Video + * 2. Initialise libfreetype (Nice to read something) + * 3. Set S9xSettings to standard defaults (s9xconfig.h) + * 4. Allocate Snes9x Memory + * 5. Allocate APU Memory + * 6. Set Pixel format to RGB565 for GL Rendering + * 7. Initialise Snes9x/GC Sound System + * 8. Initialise Snes9x Graphics subsystem + * 9. Let's Party! + * + * NB: The SNES ROM is now delivered from ARAM. (AR_SNESROM) + * Any method of loading a ROM, RAM, DVD, SMB, SDCard, + * MUST place the unpacked ROM at this location. + * This provides a single consistent interface in memmap.cpp. + * Refer to that file if you need to change it. + ****************************************************************************/ +int +main () +{ + unsigned int save_flags; + + /*** Initialise GC ***/ + InitGCVideo (); /*** Get the ball rolling ***/ + +#ifdef FORCE_WII + isWii = TRUE; +#else + int drvid = dvd_driveid (); + if ( drvid == 4 || drvid == 6 || drvid == 8 ) + isWii = FALSE; + else + isWii = TRUE; +#endif + + /*** Initialise freetype ***/ + if (FT_Init ()) + { + printf ("Cannot initialise font subsystem!\n"); + while (1); + } + + /*** Set defaults ***/ + DefaultSettings (); + + S9xUnmapAllControls (); + SetDefaultButtonMap (); + + printf ("Initialise Memory\n"); + /*** Allocate SNES Memory ***/ + if (!Memory.Init ()) + while (1); + + printf ("Initialise APU\n"); + /*** Allocate APU ***/ + if (!S9xInitAPU ()) + while (1); + + /*** Set Pixel Renderer to match 565 ***/ + S9xSetRenderPixelFormat (RGB565); + + /*** Initialise Snes Sound System ***/ + S9xInitSound (5, TRUE, 1024); + + printf ("Initialise GFX\n"); + /*** Initialise Graphics ***/ + setGFX (); + if (!S9xGraphicsInit ()) + while (1); + + legal (); + WaitButtonA (); + + // Load preferences + quickLoadPrefs(SILENT); + + // Correct any relevant saved settings that are invalid + Settings.FrameTimeNTSC = 16667; + Settings.FrameTimePAL = 20000; + if ( Settings.TurboSkipFrames <= Settings.SkipFrames ) + Settings.TurboSkipFrames = 20; + + /*** No appended ROM, so get the user to load one ***/ + if (ARAM_ROMSIZE == 0) + { + while (ARAM_ROMSIZE == 0) + { + mainmenu (); + } + } + else + { + /*** Load ROM ***/ + save_flags = CPU.Flags; + if (!Memory.LoadROM ("VIRTUAL.ROM")) + while (1); + CPU.Flags = save_flags; + + /*** Load SRAM ***/ + Memory.LoadSRAM ("DVD"); + + if ( GCSettings.AutoLoad == 1 ) + quickLoadSRAM ( SILENT ); + else if ( GCSettings.AutoLoad == 2 ) + quickLoadFreeze ( SILENT ); + } + /*** Emulate ***/ + emulate (); + + /*** NO! - We're never leaving here ! ***/ + while (1); + return 0; + +} diff --git a/source/ngc/snes9xGX.h b/source/ngc/snes9xGX.h new file mode 100644 index 0000000..d421d19 --- /dev/null +++ b/source/ngc/snes9xGX.h @@ -0,0 +1,242 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * softdev July 2006 + * crunchy2 May 2007-July 2007 + * + * snes9xGX.cpp + * + * This file controls overall program flow. Most things start and end here! + ****************************************************************************/ + +/**************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +*****************************************************************************/ + +#ifndef _SNES9XGX_H_ +#define _SNES9XGX_H_ + +#include "snes9x.h" + +#define GCVERSION "2.0.1b8" +#define GCVERSIONSTRING "Snes9x GX 2.0.1b8" + +#define NOTSILENT 0 +#define SILENT 1 + +struct SGCSettings{ + uint8 AutoLoad; + uint8 AutoSave; + char gcip[16]; + char gwip[16]; + char mask[16]; + char smbip[16]; + char smbuser[20]; + char smbpwd[20]; + char smbgcid[20]; + char smbsvid[20]; + char smbshare[20]; + bool8 NGCZoom; + uint8 VerifySaves; +}; + +START_EXTERN_C +extern struct SGCSettings GCSettings; +extern unsigned short saveicon[1024]; +extern bool8 isWii; +END_EXTERN_C + +#endif + +/*** QUICK_SAVE_SLOT defines where preferences are loaded and saved, and also + where SRAM and Freezes are auto loaded or saved if enabled: + + -1 Disabled - no prefs are loaded + 0 Memory card in slot A + 1 Memory card in slot B + 2 SD card in slot A + 3 SD card in slot B + 4 SMB share ***/ +#ifndef QUICK_SAVE_SLOT +#define QUICK_SAVE_SLOT 1 +#endif + +/*** if defined, LOAD_TYPE specifies type of load allowed: + 0 = All load types allowed - show submenu + 1 = DVD only + 2 = SMB only + 3 = SD only + This settings is something I use to allow me to make a version for my kids, + where I want it to be easy and they'll never be using SD or SMB ***/ +#ifndef LOAD_TYPE +#define LOAD_TYPE 0 +#endif + +/*** default SMB settings ***/ +#ifndef GC_IP +#define GC_IP "192.168.1.32" /*** IP to assign the GameCube ***/ +#endif +#ifndef GW_IP +#define GW_IP "192.168.1.100" /*** Your gateway IP ***/ +#endif +#ifndef MASK +#define MASK "255.255.255.0" /*** Your subnet mask ***/ +#endif +#ifndef SMB_USER +#define SMB_USER "Guest" /*** Your share user ***/ +#endif +#ifndef SMB_PWD +#define SMB_PWD "password" /*** Your share user password ***/ +#endif +#ifndef SMB_GCID +#define SMB_GCID "gamecube" /*** Machine Name of GameCube ***/ +#endif +#ifndef SMB_SVID +#define SMB_SVID "mypc" /*** Machine Name of Server(Share) ***/ +#endif +#ifndef SMB_SHARE +#define SMB_SHARE "gcshare" /*** Share name on server ***/ +#endif +#ifndef SMB_IP +#define SMB_IP "192.168.1.100" /*** IP Address of share server ***/ +#endif diff --git a/source/ngc/sram.cpp b/source/ngc/sram.cpp new file mode 100644 index 0000000..9acebf3 --- /dev/null +++ b/source/ngc/sram.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * crunchy2 April 2007-July 2007 + * + * sram.cpp + * + * SRAM save/load/import/export handling + ****************************************************************************/ +#include +#include +#include +#include + +#include "snes9x.h" +#include "snes9xGx.h" +#include "memmap.h" +#include "srtc.h" +#include "ftfont.h" +#include "mcsave.h" +#include "sdload.h" +#include "smbload.h" + +extern unsigned char savebuffer[]; +extern int currconfig[4]; +extern int padcal; +extern unsigned short gcpadmap[]; +extern unsigned short padmap[4]; + +char sramcomment[2][32] = { {"Snes9x GX 2.0.1b8 SRAM"}, {"Savegame"} }; + +/**************************************************************************** + * Prepare Memory Card SRAM Save Data + * + * This sets up the save buffer for saving to a memory card. + ****************************************************************************/ +int +prepareMCsavedata () +{ + int offset = sizeof (saveicon); + int size; + + ClearSaveBuffer (); + + /*** Copy in save icon ***/ + memcpy (savebuffer, saveicon, offset); + + /*** And the sramcomments ***/ + sprintf (sramcomment[1], "%s", Memory.ROMName); + memcpy (savebuffer + offset, sramcomment, 64); + offset += 64; + + /*** Copy SRAM size ***/ + size = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0; + + if (size > 0x20000) + size = 0x20000; + + memcpy (savebuffer + offset, &size, 4); + offset += 4; + + /*** Copy SRAM ***/ + if (size != 0) + { + memcpy (savebuffer + offset, Memory.SRAM, size); + offset += size; + } + + /*** Save Joypad Configuration ***/ + memcpy (savebuffer + offset, &currconfig, 16); + offset += 16; + memcpy (savebuffer + offset, &padcal, 4); + offset += 4; + + return offset; +} + +/**************************************************************************** + * Prepare Exportable SRAM Save Data + * + * This sets up the save buffer for saving in a format compatible with + * snes9x on other platforms. This is used when saving to SD or SMB. + ****************************************************************************/ +int +prepareEXPORTsavedata () +{ + int offset = 0; + int size; + + ClearSaveBuffer (); + + /*** Copy in the sramcomments ***/ + sprintf (sramcomment[1], "%s", Memory.ROMName); + memcpy (savebuffer + offset, sramcomment, 64); + offset += 64; + + /*** Save Joypad Configuration ***/ + memcpy (savebuffer + offset, &currconfig, 16); + offset += 16; + memcpy (savebuffer + offset, &padcal, 4); + offset += 4; + + if ( offset <= 512 ) + { + // make it a 512 byte header so it is compatible with other platforms + offset = 512; + + /*** Copy in the SRAM ***/ + size = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0; + + if (size > 0x20000) + size = 0x20000; + + if (size != 0) + { + memcpy (savebuffer + offset, Memory.SRAM, size); + offset += size; + } + + return offset; + } + else + { + // header was longer than 512 bytes - hopefully this never happens! + return 0; + } +} + +/**************************************************************************** + * Decode Save Data + ****************************************************************************/ +void +decodesavedata (int readsize) +{ + int offset; + int size; + char sramcomment[32]; + + // Check for exportable format sram - it has the sram comment at the start + memcpy (sramcomment, savebuffer, 32); + + if ( strncmp (sramcomment, "Snes9x GX 2.0", 13) == 0 ) + { + offset = 64; + + // Get the control pad configuration + memcpy (&currconfig, savebuffer + offset, 16); + offset += 16; + memcpy (&padcal, savebuffer + offset, 4); + offset += 4; + + for (size = 0; size < 4; size++) + gcpadmap[size] = padmap[currconfig[size]]; + + // move to start of SRAM which is after the 512 byte header + offset = 512; + + // import the SRAM + size = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0; + + if (size > 0x20000) + size = 0x20000; + + memcpy (Memory.SRAM, savebuffer + offset, size); + offset += size; +} + else + { + // else, check for a v2.0 memory card format save + offset = sizeof (saveicon); + memcpy (sramcomment, savebuffer + offset, 32); + + if ( strncmp (sramcomment, "Snes9x GX 2.0", 13) == 0 ) + { + //WaitPrompt ("Memory Card format save"); + offset += 64; + memcpy (&size, savebuffer + offset, 4); + offset += 4; + memcpy (Memory.SRAM, savebuffer + offset, size); + offset += size; + + // If it is an old 2.0 format save, skip over the Settings as we + // don't save them in SRAM now + if ( strcmp (sramcomment, "Snes9x GX 2.0") == 0 ) + offset += sizeof (Settings); + + // Get the control pad configuration + memcpy (&currconfig, savebuffer + offset, 16); + offset += 16; + memcpy (&padcal, savebuffer + offset, 4); + offset += 4; + + for (size = 0; size < 4; size++) + gcpadmap[size] = padmap[currconfig[size]]; + } + else if ( strncmp (sramcomment, "Snes9x 1.43 SRAM (GX", 20) == 0) + { + // it's an older SnesGx memory card format save + size = Memory.SRAMSize ? ( 1 << (Memory.SRAMSize + 3)) * 128 : 0; + + // import the SRAM + if ( size ) + memcpy(&Memory.SRAM[0], &savebuffer[sizeof(saveicon)+68], size); + + // Ignore the settings saved in the file + + // NOTE: need to add import of joypad config?? Nah. + } + else + { + // else, check for SRAM from other version/platform of snes9x + size = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0; + + if ( readsize == size || readsize == size + SRTC_SRAM_PAD) + { + //WaitPrompt("readsize=size or + SRTC_SRAM_PAD"); + // SRAM data should be at the start of the file, just import it and + // ignore anything after the SRAM + memcpy (Memory.SRAM, savebuffer, size); + } + else if ( readsize == size + 512 ) + { + //WaitPrompt("readsize=size+512"); + // SRAM has a 512 byte header - remove it, then import the SRAM, + // ignoring anything after the SRAM + memmove (savebuffer, savebuffer + 512, size); + memcpy (Memory.SRAM, savebuffer, size); + } + else + WaitPrompt("Incompatible SRAM save!"); + } + } +} + +void quickLoadSRAM (bool8 silent) +{ + switch ( QUICK_SAVE_SLOT ) + { + case CARD_SLOTA: + case CARD_SLOTB: + LoadSRAMFromMC(QUICK_SAVE_SLOT, silent); + break; + case CARD_SLOTA+2: + case CARD_SLOTB+2: + LoadSRAMFromSD(QUICK_SAVE_SLOT-2, silent); + break; + case CARD_SLOTA+4: + LoadSRAMFromSMB(SILENT); + break; + } +} + +void quickSaveSRAM (bool8 silent) +{ + switch ( QUICK_SAVE_SLOT ) + { + case CARD_SLOTA: + case CARD_SLOTB: + SaveSRAMToMC(QUICK_SAVE_SLOT, silent); + break; + case CARD_SLOTA+2: + case CARD_SLOTB+2: + SaveSRAMToSD(QUICK_SAVE_SLOT-2, silent); + break; + case CARD_SLOTA+4: + SaveSRAMToSMB(SILENT); + break; + } +} + diff --git a/source/ngc/sram.h b/source/ngc/sram.h new file mode 100644 index 0000000..cca22f9 --- /dev/null +++ b/source/ngc/sram.h @@ -0,0 +1,17 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Port + * crunchy2 April 2007 + * + * sram.cpp + * + * SRAM save/load/import/export handling + ****************************************************************************/ + +int prepareMCsavedata (); +int prepareEXPORTsavedata (); +void decodesavedata (int readsize); + +void quickLoadSRAM (bool8 silent); +void quickSaveSRAM (bool8 silent); diff --git a/source/ngc/tempgfx.h b/source/ngc/tempgfx.h new file mode 100644 index 0000000..f9d3b3d --- /dev/null +++ b/source/ngc/tempgfx.h @@ -0,0 +1,556 @@ +/******************************************************************* + * Image File : ..\snesGX2.bmp + * Width : 640 + * Height : 480 + * + * This header contains a compressed Zip image. + * Use zlib1.2.3 uncompress function to restore. + *******************************************************************/ + +#define tempgfx_RAW 614400 +#define tempgfx_COMPRESSED 8647 +#define tempgfx_WIDTH 640 +#define tempgfx_HEIGHT 480 + +unsigned char tempgfx[8647] = { +0x78,0xda,0xed,0x9d,0xd9,0x77,0x14,0x47,0x9e,0xef,0xf9,0xdb,0xee,0xcb,0x9d,0x99, +0x3b,0x67,0x66,0x7a,0xe6,0x9c,0xdb,0xe3,0xf6,0x9d,0xde,0x6c,0xb7,0xdb,0xdd,0xee, +0xf6,0xc2,0x8e,0xa9,0x88,0x5f,0xa6,0x58,0x8d,0x31,0x60,0xcc,0x2a,0x30,0x8b,0x58, +0x2c,0x10,0x48,0x2c,0x02,0x81,0x16,0xb4,0x21,0xb4,0x21,0xc4,0x22,0x21,0xc0,0x02, +0x03,0x9e,0x87,0xee,0x73,0x6e,0x9f,0xe3,0x7e,0xe8,0x97,0x7e,0xb8,0xf7,0x17,0x51, +0x59,0xa5,0xcc,0x92,0x4a,0xca,0x12,0x2a,0x55,0x09,0x3e,0xfd,0x3d,0x9f,0x36,0x52, +0xe5,0x12,0x99,0x59,0xf9,0x51,0x44,0x46,0x64,0xe6,0x32,0x59,0x46,0x08,0x21,0x84, +0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10, +0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0xbc,0xa6, +0xe9,0x91,0x2b,0x72,0x46,0x8e,0xcb,0x7e,0xd9,0x47,0x08,0x21,0x65,0xc9,0x7e,0x75, +0xcc,0x19,0x75,0x4d,0x4f,0xd5,0x98,0xaf,0x5d,0xce,0xcb,0x37,0x52,0x4b,0x08,0x21, +0x8b,0x96,0x6f,0xd4,0x3b,0xed,0x15,0xb7,0x5f,0xb3,0xfa,0x98,0x10,0x42,0x2a,0x91, +0xe6,0x0a,0xba,0xef,0x96,0x5c,0x94,0x7a,0x42,0x08,0xa9,0x58,0x2e,0xaa,0x87,0x2a, +0x61,0xbf,0x6e,0xb9,0xa4,0xeb,0x26,0x84,0x90,0x4a,0xe6,0x92,0xba,0x68,0xf1,0xfb, +0x3b,0xae,0x11,0x42,0x48,0x55,0xa4,0x67,0x91,0x5b,0xbe,0xad,0x84,0x10,0x52,0x35, +0x59,0xbc,0x56,0xf0,0x90,0x74,0x48,0xdb,0xb4,0x74,0x49,0xbf,0x19,0x92,0x3b,0xe6, +0x4e,0x00,0x00,0x50,0x1e,0x86,0xd4,0x33,0x5d,0xd2,0x66,0x0b,0xfd,0xd3,0xa1,0x5e, +0x5a,0xac,0xb6,0x6f,0x47,0x41,0x3a,0x65,0x88,0x63,0x03,0x00,0x8b,0x83,0xfa,0xa6, +0x53,0x3a,0x6c,0xd2,0x42,0x8b,0xd3,0x06,0xee,0x97,0x1b,0x05,0xe9,0xb3,0x23,0xd4, +0xfb,0x00,0x60,0x11,0x19,0x91,0x3e,0x53,0x68,0xa2,0xfe,0x45,0xf0,0x5f,0xaf,0xd6, +0xf6,0xe2,0xe9,0xc7,0x7d,0x00,0x50,0x01,0xfa,0xa5,0xd3,0xc6,0x5d,0xd4,0xbb,0x28, +0xad,0xdf,0xee,0x58,0xfa,0x2c,0xc7,0x01,0x00,0x2a,0xd3,0x0e,0xee,0x33,0x71,0x1b, +0x95,0xbf,0x05,0x3c,0xa8,0xeb,0x88,0x67,0x04,0xff,0x01,0x40,0x85,0xfc,0x77,0xdb, +0x24,0x7d,0x34,0x58,0x66,0xff,0x0d,0xc8,0xcd,0x58,0x68,0xfb,0x02,0x40,0x65,0xdb, +0xc0,0x37,0x6d,0xdc,0x48,0xe5,0xee,0xfd,0xe8,0x8b,0x85,0xf1,0x2e,0x00,0x50,0xd9, +0xf1,0x30,0x7d,0x76,0xca,0x48,0xb7,0xca,0x5e,0xff,0xeb,0x8f,0x65,0x84,0xfd,0x0f, +0x00,0x15,0xed,0x07,0xee,0xb7,0x71,0x27,0x95,0xdb,0x7f,0xf1,0xb0,0xff,0x01,0xa0, +0xb2,0xd7,0x00,0x07,0x6c,0xdc,0x49,0xe5,0xee,0xff,0x88,0x87,0xfd,0x0f,0x00,0x95, +0xf5,0xdf,0xa0,0x8d,0x3b,0xa9,0xbc,0xfe,0x1b,0x49,0x84,0xfd,0x0f,0x00,0x95,0xf5, +0xdf,0xb0,0x1d,0x96,0xa9,0x94,0xd7,0x7f,0xb7,0x13,0x61,0xff,0x03,0x40,0x85,0xc7, +0xc0,0xd8,0xb8,0x93,0xa8,0xff,0x01,0xc0,0x9b,0xe3,0xbf,0x11,0x1b,0x77,0x52,0x79, +0xfd,0x77,0x27,0x19,0xf6,0x3f,0x00,0x54,0xd4,0x7f,0x77,0x6c,0xdc,0x49,0xe5,0xf5, +0xdf,0xdd,0x44,0xd8,0xff,0x73,0x1d,0x9b,0xcb,0x66,0x9b,0xac,0xb6,0xab,0x65,0xee, +0x6c,0x93,0xba,0x45,0xbb,0x97,0xe6,0xb2,0x6c,0x33,0x69,0xca,0xa4,0xa5,0xb2,0x75, +0x6e,0x8c,0xa7,0x34,0xa6,0xda,0x8e,0x6d,0xd2,0xc8,0xfd,0x40,0xb0,0xc8,0xe7,0xd8, +0x5d,0x1b,0x77,0x52,0x79,0xfd,0x77,0x2f,0x11,0xf6,0xff,0xac,0xd7,0x65,0xcd,0x9e, +0x94,0xee,0xcb,0xe5,0xa8,0x7c,0x6e,0xd3,0x7a,0xa9,0x31,0x37,0xf6,0x3c,0xa5,0x9b, +0x72,0x8e,0x1d,0x96,0x3d,0xa6,0x94,0x32,0x69,0xa9,0xec,0xee,0x12,0xb6,0xe3,0xac, +0x0c,0x99,0x63,0x5a,0xbe,0xe4,0x7a,0xaf,0xc7,0xf6,0xcb,0xf5,0x82,0xf2,0x46,0x8e, +0x9d,0x63,0x7f,0xf6,0xc9,0x61,0xb3,0x25,0xf5,0x76,0x76,0x9a,0xba,0x05,0x2a,0xc3, +0xb0,0xec,0x33,0x61,0xaa,0xf5,0xae,0xb7,0xbb,0xe2,0xeb,0x28,0xa0,0xb1,0xa0,0x3c, +0x73,0x1e,0x57,0x48,0x79,0x9e,0xdd,0xb3,0x71,0x27,0x95,0xd7,0x7f,0xf7,0x13,0x61, +0xff,0xcf,0x76,0x5c,0x9c,0x67,0x32,0xf6,0xe4,0x86,0x3b,0x99,0x3b,0x9b,0xee,0xac, +0x9f,0x8b,0xab,0xe1,0xea,0x12,0xbd,0xb4,0xdb,0xf6,0x07,0x03,0xe6,0xeb,0x12,0x1d, +0xeb,0x5c,0x96,0x09,0x4e,0x9a,0x34,0x65,0xba,0xb3,0xf1,0xea,0xfa,0xd5,0xf2,0xb9, +0xb8,0xed,0x38,0x9b,0x62,0x3b,0xce,0x06,0xae,0x2c,0x33,0x9f,0xe7,0x57,0xd5,0x8b, +0xc3,0xc1,0x6d,0x73,0x7d,0xc6,0xf2,0x6e,0xb7,0x43,0xc1,0xb0,0xb9,0x1d,0x8c,0x98, +0x19,0xc7,0xd4,0xab,0xcf,0x4c,0x49,0xfb,0xa6,0x46,0x16,0xaa,0x0c,0xfb,0x4a,0xdc, +0xbf,0x67,0xa3,0x75,0x8c,0xe8,0x72,0xa6,0x1c,0x5a,0xca,0xdf,0x1c,0x77,0x5c,0x67, +0xd9,0x17,0x15,0x19,0x63,0x7c,0xd3,0xdc,0xf4,0x74,0xeb,0xbe,0xbb,0xee,0xb9,0x22, +0x4d,0xb6,0xc9,0x73,0xce,0x9e,0x92,0x53,0x33,0x72,0x42,0x0e,0xd9,0x43,0x52,0x98, +0x13,0x05,0xd3,0x9d,0xf5,0xcb,0xb9,0xe2,0x97,0xdb,0xed,0xd7,0x73,0xbb,0xa4,0xf3, +0xec,0xbe,0x8d,0x3b,0xa9,0xbc,0xfe,0x7b,0x90,0x08,0x9e,0xbb,0x33,0xcb,0xdf,0x7b, +0xf5,0x4c,0x38,0x90,0x19,0xdf,0x38,0xbe,0x3e,0x0d,0x6d,0x81,0xfa,0x2f,0x68,0x33, +0xa9,0xa6,0xaf,0x69,0x5a,0x9f,0xd1,0xe5,0xef,0x94,0x5d,0xd6,0xb9,0xa9,0xa9,0xa6, +0x84,0x75,0xe8,0xf4,0x03,0x1b,0xd2,0x4d,0x3f,0xbe,0xa1,0x6d,0xbd,0x3b,0x23,0x53, +0x6f,0x87,0x96,0xcb,0xdb,0xa7,0x60,0x3b,0xea,0xbc,0x17,0x9b,0x6c,0xaf,0x34,0x7b, +0x0f,0xd4,0xd5,0x8c,0x67,0xe2,0xeb,0x50,0x5b,0xd9,0x16,0xe9,0x33,0x03,0xd1,0x79, +0x5f,0xb8,0x2f,0x3b,0x65,0x8d,0xce,0xbf,0xd7,0xf6,0xa4,0x2c,0xf7,0x4e,0x5d,0xde, +0x42,0x95,0xc1,0xd5,0xfd,0x52,0xed,0xaf,0x0d,0xa3,0xd1,0x3a,0x4e,0xe9,0x3a,0xfa, +0xcd,0x90,0x77,0x60,0x76,0x19,0x7b,0xfc,0xdf,0x9c,0x26,0x93,0xfe,0xb8,0xf6,0x9a, +0x5b,0xc1,0xe0,0x8c,0xfb,0xa2,0x0c,0xf7,0xcf,0xaa,0x73,0xba,0x22,0xaf,0x65,0x9d, +0xf6,0x6d,0xe4,0xa6,0xc3,0x72,0xa8,0x82,0x39,0xa5,0xe5,0x68,0xb2,0x97,0xb4,0x5c, +0x9d,0xb3,0x39,0x51,0x1e,0xd8,0xb8,0x93,0xca,0xeb,0xbf,0xb1,0x44,0xf0,0x5c,0x71, +0x76,0xe9,0xf7,0xf8,0x72,0x38,0x99,0x99,0xac,0x49,0x47,0xb7,0xf7,0x5f,0xb7,0x49, +0x3b,0xfd,0x9d,0xc0,0xf8,0xf3,0xd8,0xe8,0xba,0x4a,0x5b,0xc7,0x65,0x9b,0x76,0xfa, +0xc9,0xb0,0x3b,0xe3,0xd6,0x51,0xca,0x76,0xe4,0xda,0x95,0x89,0x79,0xc2,0x53,0x7e, +0x39,0xf5,0x92,0xf5,0x43,0x7c,0xfa,0xcb,0xde,0x19,0x9b,0xed,0x35,0xad,0xe3,0xf5, +0xca,0xc0,0x8c,0xe7,0xbc,0xdb,0x97,0x47,0x4a,0x28,0xc3,0xae,0x05,0x2c,0x83,0xf3, +0xdf,0x9d,0xd4,0xfb,0xeb,0xb2,0xae,0x43,0xe4,0x4a,0x70,0x63,0x6a,0x39,0x7a,0xfe, +0xea,0x51,0x92,0x3b,0x25,0x1d,0xd7,0x6f,0x6d,0x7b,0xd0,0xab,0x6e,0x1a,0x7e,0xf5, +0x3a,0xa0,0x3a,0xfd,0xa6,0xf4,0x78,0xbf,0x35,0x27,0xea,0x6b,0x87,0xed,0x21,0x59, +0x5a,0x39,0xa5,0xfb,0xa5,0x49,0xae,0xa9,0x0f,0x6f,0xc5,0xb6,0x6f,0xcc,0xc6,0x9d, +0x54,0x5e,0xff,0x8d,0x27,0x82,0xe7,0x8a,0xb3,0x5e,0xcf,0x9b,0xc9,0xf0,0x87,0xcc, +0x0f,0x35,0xe9,0xb8,0xe5,0xce,0xc1,0xe0,0x96,0x4d,0x3b,0xfd,0x0f,0x61,0x7d,0xf6, +0x7c,0x2e,0x79,0x1d,0x93,0x26,0xfd,0x3a,0x6e,0xf9,0x75,0x94,0xb2,0x1d,0x17,0x74, +0xbb,0xb3,0xd7,0xcb,0x2e,0x24,0xb6,0xa5,0x3e,0x72,0x52,0xa2,0xbc,0x61,0x8b,0x5f, +0xfe,0xe7,0x72,0xd2,0x9c,0x97,0x16,0xff,0xbd,0x1e,0x9e,0xe6,0xbf,0x01,0xe7,0x8f, +0x92,0xf6,0xa5,0x6b,0xe3,0x7f,0xbe,0x40,0x65,0x70,0xdb,0x32,0x56,0x53,0xda,0xba, +0xf7,0xcb,0x05,0xd3,0xaa,0x75,0xb8,0x41,0xad,0x03,0xde,0x91,0x3a,0x2d,0x7f,0x7d, +0x89,0xc7,0xf5,0x4b,0x7b,0x5e,0xcf,0xf3,0xee,0x60,0x20,0x75,0x1d,0xd0,0xb5,0x1b, +0x3b,0x7d,0x1d,0xee,0xa2,0x69,0x92,0x46,0xef,0xb8,0x63,0x33,0xb6,0x3f,0x5f,0x97, +0x9c,0xb4,0x0d,0x72,0xc9,0xb6,0xca,0xb8,0x8d,0x3b,0xa9,0xbc,0xfe,0x7b,0x98,0x08, +0x9e,0x2b,0x8e,0x3b,0xa7,0xfe,0x1c,0xfe,0xd9,0xe4,0x48,0xd7,0x17,0x32,0x64,0xe3, +0xf3,0xcc,0x4a,0x30,0xe4,0xd7,0x31,0x14,0xa4,0x9c,0x5e,0x19,0x72,0x65,0x08,0xfe, +0x3c,0xb5,0x8e,0x20,0xdd,0x75,0xa9,0xb9,0xb6,0xa3,0x2d,0x56,0x86,0x36,0xfd,0x7c, +0x8d,0x6c,0xf0,0xd3,0x34,0xc4,0xcb,0x16,0x34,0xe8,0xba,0x1a,0x12,0xdb,0xd7,0xe0, +0x97,0x65,0xec,0x16,0xf9,0xda,0x1c,0x57,0x67,0xb4,0x07,0x37,0xb5,0xdd,0x58,0x70, +0xbe,0xcb,0x55,0x9d,0x6f,0x4f,0xfa,0xfd,0x12,0x95,0x71,0x63,0xd4,0x97,0xf4,0xaa, +0x65,0x70,0xfe,0x7b,0x52,0xc2,0xba,0x2f,0xbb,0xb6,0xb7,0x1c,0x35,0x8d,0xd2,0x6e, +0xfa,0xb4,0x2d,0x3d,0x22,0x5f,0x9a,0xd2,0x8f,0x6b,0x46,0xcf,0xef,0x06,0x75,0x59, +0xef,0xb4,0xfd,0x71,0x4b,0x3d,0x77,0x43,0x3d,0x77,0x55,0xeb,0x72,0x8d,0xbe,0x1e, +0x77,0xe4,0x35,0x76,0x5c,0x9a,0x24,0x9d,0x54,0x5e,0xff,0x4d,0x24,0x82,0xe7,0x66, +0xf7,0xdf,0x8f,0xc1,0x8f,0x26,0xc7,0x5c,0xd7,0xd1,0x57,0xc8,0x4a,0xfd,0x7c,0xd4, +0xe6,0xe7,0x29,0x32,0xfd,0xd4,0xe7,0xcf,0xfd,0x3a,0x46,0x63,0xeb,0x48,0x77,0x7d, +0xfd,0xc7,0xd8,0x3a,0xf6,0xcd,0x31,0xcf,0x0a,0x9b,0x66,0x3b,0x3a,0x65,0xea,0xf3, +0x4e,0xfd,0xfc,0x13,0x59,0x1f,0xd5,0xbf,0x1a,0x6d,0x7c,0xde,0x78,0x59,0x7f,0x94, +0x46,0xbf,0xee,0x4f,0x64,0xb9,0x35,0xb2,0xc3,0x6c,0x8b,0x9c,0x39,0x53,0x9f,0xe8, +0x6a,0xd9,0x17,0x2b,0x73,0x67,0xaa,0xed,0x14,0xad,0x43,0x7d,0x55,0x62,0x19,0x8e, +0x4a,0x93,0xfa,0xaf,0x2f,0x51,0xff,0x4b,0xd3,0xff,0x11,0x5f,0x66,0xa7,0xf7,0xff, +0x97,0xf6,0xb8,0x5c,0x36,0x5d,0x5a,0x7f,0xcb,0xfa,0x6f,0xa6,0xe3,0xfa,0x3c,0x71, +0x1c,0xa6,0xca,0x38,0xea,0xcb,0xb4,0x55,0xf6,0x9a,0xd3,0x5a,0xbe,0xcb,0xd2,0xac, +0xf5,0xb9,0xf3,0x55,0x70,0x3d,0xae,0x5a,0x93,0x74,0x12,0xfe,0xab,0x9e,0xf6,0xef, +0x5f,0x82,0xbf,0xd9,0xbf,0x45,0x1c,0x98,0xe3,0x3c,0x5a,0xe5,0x3f,0x7f,0x90,0x9f, +0xfe,0x6f,0x45,0xa6,0xcf,0x7f,0x1e,0xfc,0xb7,0xff,0xfc,0x81,0x4c,0xad,0x63,0x6e, +0x2b,0xe8,0x5a,0xe4,0x2f,0xb1,0x75,0x1c,0xb0,0x73,0x4f,0xaf,0x73,0xc4,0xb6,0x63, +0x2e,0x7a,0xb4,0xdc,0x1f,0xca,0xc7,0xbe,0x3e,0xe5,0xe6,0x3d,0x23,0x33,0x4f,0x77, +0xc6,0x6f,0xdf,0x6f,0xec,0xbb,0xf2,0x91,0xb5,0xb2,0x61,0x0e,0xa7,0x1d,0x88,0x95, +0xb9,0x67,0xce,0xed,0x5c,0xa9,0x7f,0x4b,0xc4,0xfb,0xec,0x68,0x09,0x65,0xd8,0x65, +0x4e,0xc8,0x25,0xf5,0x57,0x7f,0xa2,0xcd,0x39,0xac,0xcb,0x59,0x2d,0x5b,0xa4,0x47, +0xd2,0x6d,0x7f,0xab,0xf7,0x7f,0xc6,0xee,0xd5,0xfa,0x5b,0x9b,0x5b,0x96,0xf7,0xdf, +0xf4,0xe3,0x7a,0x51,0x92,0xfb,0x6c,0xea,0xf3,0x07,0xfa,0xf9,0x87,0xf2,0xb6,0xfc, +0x41,0x8c,0x6c,0x93,0x3d,0x72,0x10,0xc7,0x55,0x8d,0xff,0x1e,0x25,0x82,0xe7,0x66, +0xef,0xff,0x68,0x96,0xbf,0xdb,0xbf,0xcf,0xc9,0x73,0x9d,0xce,0x9d,0x11,0x9f,0xe9, +0xf7,0x7e,0x22,0xf6,0x7b,0x77,0x9e,0xfc,0x93,0xfd,0x77,0xf9,0xb9,0xfd,0x40,0x7d, +0xb2,0xd2,0xf7,0x81,0xae,0x96,0xa9,0xcf,0xff,0xe4,0x7f,0x9e,0x48,0xb5,0x0e,0x47, +0x9f,0xcd,0xd6,0xe7,0x9a,0x25,0xcd,0xf4,0xcf,0x25,0x5b,0x2a,0xf5,0xb8,0xf4,0xa5, +0x5e,0xc7,0xdf,0x6d,0x9f,0x96,0xfb,0x03,0x79,0xdf,0x86,0x52,0x6b,0x0e,0xfb,0x32, +0x1f,0x9c,0x61,0x7d,0x07,0x7d,0xd9,0x7f,0x25,0x6f,0xdb,0xf7,0xb4,0x4c,0x9b,0x45, +0x4c,0x72,0xdb,0xe3,0x34,0x17,0x2c,0xa3,0xcf,0x3b,0xeb,0x5f,0xe4,0x3f,0xed,0x3b, +0xf2,0xa1,0xfd,0x54,0x56,0x39,0xc7,0x15,0x3a,0x51,0xdb,0xbf,0xbb,0x6d,0x9d,0xd6, +0xe7,0x4e,0xa7,0x2e,0x43,0xad,0x69,0x08,0x5a,0x4d,0xaf,0x24,0xfb,0x5d,0xeb,0x74, +0x59,0x5b,0xe5,0xaf,0xa9,0xb7,0xff,0xa0,0x2e,0xf3,0x5d,0xad,0x4f,0x7e,0x29,0xa7, +0xcc,0x35,0xad,0x4b,0x66,0xfd,0x57,0x78,0x5c,0xb7,0xc6,0xca,0xf3,0x57,0x75,0x75, +0xfc,0xb8,0x4e,0xe8,0xe7,0x1f,0xc8,0xbf,0xcb,0x7b,0xb2,0x56,0xbd,0xbb,0xbb,0x6a, +0xfc,0x77,0x58,0x72,0x63,0x56,0xea,0xf3,0x63,0x5f,0x2e,0xdb,0xdc,0x78,0x98,0xf6, +0xfc,0x18,0x99,0x42,0xfa,0x8a,0x5e,0xaf,0x8c,0xd3,0x96,0xed,0x7f,0xce,0xd7,0x75, +0x8f,0xa7,0xbe,0x76,0x99,0x74,0x52,0x79,0xfd,0xf7,0x38,0x11,0x3c,0x57,0x9c,0xec, +0x18,0xb3,0x27,0xf2,0xff,0x52,0xe5,0xff,0x8a,0xf8,0xf3,0x36,0x3e,0xbd,0xfb,0xf9, +0x7f,0xd9,0xb7,0xe4,0xf7,0x76,0x9d,0x6c,0x32,0xdb,0xb5,0x7e,0xe2,0x7e,0x13,0x9f, +0xa7,0x70,0x8e,0xd9,0x33,0xe0,0xea,0x73,0xb6,0x94,0x79,0x72,0xa5,0x12,0xfd,0x57, +0x29,0x6b,0xf9,0xad,0xbc,0xa7,0xe7,0xf4,0x41,0x73,0x4a,0x44,0xd7,0x57,0x3b,0xc3, +0x54,0xb5,0x3a,0xd5,0xa7,0x5a,0xc7,0xf9,0xb9,0xd6,0x15,0xc5,0xee,0x91,0x1a,0x53, +0xbc,0x54,0x57,0x24,0xb9,0x0c,0xb7,0x86,0xf7,0xec,0x4f,0xe4,0x97,0x5a,0xcf,0xb2, +0x66,0xab,0xd6,0xcf,0x02,0x37,0x46,0xa5,0x60,0xe9,0x5b,0xd4,0x67,0xf5,0x72,0xc5, +0x34,0x4b,0x90,0xb2,0x0c,0xa7,0xcd,0x55,0xe9,0x9a,0xd6,0xe7,0xea,0xfa,0xb3,0x4b, +0xdb,0xc7,0x1f,0xcb,0x7f,0x6a,0x7d,0x72,0x93,0x1c,0xd6,0xf5,0x5f,0x30,0x97,0x64, +0x93,0x9d,0x7e,0x5c,0xe3,0x3f,0x9f,0x93,0xe4,0x71,0x7d,0xe2,0xf7,0xe0,0x3f,0xcb, +0x2f,0xb5,0x1e,0xbb,0x49,0xbe,0x5a,0x14,0xff,0xd5,0x79,0xe7,0x9c,0xf1,0x4e,0xbb, +0x10,0x39,0xad,0x27,0x72,0x53,0x25,0xcf,0xa3,0x01,0x5d,0x7f,0x9b,0x1f,0x97,0xd3, +0xa0,0xe5,0x3b,0x3a,0x63,0xd9,0x93,0x4e,0x2a,0xaf,0xff,0x9e,0x24,0x82,0xe7,0x66, +0x1b,0x77,0x50,0xe7,0x7d,0xd5,0x20,0xcf,0x53,0xd5,0xb7,0xda,0xbd,0x2f,0x0b,0xeb, +0x09,0x3f,0xd1,0x3a,0xce,0x3a,0x75,0xdf,0x21,0x73,0x52,0xea,0xcd,0xab,0xd7,0xff, +0xd6,0x6a,0x3b,0xcf,0x2d,0xd7,0x97,0x2a,0xc5,0x3c,0xed,0x3a,0xad,0xf3,0x87,0xa4, +0xae,0x03,0xba,0xfa,0xdf,0xfb,0xf2,0x8e,0x35,0xd1,0x7d,0x13,0x07,0x67,0xa9,0x27, +0x7d,0xaa,0xf5,0xc4,0xb5,0xea,0xaf,0x93,0xb2,0xb9,0xe4,0xfa,0xdf,0x4f,0xb5,0xee, +0x17,0xca,0x6e,0x6d,0xe3,0x9e,0x36,0xee,0x5a,0x63,0x5f,0xc1,0xb2,0xbf,0x90,0x23, +0xe6,0x5c,0x70,0xd1,0x6c,0x4a,0x5d,0x86,0x2b,0xa6,0xbb,0xa0,0xed,0x9b,0xbb,0x8e, +0x9b,0x6e,0xff,0xfe,0x35,0xaa,0xc7,0xff,0x87,0xfc,0x83,0xfc,0x54,0x7e,0x2f,0x19, +0xdf,0x7a,0xad,0x95,0x40,0x0a,0x8f,0x6b,0x43,0x6c,0xbe,0x89,0xa8,0xee,0x9a,0xac, +0xff,0xfd,0x56,0xfe,0x51,0xfe,0x4b,0x96,0xcb,0x46,0xd9,0x25,0x07,0x16,0x68,0xec, +0x48,0xae,0xde,0x76,0xd5,0xfb,0xad,0x23,0xaa,0x77,0x2d,0xb5,0xf3,0xaa,0x4f,0x7a, +0x7d,0x1f,0xf7,0x19,0x75,0x76,0x76,0xcb,0x92,0x4e,0xc2,0x7f,0xd5,0x41,0x67,0x8a, +0x7b,0x6c,0xe3,0xd7,0x94,0x1e,0xcc,0x78,0xfd,0xef,0x7f,0xdb,0xdf,0x69,0xfd,0xc1, +0xf5,0x05,0x5e,0xd5,0xbf,0x83,0xaf,0x7e,0xfd,0xef,0x33,0xfb,0xd9,0x9c,0xd7,0xf3, +0x7b,0x0a,0xae,0x45,0x7d,0x66,0x4b,0xd9,0x8e,0x9e,0xc8,0x7f,0x19,0x71,0xe3,0xd8, +0x76,0xda,0xa2,0xd7,0x0e,0xfd,0xb5,0xc7,0x15,0x6a,0x87,0x03,0xe6,0xbc,0xd6,0x15, +0x5f,0xf5,0xfa,0x5f,0xbc,0x0c,0x07,0x7c,0x9b,0xb5,0xd6,0x9c,0xf0,0x7d,0x2a,0x69, +0xcb,0xd0,0x6e,0x6e,0x05,0xd3,0xc7,0xdb,0x25,0xf7,0xf9,0xdc,0xd7,0x71,0x3f,0x50, +0xf7,0xbd,0x23,0x9f,0x24,0x7a,0x62,0x92,0xc7,0xd5,0xda,0xff,0x8e,0x2d,0x6f,0x4b, +0xe1,0x75,0x5d,0xbf,0xcf,0x9d,0xff,0xfe,0x8f,0xba,0x79,0x83,0xec,0x2c,0xc1,0x7f, +0x47,0x7c,0xfb,0xb4,0xc1,0xb7,0x4d,0xa7,0xda,0xa4,0x43,0x0b,0xf0,0x7d,0xbe,0x6f, +0xee,0x7b,0x1e,0x98,0x87,0xe1,0x43,0xcf,0xa3,0xf0,0xbb,0xcc,0x77,0x9e,0xc9,0xcc, +0xf7,0xe1,0xf7,0x33,0xf2,0x7c,0xa6,0x31,0x4b,0xe1,0xf3,0x82,0xe9,0x9e,0xfa,0xe5, +0x3c,0x72,0xcb,0xd5,0xe5,0xbb,0xf5,0x8c,0xa6,0xae,0x63,0xdc,0xd4,0x6d,0x7c,0x62, +0xf1,0x5f,0xf5,0x91,0xe6,0x9e,0xdc,0x78,0xbf,0xe9,0xa8,0x9f,0xbe,0xb0,0x9f,0xf0, +0x2d,0xfb,0x91,0x6c,0xd7,0xba,0xc9,0x55,0xd3,0xe3,0xc7,0xc1,0x2d,0x44,0xff,0xef, +0x9c,0xa5,0xb2,0x85,0x7d,0x91,0xa5,0x6c,0x47,0xa7,0xf7,0xdf,0x7b,0x76,0x8d,0xfe, +0x77,0x87,0xfc,0x29,0xd6,0xaf,0xf9,0x27,0x73,0x3a,0xf1,0xf3,0x8f,0x66,0x87,0x4e, +0xb3,0x56,0xeb,0x89,0x8d,0x72,0xc3,0x1c,0x29,0x7a,0xef,0xf3,0x5a,0x49,0xd3,0xff, +0x1b,0x2f,0x83,0xeb,0xb3,0xb5,0xf2,0x85,0xbb,0xae,0x56,0x52,0x19,0xfa,0x63,0xf7, +0x6c,0xe4,0xee,0x8d,0x28,0xb5,0x1f,0xbf,0x48,0x0f,0x71,0xac,0xfc,0x2d,0xd3,0xfa, +0x9f,0x93,0xeb,0x70,0xfb,0xfc,0xb7,0x5a,0x87,0x2c,0xee,0xbf,0xc3,0xde,0x73,0xe7, +0xa3,0xba,0x5c,0x87,0xaf,0xc7,0xcd,0x77,0x9c,0xf4,0x3d,0xef,0xb5,0xb1,0x8c,0x73, +0xda,0x44,0x90,0x75,0xda,0xb3,0xc8,0x4d,0x3f,0x94,0x30,0xee,0x71,0xc1,0xd1,0xf5, +0x3f,0xd3,0xb2,0x3c,0xd6,0x72,0x8d,0xcd,0xe6,0x44,0xfc,0xb7,0x24,0xc6,0xff,0xcd, +0x45,0x8f,0x3f,0xaf,0x62,0xe3,0xc4,0xfc,0x3d,0x09,0x3f,0xb3,0x9f,0xc8,0x2e,0x53, +0xaf,0x75,0xbf,0x81,0x69,0xcb,0x7c,0xf2,0xea,0xe3,0xff,0xe6,0x1c,0x8b,0xd6,0x53, +0xf2,0x76,0xb4,0x79,0xff,0x2d,0xb7,0x6e,0x0c,0xef,0x8b,0xc4,0xb2,0x5c,0x3f,0xc0, +0x97,0x89,0x75,0xbf,0xf0,0xbf,0xcb,0x48,0x5d,0xd0,0x62,0xdc,0x3d,0x63,0x7d,0xea, +0xb6,0xcb,0x72,0xca,0x1c,0xd0,0xf6,0xe8,0x56,0xd9,0x68,0x36,0xca,0x46,0xbb,0x51, +0x42,0x5b,0xea,0xf8,0xbf,0x2f,0xb5,0x0c,0x2b,0xb4,0xad,0x5f,0x4a,0x19,0x0e,0x4b, +0xa3,0xbd,0xa4,0x6d,0xe0,0x0b,0xfa,0x5f,0x77,0xff,0xd7,0x37,0x91,0x6b,0xe6,0xb3, +0xfd,0xc9,0xe3,0xb8,0x69,0x1e,0xe3,0xff,0x72,0xf5,0xbf,0x8d,0xda,0xf2,0xaf,0xb3, +0x8d,0x5a,0x9f,0x6b,0x89,0xee,0x03,0xeb,0x2f,0xf9,0xbb,0x78,0x2f,0x5f,0x6f,0x7b, +0x9c,0xa8,0xaf,0xfd,0x50,0x59,0xbf,0xcd,0x83,0xef,0xc3,0x67,0x5a,0xfe,0x89,0xcc, +0x98,0x6e,0x13,0xfe,0xab,0x7e,0xff,0x95,0x72,0x6c,0xfd,0xbd,0x09,0xf1,0xfb,0x3f, +0xfc,0xbd,0xba,0xd3,0xfd,0x37,0x35,0xcf,0xd8,0x3c,0xef,0xff,0xf8,0xc1,0x94,0x7a, +0x8f,0x49,0xa9,0xdb,0xf1,0x91,0xbb,0xfe,0x56,0x70,0x9f,0xc9,0xee,0xe8,0xf7,0xbb, +0xc3,0xd8,0xfa,0xf5,0x5c,0xfc,0x42,0x7f,0x6f,0xe4,0xb4,0x69,0x55,0xd7,0xf6,0x4a, +0xb7,0xfe,0xf7,0x82,0xd6,0xd1,0x8e,0x9a,0x5a,0xd9,0xaf,0x75,0xad,0x7d,0x76,0x9f, +0xec,0x2d,0xf1,0xfe,0x0f,0xb7,0x5f,0x56,0xc8,0x72,0x5d,0x6e,0x29,0x65,0x58,0xa5, +0xad,0xe0,0xed,0xf2,0xb5,0xd6,0xb6,0x6a,0x35,0x53,0x75,0xad,0x52,0xb7,0xbf,0x65, +0xda,0x71,0xdc,0x38,0x8f,0xfb,0x3f,0x7e,0x25,0x6f,0xfb,0xfb,0x48,0x9a,0xd4,0x79, +0xe9,0xda,0xaf,0xae,0xdd,0x38,0x16,0xb8,0xb6,0xe9,0x13,0x5f,0x87,0x73,0x8e,0x7b, +0xb1,0x04,0x1d,0x57,0x4a,0xfd,0x70,0x32,0x7c,0x9c,0x79,0x18,0xe0,0xbf,0x6a,0xf5, +0x5f,0xea,0xfb,0x6c,0x6b,0xfa,0xbd,0x67,0x12,0xf7,0xff,0x16,0xf1,0xdf,0xd4,0x3c, +0x77,0x32,0xf3,0xbb,0xff,0x77,0x32,0xf5,0xf4,0xfd,0xc1,0xea,0x12,0xb7,0x63,0x32, +0xb3,0x41,0xb2,0xcf,0x80,0x19,0x4f,0xdc,0x17,0xbb,0xdf,0xb8,0x9e,0x86,0x9f,0xca, +0xa7,0xfa,0xd9,0xfe,0xc4,0xbd,0xb7,0xe3,0x81,0xbb,0x4e,0xba,0x4e,0xea,0xa5,0xd5, +0x74,0xa9,0x03,0x3b,0xf5,0xbf,0x97,0xb5,0x5d,0xd8,0x20,0xf5,0xba,0xdd,0x8e,0x33, +0x66,0x73,0x29,0xf7,0xff,0x86,0xae,0x9f,0x7c,0x85,0xcc,0x5c,0x86,0x8f,0xe5,0x7f, +0x8a,0x33,0xe0,0x4c,0x65,0x58,0x2d,0xa1,0x37,0xe0,0xfe,0x84,0x01,0x4b,0xdd,0x7e, +0x7f,0x2f,0x71,0xe2,0x38,0x6e,0x98,0xc7,0xfd,0xbf,0x6f,0xdb,0x77,0xc5,0xea,0xdf, +0x80,0x8b,0xa6,0x3b,0x18,0x9e,0xd6,0x5e,0x1d,0xcb,0x5f,0x7f,0x73,0xf5,0xb8,0x97, +0xaf,0xaf,0xe3,0xd2,0x10,0x3c,0x31,0xf8,0xaf,0x3a,0xfd,0x97,0xf6,0xd9,0x2f,0xd9, +0xe7,0x86,0x7c,0x28,0x89,0xe7,0xbf,0xf8,0xe7,0x61,0xfd,0xc2,0xae,0x94,0xdd,0xe6, +0xac,0xb4,0xe7,0xfd,0x37,0xf5,0xbc,0x91,0x81,0xf5,0xab,0xbd,0x4f,0x4a,0x7c,0xfe, +0x4b,0x38,0x9e,0xf2,0x19,0x33,0x75,0x99,0xdc,0xb5,0xa9,0xb4,0xdb,0x31,0x10,0xee, +0xf5,0xf3,0xec,0x0d,0x47,0x13,0xcf,0x8b,0x39,0xa4,0xdb,0xb7,0x52,0xcf,0xe9,0x9f, +0xca,0xbb,0xd6,0x8d,0xa8,0x3e,0x94,0x78,0xf6,0xca,0xe8,0xfa,0xbd,0xea,0xb7,0xdd, +0x7a,0xae,0xbb,0x7b,0xfe,0x6f,0x4a,0xaf,0xe9,0xd6,0x76,0x70,0x7b,0xd0,0xae,0x6d, +0xc9,0x36,0xa5,0xdd,0x5c,0x4c,0xfb,0xfc,0x97,0x0d,0x6d,0xfe,0xd9,0x2f,0x1f,0x15, +0x29,0xc3,0x72,0x6d,0x55,0xfe,0x0f,0xf9,0x89,0xb7,0xe3,0x4c,0x65,0x58,0x2b,0x9b, +0x65,0xa7,0xec,0xd5,0x36,0x67,0xd2,0x7f,0x69,0xb7,0xdf,0xd1,0x54,0xf8,0x1c,0x9f, +0xb0,0xc6,0xef,0x93,0x52,0x9e,0xff,0xf2,0x81,0xbc,0x65,0x3f,0x94,0x2d,0xa6,0x2e, +0x68,0x35,0x83,0x7a,0xbc,0x72,0xf5,0xb9,0x37,0xda,0x73,0xf8,0xef,0xb5,0xeb,0xff, +0x88,0xe7,0x37,0xf2,0xfe,0xb4,0xe9,0x3f,0x91,0xdf,0xda,0x8c,0xb6,0x03,0xcf,0xcb, +0x0d,0xef,0xbf,0xe9,0xcb,0xfc,0x83,0xd6,0x0f,0xe7,0x73,0x3d,0x3e,0x75,0xa9,0xec, +0xc7,0x25,0xce,0xb1,0x22,0xba,0x67,0xae,0x30,0xbf,0x96,0x9f,0xdb,0xf7,0x64,0xb9, +0xef,0x93,0x98,0xfe,0xe9,0x1a,0x71,0xf7,0x4b,0x5c,0xd7,0xfa,0x5f,0xbf,0x0c,0x9a, +0xc1,0x60,0x40,0xb7,0x37,0x4e,0xab,0xc9,0xa4,0x2e,0xc1,0x47,0xf2,0x4f,0xae,0xf5, +0x3b,0xc3,0xbd,0x2c,0xff,0xaa,0xb5,0xbf,0x7f,0xd6,0x5a,0xe8,0x6f,0x8a,0xdc,0xeb, +0xb2,0x22,0xaa,0x01,0x1e,0x88,0xf9,0x4f,0x16,0x60,0x2f,0xae,0x91,0x75,0x25,0x1c, +0xa3,0x3f,0xd8,0x5f,0x07,0x1f,0x9b,0x8d,0xe1,0x11,0xd3,0x12,0x0e,0x67,0x1e,0xd5, +0x3c,0xc7,0x71,0x55,0xea,0xbf,0x46,0xb9,0x68,0xaf,0xeb,0xb9,0x79,0x53,0x86,0x71, +0xde,0x3c,0xc6,0xbf,0xe4,0xf2,0xa9,0xbc,0x67,0xdf,0x91,0xdf,0xdb,0x35,0x89,0xb1, +0x26,0x2b,0xf5,0x4c,0x5e,0x65,0xb6,0xc8,0x51,0xad,0xff,0x74,0xa9,0x13,0xa6,0x2f, +0x73,0xb9,0x9e,0x2b,0xab,0x44,0x9c,0x1b,0x6c,0x5a,0x37,0xad,0x49,0x7d,0x1e,0x7e, +0xaa,0xbe,0x7a,0xc7,0xfe,0xa1,0x04,0xbf,0xae,0x90,0x3f,0xda,0x5f,0xcb,0x07,0x5a, +0xa6,0xc2,0xb5,0xfc,0xd1,0xfe,0x4e,0x59,0xab,0x75,0x1a,0x6d,0x5d,0x16,0x3c,0x4f, +0x79,0x95,0xa6,0xc6,0xee,0x95,0x6f,0xcd,0x55,0xe9,0x56,0xd7,0x25,0xfb,0x60,0x6f, +0xcb,0x4d,0xd3,0x23,0xd7,0xcc,0x05,0x6d,0xcf,0xda,0xb9,0xdd,0x21,0xbf,0x52,0xc3, +0xfd,0x8b,0xbc,0xa5,0x2d,0xdd,0x55,0x89,0x4f,0xdc,0xa8,0xe4,0x7f,0x93,0xff,0x90, +0xb7,0xe5,0x7d,0xdd,0xdf,0xeb,0x7c,0xaf,0x72,0x7c,0x5f,0xff,0x51,0xad,0xf8,0x89, +0x58,0xf9,0x5c,0xbe,0x4a,0xb4,0x80,0xf7,0x96,0x68,0x40,0xb7,0x8f,0xd7,0x26,0x8e, +0xe3,0x1a,0xbb,0x5e,0x02,0x5b,0xa3,0xf5,0xf4,0xb9,0xe7,0x5e,0xa9,0x7f,0x6f,0xfe, +0x68,0x56,0x05,0x35,0x66,0x5f,0x78,0xce,0x74,0x87,0xf7,0xb4,0x4d,0xfc,0xa2,0x4a, +0xae,0xb7,0xfd,0x90,0x1f,0xb3,0xf2,0x2c,0x3f,0xf6,0xe5,0x71,0x26,0x37,0x1e,0x66, +0x3c,0x3f,0x46,0xa6,0x90,0x7b,0x45,0xaf,0x57,0xc6,0x79,0x18,0x3c,0xd4,0x65,0x7d, +0x97,0xbf,0x76,0xf9,0x7c,0x09,0xf8,0x6f,0xa6,0xe7,0x15,0x36,0xcb,0x75,0x6d,0xbf, +0xdc,0xc4,0x81,0xfe,0xde,0xd1,0x5e,0xd3,0x1a,0x34,0x98,0x5a,0xf9,0x42,0xcf,0xf9, +0xcf,0xcc,0x1a,0x3d,0x17,0x92,0xb8,0xeb,0xee,0xab,0xcc,0x4a,0x65,0x9d,0x84,0x66, +0x87,0x1f,0xb3,0x76,0x5a,0xd9,0xaf,0x75,0xbd,0x1a,0x9d,0x67,0xab,0xd9,0x27,0xf5, +0xa6,0x45,0x97,0x33,0x1c,0x5b,0x66,0x8b,0xfe,0x6e,0x9f,0x7e,0x16,0xea,0x3c,0x5b, +0x65,0x8f,0x39,0x26,0x27,0x95,0xfd,0x66,0xbb,0xfe,0xbc,0x4e,0x97,0xb5,0xca,0xdf, +0x13,0x56,0xb8,0xae,0x35,0x7a,0x5e,0x66,0xec,0x46,0xd9,0x6e,0xf6,0xe8,0x7a,0x0e, +0xca,0x57,0xe6,0x73,0x9d,0xfe,0x33,0x59,0x33,0xad,0x5c,0xab,0xfd,0x32,0x56,0x2a, +0xeb,0x74,0x1d,0x3b,0x74,0xda,0xe3,0xe6,0x94,0xb2,0x6f,0x8e,0xed,0xc8,0xfa,0xd5, +0x18,0x77,0xef,0xfe,0x71,0x39,0xa3,0xed,0xf6,0x93,0x3a,0xef,0x76,0x9d,0x27,0xa3, +0x8e,0xde,0x68,0x77,0xca,0x37,0xa6,0x21,0xb8,0x62,0xae,0x29,0x0d,0xfa,0xef,0x9d, +0xb2,0x51,0x7f,0x9f,0xb1,0x5a,0xeb,0xd2,0x7d,0x54,0x6f,0xdc,0x33,0x9f,0x5a,0xa4, +0xc5,0x3f,0xa7,0xee,0x9c,0x7e,0x9f,0xea,0x62,0xf7,0x40,0x1d,0x54,0x13,0xed,0xd4, +0xf6,0xe9,0x7a,0xfd,0xab,0xf0,0x1b,0xf9,0x85,0x7a,0xec,0x2d,0x9f,0x9f,0xe9,0xbf, +0xb2,0xf9,0x59,0xf4,0x9b,0xb7,0xf5,0xd3,0xf7,0xd5,0x65,0x9f,0xc9,0x06,0x9d,0x7e, +0xa3,0x18,0xb5,0xdb,0xef,0xb4,0xfe,0xf9,0x0b,0xcd,0xbb,0x6a,0x48,0x77,0x9d,0x6f, +0xab,0x6c,0x53,0x42,0x6f,0xcc,0x77,0xfd,0x27,0xbf,0xd6,0x69,0x56,0xaa,0xeb,0xb2, +0xfe,0x9b,0x6a,0x01,0x1f,0xf7,0xe3,0x86,0x4f,0x5b,0xdd,0xbf,0xf6,0x0b,0xf5,0x98, +0xdb,0xbf,0xcb,0x75,0x3b,0x57,0xce,0xb2,0x8f,0x37,0xe9,0x3e,0xab,0x0d,0xea,0xcc, +0xc9,0xe0,0xb0,0xd9,0x1b,0xec,0x32,0x3b,0x83,0x7d,0xe6,0x68,0xd8,0x68,0x2e,0x87, +0x4d,0x99,0xd3,0xe1,0x41,0xf3,0x65,0xb8,0xd1,0xe8,0xa2,0x8c,0x09,0x8c,0x62,0x8d, +0x0d,0xc4,0x84,0x41,0x18,0xb1,0xd9,0xec,0x08,0x6b,0xcd,0xd9,0xb0,0xdd,0xdc,0x0e, +0x27,0x16,0xe7,0xfa,0x5e,0x34,0x26,0xef,0xa9,0xf7,0xcf,0x93,0xac,0xd3,0xa2,0xb1, +0x78,0xf7,0x2b,0x7a,0x0e,0xdd,0xd5,0xf5,0x3f,0xcc,0xb8,0x71,0x39,0x93,0xae,0x3f, +0xa7,0xaa,0xfd,0x37,0xc3,0x68,0x4c,0x3f,0x16,0xb3,0xc5,0xb6,0xaa,0x0f,0x07,0xde, +0x40,0xff,0xdd,0x0e,0xfa,0xb5,0xce,0x76,0xc5,0xd4,0x6b,0x1d,0x6e,0xbf,0xec,0x36, +0xbb,0x64,0x57,0x11,0x76,0xab,0x5b,0x0e,0x9b,0x93,0x72,0xde,0x5c,0x56,0x37,0x5c, +0x92,0xb3,0xea,0x8f,0xc3,0xe6,0x90,0x1c,0xf3,0xf7,0x70,0x65,0xef,0xc9,0x9f,0xbe, +0x4c,0x3d,0x47,0xd5,0x7b,0xf5,0xe6,0x42,0x70,0x59,0xeb,0x88,0x0d,0x3a,0xff,0x21, +0xb3,0x77,0xd6,0xf5,0x7c,0xad,0xf3,0x1c,0xf5,0xf7,0x92,0xd4,0xcb,0x09,0x73,0x58, +0x9d,0xb9,0xbb,0xe8,0xb4,0xbb,0xf4,0xb3,0x7d,0x3a,0x8d,0x7b,0x2e,0xde,0x25,0x2d, +0x57,0xb6,0x5f,0x76,0xf6,0xed,0xf8,0xca,0x7c,0x2d,0x07,0x7d,0x99,0x2e,0x6a,0x19, +0xaf,0x04,0x4d,0xbe,0x9c,0x07,0x74,0x39,0xfb,0xe5,0x88,0xce,0x7f,0xd1,0xb4,0xba, +0x3e,0x5e,0xf5,0x5c,0x83,0xfe,0xfe,0x6b,0xd9,0xac,0xee,0x5b,0x67,0x3f,0x93,0xf5, +0x5a,0xb7,0xdb,0x2c,0x3b,0xa6,0xf5,0x3e,0x4c,0xa5,0x56,0x5b,0xa5,0x7b,0x74,0x8a, +0x2d,0xea,0xa8,0xb5,0x5a,0xf3,0xd5,0x7a,0x52,0x91,0x7c,0xac,0x75,0xb0,0x75,0x3a, +0xd5,0x66,0x6d,0xcb,0x7e,0xa9,0x9e,0xdb,0xa4,0xb5,0xba,0xb5,0xfa,0xbb,0x4f,0x75, +0x2e,0xb5,0xb3,0xfe,0xbc,0x5d,0x1d,0xf7,0xb5,0xb2,0x5d,0xff,0x6d,0xf4,0x77,0xcb, +0xf5,0xb3,0x15,0x3a,0xcd,0x46,0xd9,0x69,0xbf,0x51,0xd7,0x5d,0xf2,0xcf,0xd8,0xbc, +0x69,0x86,0x24,0xdd,0x71,0xdc,0xad,0xfb,0x75,0xaf,0x3a,0xee,0x40,0x70,0xd0,0x1c, +0x0a,0xf4,0x98,0x85,0x97,0x32,0xd7,0xc3,0x1b,0xa6,0x23,0x6c,0x31,0x17,0xc2,0x06, +0x75,0x59,0xa3,0xb9,0x1a,0x76,0x9a,0xde,0xb0,0x27,0xd3,0x1e,0x36,0xeb,0xcf,0x27, +0xcd,0xf1,0xf0,0xa8,0x3a,0x71,0x3a,0xc7,0xf5,0xb3,0xb3,0x3a,0x4d,0xa7,0xb6,0x7d, +0xc7,0xc3,0xa7,0x5a,0x0f,0x7a,0xb9,0x40,0x63,0x47,0x22,0xbf,0x05,0x8f,0x32,0x51, +0x7d,0x2d,0xe3,0xfc,0xb6,0xd4,0xce,0x29,0xd7,0xff,0xe3,0xfa,0xb8,0x9f,0x86,0xcf, +0xab,0xdc,0x7f,0xd3,0xe3,0xfe,0x96,0x66,0xdb,0xcc,0x1d,0x45,0xef,0x8b,0x7e,0x9d, +0x18,0x09,0x86,0xfc,0x98,0xb6,0x16,0x3d,0xef,0xcf,0xab,0xd3,0xea,0xf3,0x7d,0x9a, +0x85,0x9c,0xd5,0xcf,0x2f,0x9a,0x96,0xa0,0x5d,0xcf,0xb3,0x2e,0xff,0x1c,0x4b,0xe7, +0x9b,0x0b,0xea,0x9d,0x16,0x9d,0xbf,0x4f,0x97,0x33,0x32,0x6d,0x99,0x97,0x4c,0x53, +0xe0,0xee,0x2f,0x6d,0x31,0x1d,0xfa,0xb3,0xeb,0x37,0xbd,0x2a,0x17,0xe6,0x58,0x4f, +0x83,0x69,0xd4,0xf9,0xae,0x04,0x2d,0xba,0xae,0x66,0x75,0xd4,0x79,0xad,0xa3,0xd5, +0x17,0x9d,0xfe,0xac,0x7e,0x7e,0x51,0x97,0xdf,0xee,0x97,0xdf,0x9e,0x62,0x3b,0xce, +0x68,0xfd,0xae,0x49,0xcb,0x7e,0xdd,0x97,0xe9,0x8a,0x4e,0x5f,0xaf,0xde,0x3b,0x24, +0xbb,0xad,0xfa,0x46,0xd9,0x6b,0xf7,0xa8,0xe1,0x0e,0x28,0x7b,0xb4,0x36,0xb7,0x4d, +0x1d,0xb5,0x41,0x6b,0x61,0x35,0x6a,0x9e,0xad,0xea,0xaa,0xaf,0x0a,0xfa,0x1e,0x92, +0xfe,0xab,0xf5,0x73,0xed,0x92,0x2f,0xd4,0x81,0x6e,0xae,0x62,0xff,0x0b,0x75,0x69, +0x5b,0xd4,0x6d,0x3b,0x65,0xb7,0xc6,0x59,0x6e,0xab,0xfe,0xa6,0x46,0x7f,0xef,0xea, +0x83,0xdb,0xf4,0xf7,0xae,0x0c,0x75,0x72,0xcc,0x9e,0x96,0x3a,0x7b,0x52,0xff,0xc6, +0xd4,0xc9,0x09,0xdb,0xa0,0xfb,0xf2,0x8a,0xb4,0x99,0x6e,0x75,0x5d,0xe1,0x33,0x58, +0xe3,0xc7,0xf1,0x42,0x70,0xde,0x34,0xea,0x36,0x5e,0xd4,0xbf,0x39,0x57,0xc2,0xab, +0xe6,0x7a,0xd8,0x9a,0x69,0x8d,0xd1,0x16,0xb6,0x67,0xba,0xc3,0xbe,0xcc,0x50,0x38, +0x92,0x19,0x09,0x07,0x33,0x37,0xd5,0x79,0xdd,0xe1,0xcd,0xcc,0x40,0xa8,0xe7,0x6e, +0xcd,0x5d,0xfd,0xdd,0x40,0xa6,0x27,0xbc,0xa1,0xd3,0x25,0xe7,0x9b,0x9a,0xff,0x86, +0xe9,0xd1,0x69,0x46,0x6b,0x1e,0x9a,0xc9,0x9a,0xef,0x33,0x2f,0x4b,0x70,0xdc,0x4b, +0xdf,0x3e,0x9d,0xf4,0x6d,0xc8,0x09,0xad,0x37,0x65,0xdb,0xa4,0xa3,0xaf,0xf1,0x39, +0x76,0x5f,0x3d,0x5e,0xb9,0xf1,0x2f,0x0b,0x71,0x5f,0xe2,0x09,0x75,0xe2,0x59,0x6d, +0xef,0x5c,0xf4,0xf7,0x5c,0xf7,0x2e,0xd0,0xfd,0x3a,0xd5,0xe2,0xbf,0xdb,0x66,0x48, +0xcf,0xa7,0x5e,0x75,0xda,0x8d,0x7c,0x7f,0xe6,0x74,0xda,0xbd,0xf7,0xba,0x75,0xba, +0x5b,0xfe,0x7a,0x7f,0x7f,0xd4,0x07,0xea,0x5c,0x58,0xf8,0x2e,0x89,0xf8,0x32,0x3b, +0x75,0x9a,0x2e,0xf7,0xae,0x08,0x9d,0xa6,0x5f,0xe7,0xcd,0xad,0xa7,0x7d,0xd6,0xf5, +0x74,0x99,0x1e,0x9d,0xa7,0x37,0xe8,0xd6,0x7f,0xdf,0x28,0x3a,0xad,0xeb,0x77,0x75, +0xde,0xeb,0x8e,0x2f,0x3f,0x98,0x79,0x3b,0xae,0x38,0x17,0xab,0xff,0xce,0x68,0x1b, +0xf9,0x78,0xf6,0xb9,0xea,0x76,0xaf,0xba,0x6c,0x8f,0xaf,0x65,0xed,0xd4,0x5a,0xdb, +0x0e,0xfd,0xff,0xaf,0xf4,0xe7,0x7d,0xde,0x6f,0x2e,0x07,0xf5,0xdf,0x7b,0x12,0x9f, +0xaa,0x1d,0xd5,0x8c,0xc5,0xfc,0x77,0x28,0x9a,0x6b,0x7f,0x6c,0xae,0x1d,0xea,0xcc, +0x64,0xb2,0xbf,0xd5,0xfa,0xb4,0x5f,0xd7,0x7e,0xcd,0x5e,0xd9,0xe7,0xcb,0x73,0x5c, +0x5d,0xd7,0x20,0x8d,0x5a,0xde,0x1b,0xd1,0xfb,0x89,0x6e,0x9b,0x61,0xdd,0xae,0x9b, +0x7e,0x3f,0x74,0x78,0x5f,0xbb,0x6d,0xed,0x57,0xd7,0xe5,0xee,0x01,0x76,0x75,0x8d, +0x71,0x3f,0xd6,0xe4,0x51,0xe6,0x89,0xb6,0x45,0x1f,0x86,0x63,0x99,0x7b,0x35,0xa3, +0x99,0x3b,0x35,0x7a,0x2c,0x8a,0x30,0xaa,0x8e,0xbb,0x1f,0x8e,0x67,0x1e,0xd6,0x4c, +0x98,0x09,0x75,0xd8,0x58,0xa8,0xf5,0x2c,0x9d,0xef,0x61,0xcd,0xe3,0xcc,0x77,0x35, +0xdf,0x65,0x1e,0xd7,0x3c,0xcc,0x8c,0x85,0xf7,0xd4,0x6f,0xa3,0x33,0xcc,0x3f,0xaa, +0xf3,0xdf,0xd3,0xcf,0x27,0x74,0x7d,0xcf,0x8a,0xd7,0xfd,0xbc,0xe7,0x5c,0x5b,0x55, +0xeb,0x72,0xc1,0xf8,0x92,0xac,0xc7,0x2d,0xdc,0x7d,0xf6,0x4b,0xdb,0x7f,0x45,0xda, +0xce,0xfe,0x79,0x14,0x4d,0xd1,0xb8,0xf7,0x1b,0xda,0x16,0xe9,0x5b,0x92,0xef,0x05, +0x1c,0xc9,0x9e,0x67,0xc1,0x60,0x41,0x7f,0xe6,0x74,0x06,0x83,0xec,0x7b,0xc3,0x6e, +0x7b,0x86,0xd5,0x71,0xae,0x1f,0x74,0x70,0xda,0xbb,0xc4,0xe2,0xcb,0x1c,0xf4,0x0c, +0x47,0xf3,0xb8,0xdf,0x0d,0xcd,0xb9,0x9e,0x01,0x9d,0xc7,0xbd,0xe7,0xcc,0x4d,0x3b, +0x98,0x72,0xda,0xdc,0xf2,0x7b,0xd4,0x11,0x1d,0xd2,0x6c,0x9a,0xe5,0x9c,0xd6,0x0d, +0xdd,0x35,0xb1,0x63,0x76,0xbf,0x4c,0x8f,0xb3,0x58,0x36,0x07,0x0a,0x7e,0x5b,0x1b, +0xb5,0x6e,0x73,0x0e,0x2c,0xf6,0x79,0x71,0x03,0xd6,0xfa,0xe5,0xee,0x2f,0x92,0x23, +0x72,0x4c,0xbe,0x55,0xcf,0x5d,0xd6,0xef,0x4d,0x87,0x96,0xf7,0x56,0x62,0x3b,0x73, +0xfb,0x38,0xbb,0x3f,0x73,0xfb,0x31,0xfb,0xb9,0xfb,0xfd,0xdd,0xf0,0xbe,0x99,0x08, +0x1f,0x6b,0xdb,0xea,0x59,0x41,0xbd,0xeb,0xa5,0xfe,0xfc,0xdc,0xdf,0x7f,0xf0,0xb4, +0xe6,0xe9,0x9c,0xf8,0xfb,0xc7,0x6a,0xb2,0x3c,0xd3,0x79,0x1c,0xee,0xdf,0xcf,0x6b, +0x5e,0x28,0xd9,0x7b,0x5e,0x67,0x9b,0x3f,0x7b,0xfd,0xdf,0xad,0xf3,0xa5,0xff,0xb7, +0xaf,0xcf,0x45,0xf7,0x81,0xdd,0xe3,0xba,0xfa,0x1b,0xe0,0xbf,0xa2,0xcf,0xfc,0x97, +0xec,0xfb,0xf2,0x2e,0xfa,0xfb,0xbb,0x7b,0xdd,0x35,0x1a,0xbe,0x03,0x0b,0xf8,0x5d, +0x1a,0xf0,0xf7,0x92,0x76,0xf8,0xba,0xb8,0xab,0xd3,0x35,0xd9,0x7a,0x7f,0xaf,0xe9, +0x37,0x55,0xf7,0x8c,0xf5,0x6f,0xb4,0x5c,0xa7,0xfd,0xf3,0x4c,0x72,0xed,0x86,0xf4, +0xef,0x4a,0x8b,0xfa,0x1b,0xcd,0x93,0xe8,0x5e,0xd7,0x97,0x55,0xd0,0xbf,0xfa,0x32, +0x5f,0xa7,0xd3,0x7a,0x66,0x30,0xa6,0x75,0xba,0xbb,0x7c,0x1f,0xab,0xdc,0x7f,0xad, +0xd2,0xa2,0xdf,0xbf,0xb3,0x55,0xf0,0x0e,0x82,0x63,0xb1,0xe7,0xfb,0x64,0xdd,0xd8, +0x1a,0x3d,0xdf,0x67,0x84,0xef,0x48,0xec,0xbb,0x72,0xcb,0xef,0x93,0xde,0xe8,0x99, +0x95,0x57,0xfd,0xfe,0x6a,0xa8,0xfa,0x77,0xe5,0x1c,0x8f,0xae,0x91,0x5c,0x8e,0x9e, +0xdb,0x94,0xfe,0x1e,0xd8,0xd1,0xe8,0xde,0xd7,0x89,0x4c,0xf5,0x8c,0x21,0x7e,0x11, +0xdd,0xc7,0xfa,0x9d,0xef,0x87,0x78,0xa0,0x2e,0xbe,0xcb,0x77,0x73,0x49,0xfa,0xaf, +0xf0,0x59,0x34,0xdd,0xd1,0x3b,0xf6,0xbe,0x95,0x93,0x55,0x76,0x2e,0xe5,0xde,0xb9, +0xdc,0x18,0x3d,0xb7,0xf6,0x6a,0xf4,0x8c,0xc7,0x1b,0xd1,0x33,0x1e,0x6f,0x2d,0xf1, +0xef,0xc1,0x48,0xfe,0x39,0xba,0xed,0x91,0xdb,0x92,0xef,0xa6,0x3e,0xb6,0x44,0xde, +0x91,0x53,0xa7,0x7f,0xc7,0xea,0xfd,0x31,0xba,0x16,0x8d,0xa3,0x1a,0x92,0x52,0xc6, +0x4a,0x8c,0xa9,0xeb,0x1e,0x99,0xec,0x3d,0xfe,0xcf,0xab,0xa2,0x4e,0xe7,0xc6,0xca, +0x3d,0xc9,0x8e,0x27,0xc9,0xbc,0xde,0x7d,0x11,0x6f,0xb8,0xff,0xa6,0x31,0xac,0xe7, +0x63,0x87,0x7f,0x56,0x61,0x63,0xf6,0x79,0xd6,0x4b,0xe4,0x1d,0xa3,0xb9,0xf7,0xd2, +0x9f,0x89,0x5c,0xe9,0x68,0xce,0x3f,0xe7,0x3b,0x4b,0x57,0x91,0x67,0x7d,0x67,0x19, +0x2a,0xa1,0xad,0x59,0x9c,0xb6,0xfc,0xfa,0xae,0xf9,0xe7,0x82,0x67,0xcb,0xd2,0x90, +0x2f,0xdf,0x29,0x7b,0x64,0xc9,0xbe,0xb3,0xe1,0xb8,0xcd,0xbe,0xcb,0x75,0xea,0xfa, +0x6e,0x69,0xcf,0x19,0x76,0xcf,0x34,0x19,0x57,0xd7,0x3d,0x56,0xd7,0xb9,0xeb,0x65, +0x2f,0xaa,0xc6,0x75,0x8f,0xa3,0xb1,0xc0,0x5c,0xa7,0x7b,0xfd,0xfd,0x97,0x1d,0x2b, +0x39,0x96,0xba,0x8f,0xdd,0x3d,0x4f,0x2d,0xdb,0x66,0x76,0x6d,0xae,0x93,0x6f,0xf8, +0x7b,0xfb,0xde,0x84,0x1c,0x97,0xb8,0xe7,0x3a,0xe6,0xf1,0x3c,0xf5,0x51,0x75,0xc9, +0x83,0x68,0x0c,0xec,0x77,0x55,0xf2,0xdc,0xa6,0x17,0xd1,0x58,0x3a,0x75,0x9d,0x1b, +0x63,0x92,0xc1,0x75,0x6f,0xa6,0xff,0x66,0x7a,0x5e,0xe1,0xa3,0xe8,0x9a,0x46,0xfa, +0xe7,0x59,0x67,0xdf,0x67,0xda,0xe2,0xeb,0x37,0xbc,0xcf,0x74,0x69,0xe6,0x98,0x1e, +0xb7,0xd3,0xaf,0xe4,0xb9,0x5c,0xbf,0xc4,0x78,0xf4,0x6c,0x93,0xc9,0x62,0xcf,0x0f, +0xae,0x80,0xeb,0x26,0xa3,0xef,0xf5,0x18,0xd7,0xea,0xf0,0x5f,0x31,0xff,0x4d,0xe3, +0x65,0x34,0x16,0xd3,0xf5,0x67,0x95,0xf8,0xbd,0x91,0x21,0xff,0x1c,0x10,0xd7,0xf6, +0xbb,0xa8,0xe7,0xd4,0x59,0xf5,0xe2,0x89,0xd7,0xfa,0x5d,0xf6,0x4b,0x25,0x27,0xf2, +0x9e,0xbb,0x9a,0x7f,0xbe,0xfa,0xc8,0xfc,0x3c,0xe7,0xea,0x74,0xbe,0xbf,0xf3,0x59, +0x55,0xb4,0x5f,0x1d,0xcf,0x73,0xae,0xd3,0xb2,0xa9,0xeb,0x32,0xa3,0xf8,0x05,0xff, +0xcd,0xdb,0x7f,0x33,0x7f,0xbf,0x7c,0x9b,0x79,0xde,0x63,0x36,0xfb,0xf4,0x7c,0xbb, +0xa1,0x5e,0x6c,0xf1,0xd7,0xc3,0x4e,0x15,0x7d,0x27,0x14,0x79,0x95,0xbe,0xd6,0x53, +0x72,0x2e,0xef,0xb8,0xeb,0xd2,0xed,0xaf,0x47,0xde,0x9e,0xe7,0xbd,0x4a,0xee,0x99, +0x9c,0xd9,0xb6,0xeb,0xb3,0xaa,0xe8,0x93,0x88,0xdf,0x0f,0x96,0x1b,0x57,0xf7,0xa0, +0x94,0x77,0x4e,0x00,0xfe,0x9b,0xa7,0xff,0x8a,0x39,0xf1,0x69,0xb6,0x8f,0xcc,0xd7, +0x13,0xe7,0xd7,0x47,0x36,0xe8,0xcf,0xd1,0x2e,0x7f,0xbe,0x66,0xdd,0xd8,0x18,0xf5, +0x11,0x1c,0xc6,0x69,0x33,0xbc,0xc3,0xb5,0x3e,0xea,0xd7,0xb9,0xe2,0xfb,0x75,0x3a, +0x5f,0xf1,0x3d,0x39,0xf7,0xb2,0xd7,0xe8,0xdc,0x7d,0x99,0x51,0x7f,0x44,0x15,0x3d, +0xb3,0x29,0x7c,0x19,0x8d,0x37,0x71,0x7f,0x77,0x1f,0x9a,0x37,0xfa,0x5e,0x09,0xfc, +0x57,0x75,0xfe,0x2b,0xfe,0x9d,0x5d,0xc0,0x71,0xef,0xd2,0x17,0xf5,0xa9,0xb6,0x46, +0x7d,0xaa,0x97,0xa2,0xfe,0xd4,0xb3,0x51,0x5f,0x6a,0xdd,0x92,0x6f,0x5b,0x1f,0x8b, +0x7c,0xff,0x6d,0xd4,0x4f,0xdc,0x1c,0xf5,0x1d,0x77,0x2d,0xe0,0x38,0xc8,0xc8,0x73, +0x99,0xec,0x33,0xd6,0x27,0xab,0xef,0x99,0x9c,0xfe,0x39,0x26,0x93,0xd1,0x7d,0x61, +0xae,0x5f,0x8e,0x31,0xc4,0xf8,0x6f,0x09,0xfa,0xaf,0x28,0xb9,0xf7,0xe5,0x65,0x9f, +0xd1,0x73,0xbf,0x0c,0xd7,0xa3,0xa7,0xc6,0x9f,0x74,0xc6,0xc6,0xbb,0x34,0x9b,0xa9, +0xb1,0x30,0x8e,0x7a,0x7b,0x2a,0x36,0x0e,0xa5,0x90,0x74,0x6d,0xf2,0xa3,0x32,0xdb, +0x32,0x72,0xef,0x31,0xcc,0xd2,0x92,0x1f,0x7f,0xd3,0x1a,0x1b,0x23,0xd3,0xbf,0xe0, +0xdf,0xa7,0xbb,0xf9,0x6b,0x73,0xd9,0xb1,0x25,0xb9,0x77,0x81,0x55,0xdf,0x33,0xd6, +0x5f,0xe6,0x9f,0x43,0x97,0x6b,0x37,0xe0,0x02,0xfc,0xb7,0xb8,0xfe,0x7b,0x18,0x4e, +0x44,0xed,0x9d,0x97,0x55,0x30,0xa6,0xbe,0xf0,0xf9,0x65,0xf7,0x69,0xeb,0xcc,0x38, +0x6e,0xce,0xed,0x97,0xf8,0x3b,0x5c,0x27,0xab,0xfe,0x5d,0x39,0x05,0xe3,0x4d,0x18, +0x5b,0x07,0x55,0x38,0xfe,0x39,0x7b,0x0d,0xe8,0x71,0x54,0x67,0xa8,0xbe,0x76,0x51, +0xee,0xfe,0xca,0xa9,0x67,0xa0,0x65,0xc7,0x2e,0x16,0x7f,0x46,0xed,0x52,0x22,0xf7, +0x1c,0xdd,0xf1,0xe8,0x79,0xbc,0xc9,0x77,0x53,0xbf,0x58,0x22,0xef,0xf4,0x7a,0x9e, +0xbf,0x37,0x6c,0x42,0x5d,0x47,0xbf,0x04,0x2c,0xdd,0xfb,0x3f,0xdc,0xbd,0x97,0xe3, +0xd1,0xb5,0xa2,0xa5,0xf3,0x2e,0xbe,0xc2,0xf7,0xd2,0x7f,0x97,0x7b,0xce,0x50,0xe4, +0x95,0x6c,0xdd,0x72,0x2c,0x73,0xbf,0xe8,0xf3,0xbe,0xd3,0xb6,0xc9,0xef,0x9a,0xd9, +0x96,0x71,0xdf,0xb7,0x41,0xb3,0xeb,0x9b,0xc8,0x97,0x23,0x3b,0x2e,0x2e,0x57,0xc6, +0x97,0x4b,0xf6,0xbd,0x0d,0x09,0xcf,0xf9,0xeb,0xbb,0xb4,0x5f,0xe1,0xf5,0xf2,0x5f, +0xb1,0x67,0xb7,0x4e,0x98,0xaa,0xbc,0x76,0x0e,0x65,0xa8,0xcf,0xbd,0x48,0x78,0x2e, +0xfb,0xcc,0x61,0xce,0x59,0x78,0x33,0xfd,0x57,0x74,0x8c,0x58,0xbe,0x8e,0xc3,0xfb, +0x4c,0x5f,0x13,0xcf,0x51,0x9f,0x03,0xfc,0x37,0x6f,0x46,0xb3,0xcf,0x68,0x0b,0xb3, +0xcf,0x68,0x7b,0x5a,0x25,0xf7,0x42,0xe1,0xb9,0xa9,0x76,0xeb,0xa3,0xfc,0xf3,0xd5, +0x39,0x07,0x01,0xff,0x2d,0xd6,0xf3,0xfe,0xb3,0xcf,0x38,0x9a,0xc8,0xbf,0x13,0xfa, +0x05,0x5e,0x5a,0xf0,0x7b,0xc0,0x72,0xef,0x90,0x70,0x8e,0xcb,0xbd,0x07,0x8c,0x7e, +0x08,0xc0,0x7f,0xd5,0xfa,0xfe,0xf3,0x6c,0x5f,0xc2,0x98,0xef,0x33,0x98,0x88,0xfa, +0x3e,0xbf,0xe7,0x1a,0x63,0xd1,0x77,0xb8,0x3e,0x4d,0xf4,0xeb,0x8c,0xbd,0xf6,0xef, +0xc9,0x01,0xfc,0xf7,0x3a,0xfb,0xaf,0xb4,0x71,0x6f,0xb9,0xb1,0xbd,0xd9,0xb1,0x8b, +0xdf,0x57,0xd7,0xfd,0x5a,0xaf,0x30,0x46,0x2e,0xfe,0x6e,0x6a,0x37,0x56,0x2e,0x72, +0x5b,0x86,0x71,0x90,0x80,0xff,0xde,0x64,0xff,0x95,0x3e,0x8e,0x2e,0xdb,0xce,0xce, +0xfb,0x32,0x36,0x16,0x26,0xee,0xcd,0x99,0x79,0x51,0xc2,0x98,0xed,0xe2,0x4c,0xc6, +0xd6,0x37,0x31,0x35,0xfe,0x26,0x36,0x46,0x86,0x71,0xc0,0x80,0xff,0xf0,0x1f,0x00, +0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff, +0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f, +0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00, +0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00, +0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8, +0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00, +0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f, +0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00, +0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87, +0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03, +0x00,0xfc,0xc7,0xfe,0x07,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00, +0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0, +0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03, +0x00,0xc0,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f, +0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07, +0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0, +0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xd8, +0xff,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00, +0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80, +0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f, +0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0, +0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1, +0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00, +0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03, +0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00, +0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f, +0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0xc0,0x7f,0xf8,0x0f, +0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0, +0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1, +0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00, +0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00, +0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0x96,0xb6,0xff,0x86,0xf1, +0x1f,0x00,0x50,0xff,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01, +0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00, +0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f, +0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00, +0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87, +0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03, +0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xec,0x7f,0x00,0xc0, +0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07, +0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00, +0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0xf8,0x0f, +0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07, +0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0, +0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0, +0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x8f,0xfd,0x0f,0x00,0xf8,0x0f,0x00,0x00, +0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f, +0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00, +0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0, +0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1, +0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00, +0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc, +0x87,0xff,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff, +0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00, +0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0, +0x1f,0x00,0x00,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0, +0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1, +0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00, +0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc, +0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00, +0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80, +0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x80,0xff,0xf0, +0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00, +0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe, +0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff, +0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0x00,0x00,0xfc, +0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00, +0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80, +0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff, +0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff, +0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00, +0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f, +0xfe,0x03,0x00,0xfc,0xc7,0xfe,0x07,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0, +0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01, +0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00, +0xfe,0x03,0x00,0xc0,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f,0xfc,0x07,0x00, +0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f,0x00,0xe0,0x3f, +0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80,0xff,0xf0,0x1f, +0x00,0xe0,0x3f,0xfc,0x07,0x00,0xf8,0x0f,0xff,0x01,0x00,0xfe,0xc3,0x7f,0x00,0x80, +0xff,0xd8,0xff,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0, +0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0x00,0xfc,0x07, +0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00, +0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f, +0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00, +0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87, +0xff,0x00,0x00,0xff,0xe1,0x3f,0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0x00,0x00, +0xfe,0x03,0x00,0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f, +0x00,0x00,0xfc,0x07,0x00,0x80,0xff,0x00,0x00,0xf0,0x1f,0x00,0x00,0xfe,0x03,0x00, +0xc0,0x7f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xff,0x01,0x00,0xe0,0x3f,0x00,0xc0,0x7f, +0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00,0xff,0xe1,0x3f, +0x00,0xc0,0x7f,0xf8,0x0f,0x00,0xf0,0x1f,0xfe,0x03,0x00,0xfc,0x87,0xff,0x00,0x00, +0xff,0x95,0xe0,0xbf,0x11,0x19,0x31,0x00,0x00,0x95,0xa3,0x82,0xfe,0x0b,0x74,0xfd, +0x00,0x00,0x95,0x62,0x51,0xfd,0xf7,0x38,0x11,0xf6,0x3f,0x00,0x54,0xd6,0x7f,0x8f, +0x6d,0xdc,0x49,0xe5,0xf5,0xdf,0xa3,0x44,0xa8,0x7b,0x03,0x40,0x65,0x79,0x64,0xe3, +0x4e,0x2a,0xaf,0xff,0x26,0x12,0xb9,0x1d,0xdc,0x36,0x00,0x00,0x15,0x43,0x26,0x6c, +0xdc,0x49,0xf8,0x0f,0x00,0xf0,0x5f,0x39,0xf2,0x30,0x91,0xdb,0xe2,0xd6,0x0f,0x00, +0x50,0x29,0x1e,0xda,0xb8,0x93,0xca,0xeb,0xbf,0xf1,0x44,0x86,0x83,0x61,0x03,0x00, +0x50,0x31,0x64,0xdc,0xc6,0x9d,0x54,0x5e,0xff,0x8d,0x25,0x32,0x2c,0x6e,0xfd,0x00, +0x00,0x95,0x62,0xcc,0xc6,0x9d,0x54,0x5e,0xff,0x3d,0x48,0x64,0x48,0x86,0x0c,0x00, +0x40,0xe5,0x78,0x60,0xe3,0x4e,0x2a,0xaf,0xff,0xee,0x27,0xc2,0xbe,0x07,0x80,0xca, +0x72,0xdf,0xc6,0x9d,0x54,0x5e,0xff,0xdd,0x4b,0x64,0x50,0x06,0x0d,0x00,0x40,0xe5, +0xb8,0x67,0xe3,0x4e,0x2a,0xaf,0xff,0xee,0x26,0xa2,0xeb,0xb7,0x00,0x00,0x95,0xe3, +0xae,0x8d,0x3b,0xa9,0xbc,0xfe,0xbb,0x93,0xc8,0x80,0x0c,0x18,0x00,0x80,0xca,0x71, +0xc7,0xc6,0x9d,0x54,0x5e,0xff,0x8d,0x24,0xa2,0xeb,0xb7,0x00,0x00,0x95,0x63,0xc4, +0xc6,0x9d,0x54,0x5e,0xff,0xdd,0x4e,0xa4,0x5f,0xfa,0x0d,0x00,0x40,0xe5,0xb8,0x6d, +0xe3,0x4e,0x5a,0x64,0xff,0x59,0x00,0x80,0xca,0x31,0x6c,0x87,0x65,0x2a,0xe5,0xf5, +0xdf,0x60,0x22,0xb7,0xe4,0x96,0x05,0x00,0xa8,0x1c,0xbe,0x1f,0x24,0x9f,0xf2,0xfa, +0x6f,0x20,0x11,0xf6,0x3d,0x00,0x54,0x16,0x7f,0x1d,0x30,0x6f,0xa4,0x72,0xfb,0xaf, +0x3f,0x96,0x3e,0xe9,0xb3,0x00,0x00,0x95,0xc3,0xb7,0x83,0xa3,0x74,0x95,0xd9,0x7f, +0xde,0x79,0xf1,0xb0,0xff,0x01,0xa0,0xd2,0x44,0xb9,0x5a,0xf6,0xfa,0xdf,0xcd,0x64, +0x2c,0x00,0x40,0x85,0x89,0x72,0xae,0xec,0xfd,0x1f,0x3d,0x89,0xb0,0xef,0x01,0xa0, +0x72,0x24,0x7d,0x54,0x57,0x66,0xff,0x2d,0xd3,0x75,0x74,0xc7,0xd2,0x23,0xbd,0xd2, +0x6b,0x01,0x00,0x16,0x9f,0x1e,0x1b,0xb7,0x51,0x67,0xd9,0xed,0xb7,0x4c,0x7d,0xd7, +0x99,0x48,0x37,0xc7,0x01,0x00,0x2a,0x80,0x1a,0xcf,0xc6,0x5d,0x74,0x69,0x11,0xfc, +0xd7,0x2f,0x37,0x0a,0xd2,0xe5,0xea,0xa0,0x00,0x00,0x8b,0x48,0x97,0x2d,0x34,0xd1, +0xa9,0x45,0xf0,0x9f,0x6b,0x01,0x77,0x14,0xe4,0x86,0x74,0x73,0x3c,0x00,0x60,0x91, +0xe8,0x56,0xf7,0x15,0x5a,0xe8,0xc2,0xa2,0xd8,0x6f,0x99,0x0c,0xe9,0xba,0xda,0xa6, +0xa5,0x43,0x7d,0xdc,0xcd,0xb1,0x01,0x80,0x32,0xd2,0x2d,0x5d,0xce,0x3f,0xb6,0xd0, +0x3f,0x2d,0x8b,0x64,0x3f,0x97,0x5b,0xd2,0x4a,0x08,0x21,0x55,0x93,0x93,0x8b,0xe8, +0xbf,0x65,0xd2,0x2d,0xd7,0x08,0x21,0xa4,0x2a,0x72,0x76,0x51,0xed,0xe7,0xd2,0x21, +0x17,0x09,0x21,0xa4,0xe2,0x39,0xbd,0xe8,0xf6,0x73,0xe9,0x92,0x0b,0x52,0x4f,0x08, +0x21,0x15,0xcb,0x29,0x39,0x22,0xb5,0x15,0xf1,0x9f,0x4b,0xb3,0x1c,0x27,0x84,0x90, +0x8a,0xe4,0x88,0x1c,0xd2,0x2c,0xab,0x60,0xda,0xe5,0x9c,0x1c,0x56,0x03,0x13,0x42, +0xc8,0xe2,0xc5,0x99,0xef,0xb0,0xcf,0xb2,0x8a,0xa7,0x5b,0xae,0x68,0x5d,0xf4,0x98, +0xec,0x23,0x84,0x90,0xb2,0xe5,0x80,0x1c,0xf4,0xde,0x3b,0x92,0xcf,0x32,0x42,0x08, +0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21, +0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84, +0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x10,0x42,0x08,0x21,0x84,0x54, +0x79,0xfe,0x3f,0x57,0x9d,0xaa,0x31}; diff --git a/source/ngc/ttf/font.ttf b/source/ngc/ttf/font.ttf new file mode 100644 index 0000000..d8d07cd Binary files /dev/null and b/source/ngc/ttf/font.ttf differ diff --git a/source/ngc/video.cpp b/source/ngc/video.cpp new file mode 100644 index 0000000..4050bac --- /dev/null +++ b/source/ngc/video.cpp @@ -0,0 +1,619 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Video + * + * This is a modified renderer from the Genesis Plus Project. + * Well - you didn't expect me to write another one did ya ? -;) + * + * softdev July 2006 + * crunchy2 May 2007 + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "snes9x.h" +#include "memmap.h" +//#include "debug.h" +//#include "cpuexec.h" +//#include "ppu.h" +//#include "apu.h" +//#include "display.h" +//#include "gfx.h" +//#include "soundux.h" +//#include "spc700.h" +//#include "spc7110.h" +//#include "controls.h" +#include "aram.h" +//#include "video.h" + +/*** Snes9x GFX Buffer ***/ +static unsigned char snes9xgfx[1024 * 512 * 2]; + +/*** Memory ROM Loading ***/ +extern unsigned long ARAM_ROMSIZE; +extern unsigned int SMBTimer; + +/*** 2D Video ***/ +unsigned int *xfb[2] = { NULL, NULL }; /*** Double buffered ***/ +int whichfb = 0; /*** Switch ***/ +GXRModeObj *vmode; /*** General video mode ***/ +int screenheight = 480; + +/*** GX ***/ +#define TEX_WIDTH 512 +#define TEX_HEIGHT 512 +#define DEFAULT_FIFO_SIZE 256 * 1024 +unsigned int copynow = GX_FALSE; +static unsigned char gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN (32); +static unsigned char texturemem[TEX_WIDTH * (TEX_HEIGHT + 8)] ATTRIBUTE_ALIGN (32); +GXTexObj texobj; +static Mtx view; +int vwidth, vheight, oldvwidth, oldvheight; + +u32 FrameTimer = 0; + +#define HASPECT 76 +#define VASPECT 54 + +/* New texture based scaler */ +typedef struct tagcamera +{ + Vector pos; + Vector up; + Vector view; +} +camera; + +/*** Square Matrix + This structure controls the size of the image on the screen. + Think of the output as a -80 x 80 by -60 x 60 graph. +***/ +s16 square[] ATTRIBUTE_ALIGN (32) = +{ + /* + * X, Y, Z + * Values set are for roughly 4:3 aspect + */ + -HASPECT, VASPECT, 0, // 0 + HASPECT, VASPECT, 0, // 1 + HASPECT, -VASPECT, 0, // 2 + -HASPECT, -VASPECT, 0, // 3 +}; + +static camera cam = { {0.0F, 0.0F, 0.0F}, +{0.0F, 0.5F, 0.0F}, +{0.0F, 0.0F, -0.5F} +}; + +#ifdef VIDEO_THREADING +/**************************************************************************** + * VideoThreading + ****************************************************************************/ +#define TSTACK 16384 +lwpq_t videoblankqueue; +lwp_t vbthread; +static unsigned char vbstack[TSTACK]; + +/**************************************************************************** + * vbgetback + * + * This callback enables the emulator to keep running while waiting for a + * vertical blank. + * + * Putting LWP to good use :) + ****************************************************************************/ +static void * +vbgetback (void *arg) +{ + while (1) + { + VIDEO_WaitVSync (); /**< Wait for video vertical blank */ + LWP_SuspendThread (vbthread); + } + + return NULL; + +} + +/**************************************************************************** + * InitVideoThread + * + * libOGC provides a nice wrapper for LWP access. + * This function sets up a new local queue and attaches the thread to it. + ****************************************************************************/ +void +InitVideoThread () +{ + /*** Initialise a new queue ***/ + LWP_InitQueue (&videoblankqueue); + + /*** Create the thread on this queue ***/ + LWP_CreateThread (&vbthread, vbgetback, NULL, vbstack, TSTACK, 80); +} + +#endif + +/**************************************************************************** + * copy_to_xfb + * + * Stock code to copy the GX buffer to the current display mode. + * Also increments the frameticker, as it's called for each vb. + ****************************************************************************/ +static void +copy_to_xfb (u32 arg) +{ + + if (copynow == GX_TRUE) + { + GX_SetZMode (GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetColorUpdate (GX_TRUE); + GX_CopyDisp (xfb[whichfb], GX_TRUE); + GX_Flush (); + copynow = GX_FALSE; + } + + FrameTimer++; + SMBTimer++; + +} + +/**************************************************************************** + * WIP3 - Scaler Support Functions + ****************************************************************************/ +static void +draw_init () +{ + GX_ClearVtxDesc (); + GX_SetVtxDesc (GX_VA_POS, GX_INDEX8); + GX_SetVtxDesc (GX_VA_CLR0, GX_INDEX8); + GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_SetArray (GX_VA_POS, square, 3 * sizeof (s16)); + + GX_SetNumTexGens (1); + GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GX_InvalidateTexAll (); + GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, + GX_CLAMP, GX_CLAMP, GX_FALSE); +} + +static void +draw_vert (u8 pos, u8 c, f32 s, f32 t) +{ + GX_Position1x8 (pos); + GX_Color1x8 (c); + GX_TexCoord2f32 (s, t); +} + +static void +draw_square (Mtx v) +{ + Mtx m; // model matrix. + Mtx mv; // modelview matrix. + + /* + * Use C functions! + * Calling the faster asm ones cause reboot! + */ + guMtxIdentity (m); + guMtxTransApply (m, m, 0, 0, -100); + guMtxConcat (v, m, mv); + + GX_LoadPosMtxImm (mv, GX_PNMTX0); + GX_Begin (GX_QUADS, GX_VTXFMT0, 4); + draw_vert (0, 0, 0.0, 0.0); + draw_vert (1, 0, 1.0, 0.0); + draw_vert (2, 0, 1.0, 1.0); + draw_vert (3, 0, 0.0, 1.0); + GX_End (); +} + +/**************************************************************************** + * StartGX + * + * This function initialises the GX. + * WIP3 - Based on texturetest from libOGC examples. + ****************************************************************************/ +static void +StartGX () +{ + Mtx p; + + GXColor background = { 0, 0, 0, 0xff }; + + /*** Clear out FIFO area ***/ + memset (&gp_fifo, 0, DEFAULT_FIFO_SIZE); + + /*** Initialise GX ***/ + GX_Init (&gp_fifo, DEFAULT_FIFO_SIZE); + GX_SetCopyClear (background, 0x00ffffff); + + GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); + GX_SetDispCopyYScale ((f32) vmode->xfbHeight / (f32) vmode->efbHeight); + GX_SetScissor (0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopySrc (0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopyDst (vmode->fbWidth, vmode->xfbHeight); + GX_SetCopyFilter (vmode->aa, vmode->sample_pattern, GX_TRUE, + vmode->vfilter); + GX_SetFieldMode (vmode->field_rendering, + ((vmode->viHeight == + 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); + GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR); + GX_SetCullMode (GX_CULL_NONE); + GX_CopyDisp (xfb[whichfb], GX_TRUE); + GX_SetDispCopyGamma (GX_GM_1_0); + + guPerspective (p, 60, 1.33F, 10.0F, 1000.0F); + GX_LoadProjectionMtx (p, GX_PERSPECTIVE); + + vwidth = 100; + vheight = 100; +} + +/**************************************************************************** + * InitGCVideo + * + * This function MUST be called at startup. + ****************************************************************************/ + +void +InitGCVideo () +{ + /* + * Before doing anything else under libogc, + * Call VIDEO_Init + */ + + int *romptr = (int *) 0x81000000; + + VIDEO_Init (); + PAD_Init (); + DVD_Init (); + + /*** Check to see if this is a GC or a Wii ***/ +// int driveid = dvd_driveid(); +// bool8 isWii = !((driveid == 4) || (driveid == 6) || (driveid == 8)); + + AUDIO_Init (NULL); + AR_Init (NULL, 0); + + /* Before going any further, let's copy any attached ROM image ** */ + if (memcmp ((char *) romptr, "SNESROM0", 8) == 0) + { + ARAM_ROMSIZE = romptr[2]; + romptr = (int *) 0x81000020; + ARAMPut ((char *) romptr, (char *) AR_SNESROM, ARAM_ROMSIZE); + } + + /* + * Always use NTSC mode - this works on NTSC and PAL, GC and Wii + */ + vmode = &TVNtsc480IntDf; + VIDEO_Configure (vmode); + + screenheight = vmode->xfbHeight; + + /* + * Allocate the video buffers + */ + xfb[0] = (unsigned int *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); + xfb[1] = (unsigned int *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); + + /* + * A console is always useful while debugging. + */ + console_init (xfb[0], 20, 64, vmode->fbWidth, vmode->xfbHeight, + vmode->fbWidth * 2); + + /* + * Clear framebuffers etc. + */ + VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK); + VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK); + VIDEO_SetNextFramebuffer (xfb[0]); + + /* + * Let libogc populate manage the PADs for us + */ + VIDEO_SetPostRetraceCallback (PAD_ScanPads); + VIDEO_SetPreRetraceCallback (copy_to_xfb); + VIDEO_SetBlack (FALSE); + VIDEO_Flush (); + VIDEO_WaitVSync (); + if (vmode->viTVMode & VI_NON_INTERLACE) + VIDEO_WaitVSync (); + + // DVD_Init (); + copynow = GX_FALSE; + StartGX (); + + #ifdef VIDEO_THREADING + InitVideoThread (); + #endif + + /* + * Finally, the video is up and ready for use :) + */ +} + +/**************************************************************************** + * Drawing screen + ****************************************************************************/ +void +clearscreen () +{ + whichfb ^= 1; + ARAMFetch ((char *) xfb[whichfb], (char *) AR_BACKDROP, + 640 * screenheight * 2); +} + +void +showscreen () +{ + copynow = GX_FALSE; + VIDEO_SetNextFramebuffer (xfb[whichfb]); + VIDEO_Flush (); + VIDEO_WaitVSync (); +} + +/**************************************************************************** + * setGFX + * + * Setup the global GFX information for Snes9x + ****************************************************************************/ +void +setGFX () +{ + GFX.Screen = (unsigned short *) snes9xgfx; + GFX.Pitch = 1024; +} + +#ifndef NGCC +#if 0 +/**************************************************************************** + * MakeTexture + * + * GC requires RGB565 colour tiles of 4 x 4 pixels. + * Ok, apparently the pipeline stalls waiting for the indexed register to update. + * Solution : Use R9 to mirror R4 + * + * THIS IS NOW UNUSED, BUT LEFT HERE SO I CAN TINKER -;) + ****************************************************************************/ +void +MakeTexture (char *src, /*** R3 Pointer to source ***/ + char *dst, /*** R4 Pointer to output ***/ + int width, /*** R5 Width ***/ + int height, /*** R6 Height ***/ + int w1, /*** R7 Worker ***/ + int w2, /*** R8 Worker ***/ + int w3, /*** R9 Worker ***/ + int w4) /*** R10 Worker ***/ +{ + /*** How many tiles per row ***/ + asm ("srwi 5,5,2"); /*** Width / 4 == Tiles ***/ + asm ("srwi 6,6,2"); /*** Height / 4 == Tiles ***/ + + asm ("mr 9,4"); /*** Mirror R4 ***/ + asm ("subi 4,4,8"); /*** Adjust R4 for index update ***/ + asm ("subi 9,9,4"); /*** Adjust R9 for index update ***/ + + /*** Outer loop ***/ + asm ("DoAllTiles:"); + + asm ("mtctr 5"); /*** Will loop for this number of tiles across ***/ + asm ("mr 8,3"); /*** Preserve current source position ***/ + + asm ("DoOneTile:"); + + /*** Store 4 Horizontal Pixels - ROW 1 ***/ + asm ("lwz 7,0(3)"); + asm ("stwu 7,8(4)"); + asm ("lwz 10,4(3)"); + asm ("stwu 10,8(9)"); + + /*** Store 4 Horizontal Pixels - ROW 2 ***/ + asm ("lwz 7,1024(3)"); + asm ("stwu 7,8(4)"); + asm ("lwz 10,1028(3)"); + asm ("stwu 10,8(9)"); + + /*** Store 4 Horizontal Pixels - ROW 3 ***/ + asm ("lwz 7,2048(3)"); + asm ("stwu 7,8(4)"); + asm ("lwz 10,2052(3)"); + asm ("stwu 10,8(9)"); + + /*** Store 4 Horizontal Pixels - ROW 4 ***/ + asm ("lwz 7,3072(3)"); + asm ("stwu 7,8(4)"); + asm ("lwz 10,3076(3)"); + asm ("stwu 10,8(9)"); + + /*** Move along 4 pixels ***/ + asm ("addi 3,3,8"); + + /*** Repeat for next tile ***/ + asm ("bdnz DoOneTile"); + + /*** Update R3 to be 4 rows down ***/ + asm ("mr 3,8"); + asm ("addi 3,3,4096"); + + /*** Decrement Outer Tile loop ***/ + asm ("subi 6,6,1"); + asm ("cmpwi 6,0"); + asm ("bne DoAllTiles"); + +} +#endif + +/**************************************************************************** + * MakeTexture + * + * Proper GNU Asm rendition of the above, converted by shagkur. - Thanks! + ****************************************************************************/ +void +MakeTexture (const void *src, void *dst, s32 width, s32 height) +{ + register u32 tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0; + + __asm__ __volatile__ (" srwi %6,%6,2\n" + " srwi %7,%7,2\n" + " subi %3,%4,4\n" + " mr %4,%3\n" + " subi %4,%4,4\n" + "2: mtctr %6\n" + " mr %0,%5\n" + // + "1: lwz %1,0(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,4(%5)\n" + " stwu %2,8(%3)\n" + " lwz %1,1024(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,1028(%5)\n" + " stwu %2,8(%3)\n" + " lwz %1,2048(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,2052(%5)\n" + " stwu %2,8(%3)\n" + " lwz %1,3072(%5)\n" + " stwu %1,8(%4)\n" + " lwz %2,3076(%5)\n" + " stwu %2,8(%3)\n" + " addi %5,%5,8\n" + " bdnz 1b\n" + " addi %5,%0,4096\n" + " subic. %7,%7,1\n" + " bne 2b" + // 0 1 2 3 4 5 6 7 + :"=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), + "=&r" (tmp3), "+r" (dst):"r" (src), "r" (width), + "r" (height)); +} + +#endif + +/**************************************************************************** + * Update Video + ****************************************************************************/ +void +update_video (int width, int height) +{ + vwidth = width; + vheight = height; + +#ifdef VIDEO_THREADING + /* Ensure previous vb has complete */ + while ((LWP_ThreadIsSuspended (vbthread) == 0) || (copynow == GX_TRUE)) +#else + while (copynow == GX_TRUE) +#endif + { + usleep (50); + } + + whichfb ^= 1; + + if ((oldvheight != vheight) || (oldvwidth != vwidth)) + { + /** Update scaling **/ + oldvwidth = vwidth; + oldvheight = vheight; + draw_init (); + + memset (&view, 0, sizeof (Mtx)); + guLookAt(view, &cam.pos, &cam.up, &cam.view); + GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); + } + + GX_InvVtxCache (); + GX_InvalidateTexAll (); + GX_SetTevOp (GX_TEVSTAGE0, GX_DECAL); + GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + +#ifdef NGCC + int h, w; + int *dst = (int *) texturemem; + int *src = (int *) GFX.Screen; + int hpos; + + /*** Pitch for screen, regardless of size is always the same ***/ + for (h = 0; h < vheight; h += 4) + { + + for (w = 0; w < (vwidth >> 1); w += 2) + { + + hpos = w; + *dst++ = src[hpos++]; + *dst++ = src[hpos]; + + hpos = w + 256; + *dst++ = src[hpos++]; + *dst++ = src[hpos]; + + hpos = w + 512; + *dst++ = src[hpos++]; + *dst++ = src[hpos]; + + hpos = w + 768; + *dst++ = src[hpos++]; + *dst++ = src[hpos]; + + } + + src += GFX.Pitch; + + } + +#else + + MakeTexture ((char *) GFX.Screen, (char *) texturemem, vwidth, vheight); + +#endif + + DCFlushRange (texturemem, TEX_WIDTH * TEX_HEIGHT * 2); + + GX_SetNumChans (1); + + GX_LoadTexObj (&texobj, GX_TEXMAP0); + + draw_square (view); + + GX_DrawDone (); + VIDEO_SetNextFramebuffer (xfb[whichfb]); + VIDEO_Flush (); + copynow = GX_TRUE; + +#ifdef VIDEO_THREADING + /* Return to caller, don't waste time waiting for vb */ + LWP_ResumeThread (vbthread); +#endif + +} + +void +zoom (float speed) +{ + Vector v; + + v.x = cam.view.x - cam.pos.x; + v.y = cam.view.y - cam.pos.y; + v.z = cam.view.z - cam.pos.z; + + cam.pos.x += v.x * speed; + cam.pos.z += v.z * speed; + cam.view.x += v.x * speed; + cam.view.z += v.z * speed; + + oldvheight = 0; +} diff --git a/source/ngc/video.h b/source/ngc/video.h new file mode 100644 index 0000000..12bea9b --- /dev/null +++ b/source/ngc/video.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * Snes9x 1.50 + * + * Nintendo Gamecube Video + * + * This is a modified renderer from the Genesis Plus Project. + * Well - you didn't expect me to write another one did ya ? -;) + * + * softdev July 2006 + ****************************************************************************/ +#ifndef _GCVIDEOH_ + +#define _GCVIDEOH_ +#include "snes9x.h" + +void InitGCVideo (); +void clearscreen (); +void showscreen (); +void setGFX (); +void update_video (int width, int height); +void zoom (float speed); + +#endif diff --git a/source/smb/DES.c b/source/smb/DES.c new file mode 100644 index 0000000..8095566 --- /dev/null +++ b/source/smb/DES.c @@ -0,0 +1,726 @@ +/* ========================================================================== ** + * + * DES.c + * + * Copyright: + * Copyright (C) 2003, 2004 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: DES.c,v 0.6 2004/05/30 05:41:20 crh Exp $ + * + * -------------------------------------------------------------------------- ** + * + * Description: + * + * Implements DES encryption, but not decryption. + * DES is used to create LM password hashes and both LM and NTLM Responses. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * This implementation was created by studying many existing examples + * found in Open Source, in the public domain, and in various documentation. + * The SMB protocol makes minimal use of the DES function, so this is a + * minimal implementation. That which is not required has been removed. + * + * The SMB protocol uses the DES algorithm as a hash function, not an + * encryption function. The auth_DEShash() implemented here is a one-way + * function. The reverse is not implemented in this module. Also, there + * is no attempt at making this either fast or efficient. There is no + * need, as the auth_DEShash() function is used for generating the LM + * Response from a 7-byte key and an 8-byte challenge. It is not intended + * for use in encrypting large blocks of data or data streams. + * + * As stated above, this implementation is based on studying existing work + * in the public domain or under Open Source (specifically LGPL) license. + * The code, however, is written from scratch. Obviously, I make no claim + * with regard to those earlier works (except to claim that I am grateful + * to the previous implementors whose work I studied). See the list of + * references below for resources I used. + * + * References: + * I read through the libmcrypt code to see how they put the pieces + * together. See: http://mcrypt.hellug.gr/ + * Libmcrypt is available under the terms of the LGPL. + * + * The libmcrypt implementation includes the following credits: + * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted + * from the 1977 public-domain program by Jim Gillogly + * Modified for additional speed - 6 December 1988 Phil Karn + * Modified for parameterized key schedules - Jan 1991 Phil Karn + * modified in order to use the libmcrypt API by Nikos Mavroyanopoulos + * All modifications are placed under the license of libmcrypt. + * + * See also Phil Karn's privacy and security page: + * http://www.ka9q.net/privacy.html + * + * I relied heavily upon: + * Applied Cryptography, Second Edition: + * Protocols, Algorithms, and Source Code in C + * by Bruce Schneier. ISBN 0-471-11709-9, John Wiley & Sons, Inc., 1996 + * Particularly Chapter 12. + * + * Here's one more DES resource, which I found quite helpful (aside from + * the Clinton jokes): + * http://www.aci.net/kalliste/des.htm + * + * Finally, the use of DES in SMB is covered in: + * Implementing CIFS - the Common Internet File System + * by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003 + * Section 15.3, in particular. + * (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3) + * + * ========================================================================== ** + */ + +#include "DES.h" + + +/* -------------------------------------------------------------------------- ** + * Static Constants: + */ + +/* Initial permutation map. + * In the first step of DES, the bits of the initial plaintext are rearranged + * according to the map given below. This map and those like it are read by + * the Permute() function (below) which uses the maps as a guide when moving + * bits from one place to another. + * + * Note that the values here are all one less than those shown in Schneier. + * That's because C likes to start counting from 0, not 1. + * + * According to Schneier (Ch12, pg 271), the purpose of the initial + * permutation was to make it easier to load plaintext and ciphertext into + * a DES ecryption chip. I have no idea why that would be the case. + */ +static const uint8_t InitialPermuteMap[64] = + { + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6 + }; + + +/* Key permutation map. + * Like the input data and encryption result, the key is permuted before + * the algorithm really gets going. The original algorithm called for an + * eight-byte key in which each byte contained a parity bit. During the + * key permutiation, the parity bits were discarded. The DES algorithm, + * as used with SMB, does not make use of the parity bits. Instead, SMB + * passes 7-byte keys to DES. For DES implementations that expect parity, + * the parity bits must be added. In this case, however, we're just going + * to start with a 7-byte (56 bit) key. KeyPermuteMap, below, is adjusted + * accordingly and, of course, each entry in the map is reduced by 1 with + * respect to the documented values because C likes to start counting from + * 0, not 1. + */ +static const uint8_t KeyPermuteMap[56] = + { + 49, 42, 35, 28, 21, 14, 7, 0, + 50, 43, 36, 29, 22, 15, 8, 1, + 51, 44, 37, 30, 23, 16, 9, 2, + 52, 45, 38, 31, 55, 48, 41, 34, + 27, 20, 13, 6, 54, 47, 40, 33, + 26, 19, 12, 5, 53, 46, 39, 32, + 25, 18, 11, 4, 24, 17, 10, 3, + }; + + +/* Key rotation table. + * At the start of each round of encryption, the key is split and each + * 28-bit half is rotated left. The number of bits of rotation per round + * is given in the table below. + */ +static const uint8_t KeyRotation[16] = + { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; + + +/* Key compression table. + * This table is used to select 48 of the 56 bits of the key. + * The left and right halves of the source text are each 32 bits, + * but they are expanded to 48 bits and the results are XOR'd + * against the compressed (48-bit) key. + */ +static const uint8_t KeyCompression[48] = + { + 13, 16, 10, 23, 0, 4, 2, 27, + 14, 5, 20, 9, 22, 18, 11, 3, + 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, + 50, 44, 32, 47, 43, 48, 38, 55, + 33, 52, 45, 41, 49, 35, 28, 31 + }; + + +/* Data expansion table. + * This table is used after the data block (64-bits) has been split + * into two 32-bit (4-byte) halves (generally denoted L and R). + * Each 32-bit half is "expanded", using this table, to a 48 bit + * data block, which is then XOR'd with the 48 bit subkey for the + * round. + */ +static const uint8_t DataExpansion[48] = + { + 31, 0, 1, 2, 3, 4, 3, 4, + 5, 6, 7, 8, 7, 8, 9, 10, + 11, 12, 11, 12, 13, 14, 15, 16, + 15, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, + 27, 28, 27, 28, 29, 30, 31, 0 + }; + + +/* The (in)famous S-boxes. + * These are used to perform substitutions. + * Six bits worth of input will return four bits of output. + * The four bit values are stored in these tables. Each table has + * 64 entries...and 6 bits provides a number between 0 and 63. + * There are eight S-boxes, one per 6 bits of a 48-bit value. + * Thus, 48 bits are reduced to 32 bits. Obviously, this step + * follows the DataExpansion step. + * + * Note that the literature generally shows this as 8 arrays each + * with four rows and 16 colums. There is a complex formula for + * mapping the 6 bit input values to the correct row and column. + * I've pre-computed that mapping, and the tables below provide + * direct 6-bit input to 4-bit output. See pp 274-274 in Schneier. + */ +static const uint8_t SBox[8][64] = + { + { /* S0 */ + 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, + 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, + 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, + 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 + }, + { /* S1 */ + 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, + 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, + 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, + 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 + }, + { /* S2 */ + 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, + 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, + 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, + 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 + }, + { /* S3 */ + 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, + 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, + 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, + 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 + }, + { /* S4 */ + 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, + 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, + 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, + 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 + }, + { /* S5 */ + 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, + 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, + 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, + 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 + }, + { /* S6 */ + 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, + 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, + 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, + 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 + }, + { /* S7 */ + 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, + 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, + 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, + 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 + } + }; + + +/* P-Box permutation. + * This permutation is applied to the result of the S-Box Substitutions. + * It's a straight-forward re-arrangement of the bits. + */ +static const uint8_t PBox[32] = + { + 15, 6, 19, 20, 28, 11, 27, 16, + 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, + 18, 12, 29, 5, 21, 10, 3, 24 + }; + + +/* Final permutation map. + * This is supposed to be the inverse of the Initial Permutation, + * but there's been a bit of fiddling done. + * As always, the values given are one less than those in the literature + * (because C starts counting from 0, not 1). In addition, the penultimate + * step in DES is to swap the left and right hand sides of the ciphertext. + * The inverse of the Initial Permutation is then applied to produce the + * final result. + * To save a step, the map below does the left/right swap as well as the + * inverse permutation. + */ +static const uint8_t FinalPermuteMap[64] = + { + 7, 39, 15, 47, 23, 55, 31, 63, + 6, 38, 14, 46, 22, 54, 30, 62, + 5, 37, 13, 45, 21, 53, 29, 61, + 4, 36, 12, 44, 20, 52, 28, 60, + 3, 35, 11, 43, 19, 51, 27, 59, + 2, 34, 10, 42, 18, 50, 26, 58, + 1, 33, 9, 41, 17, 49, 25, 57, + 0, 32, 8, 40, 16, 48, 24, 56 + }; + + +/* -------------------------------------------------------------------------- ** + * Macros: + * + * CLRBIT( STR, IDX ) + * Input: STR - (uchar *) pointer to an array of 8-bit bytes. + * IDX - (int) bitwise index of a bit within the STR array + * that is to be cleared (that is, given a value of 0). + * Notes: This macro clears a bit within an array of bits (which is + * built within an array of bytes). + * - The macro converts to an assignment of the form A &= B. + * - The string of bytes is viewed as an array of bits, read from + * highest order bit first. The highest order bit of a byte + * would, therefore, be bit 0 (within that byte). + * + * SETBIT( STR, IDX ) + * Input: STR - (uchar *) pointer to an array of 8-bit bytes. + * IDX - (int) bitwise index of a bit within the STR array + * that is to be set (that is, given a value of 1). + * Notes: This macro sets a bit within an array of bits (which is + * built within an array of bytes). + * - The macro converts to an assignment of the form A |= B. + * - The string of bytes is viewed as an array of bits, read from + * highest order bit first. The highest order bit of a byte + * would, therefore, be bit 0 (within that byte). + * + * GETBIT( STR, IDX ) + * Input: STR - (uchar *) pointer to an array of 8-bit bytes. + * IDX - (int) bit-wise index of a bit within the STR array + * that is to be read. + * Output: True (1) if the indexed bit was set, else false (0). + * + * -------------------------------------------------------------------------- ** + */ + +#define CLRBIT( STR, IDX ) ( (STR)[(IDX)/8] &= ~(0x01 << (7 - ((IDX)%8))) ) + +#define SETBIT( STR, IDX ) ( (STR)[(IDX)/8] |= (0x01 << (7 - ((IDX)%8))) ) + +#define GETBIT( STR, IDX ) (( ((STR)[(IDX)/8]) >> (7 - ((IDX)%8)) ) & 0x01) + + +/* -------------------------------------------------------------------------- ** + * Static Functions: + */ + +static void Permute( uchar *dst, + const uchar *src, + const uint8_t *map, + const int mapsize ) + /* ------------------------------------------------------------------------ ** + * Performs a DES permutation, which re-arranges the bits in an array of + * bytes. + * + * Input: dst - Destination into which to put the re-arranged bits. + * src - Source from which to read the bits. + * map - Permutation map. + * mapsize - Number of bytes represented by the . This also + * represents the number of bytes to be copied to . + * + * Output: none. + * + * Notes: and must not point to the same location. + * + * - No checks are done to ensure that there is enough room + * in , or that the bit numbers in do not exceed + * the bits available in . A good reason to make this + * function static (private). + * + * - The value is in bytes. All permutations in DES + * use tables that are a multiple of 8 bits, so there is no + * need to handle partial bytes. (Yes, I know that there + * are some machines out there that still use bytes of a size + * other than 8 bits. For our purposes we'll stick with 8-bit + * bytes.) + * + * ------------------------------------------------------------------------ ** + */ + { + int bitcount; + int i; + + /* Clear all bits in the destination. + */ + for( i = 0; i < mapsize; i++ ) + dst[i] = 0; + + /* Set destination bit if the mapped source bit it set. */ + bitcount = mapsize * 8; + for( i = 0; i < bitcount; i++ ) + { + if( GETBIT( src, map[i] ) ) + SETBIT( dst, i ); + } + } /* Permute */ + + +static void KeyShift( uchar *key, const int numbits ) + /* ------------------------------------------------------------------------ ** + * Split the 56-bit key in half & left rotate each half by bits. + * + * Input: key - The 56-bit key to be split-rotated. + * numbits - The number of bits by which to rotate the key. + * + * Output: none. + * + * Notes: There are probably several better ways to implement this. + * + * ------------------------------------------------------------------------ ** + */ + { + int i; + uchar keep = key[0]; /* Copy the highest order bits of the key. */ + + /* Repeat the shift process times. + */ + for( i = 0; i < numbits; i++ ) + { + int j; + + /* Shift the entire thing, byte by byte. + */ + for( j = 0; j < 7; j++ ) + { + if( j && (key[j] & 0x80) ) /* If the top bit of this byte is set. */ + key[j-1] |= 0x01; /* ...shift it to last byte's low bit. */ + key[j] <<= 1; /* Then left-shift the whole byte. */ + } + + /* Now move the high-order bits of each 28-bit half-key to their + * correct locations. + * Bit 27 is the lowest order bit of the first half-key. + * Before the shift, it was the highest order bit of the 2nd half-key. + */ + if( GETBIT( key, 27 ) ) /* If bit 27 is set... */ + { + CLRBIT( key, 27 ); /* ...clear bit 27. */ + SETBIT( key, 55 ); /* ...set lowest order bit of 2nd half-key. */ + } + + /* We kept the highest order bit of the first half-key in . + * If it's set, copy it to bit 27. + */ + if( keep & 0x80 ) + SETBIT( key, 27 ); + + /* Rotate the byte too, in case is 2 and there's + * a second round coming. + */ + keep <<= 1; + } + } /* KeyShift */ + + +static void sbox( uchar *dst, const uchar *src ) + /* ------------------------------------------------------------------------ ** + * Perform S-Box substitutions. + * + * Input: dst - Destination byte array into which the S-Box substituted + * bitmap will be written. + * src - Source byte array. + * + * Output: none. + * + * Notes: It's really not possible (for me, anyway) to understand how + * this works without reading one or more detailed explanations. + * Quick overview, though: + * + * After the DataExpansion step (in which a 32-bit bit array is + * expanded to a 48-bit bit array) the expanded data block is + * XOR'd with 48-bits worth of key. That 48 bits then needs to + * be condensed back into 32 bits. + * + * The S-Box substitution handles the data reduction by breaking + * the 48-bit value into eight 6-bit values. For each of these + * 6-bit values there is a table (an S-Box table). The table + * contains 64 possible values. Conveniently, a 6-bit integer + * can represent a value between 0 and 63. + * + * So, if you think of the 48-bit bit array as an array of 6-bit + * integers, you use S-Box table 0 with the 0th 6-bit value. + * Table 1 is used with the 6-bit value #1, and so on until #7. + * Within each table, the correct substitution is found based + * simply on the value of the 6-bit integer. + * + * Well, the original algorithm (and most documentation) don't + * make it so simple. There's a complex formula for mapping + * the 6-bit values to the correct substitution. Fortunately, + * those lookups can be precomputed (and have been for this + * implementation). See pp 274-274 in Schneier. + * + * Oh, and the substitute values are all 4-bit values, so each + * 6-bits gets reduced to 4-bits resulting in a 32-bit bit array. + * + * ------------------------------------------------------------------------ ** + */ + { + int i; + + /* Clear the destination array. + */ + for( i = 0; i < 4; i++ ) + dst[i] = 0; + + /* For each set of six input bits... + */ + for( i = 0; i < 8; i++ ) + { + int j; + int Snum; + int bitnum; + + /* Extract the 6-bit integer from the source. + * This will be the lookup key within the SBox[i] array. + */ + for( Snum = j = 0, bitnum = (i * 6); j < 6; j++, bitnum++ ) + { + Snum <<= 1; + Snum |= GETBIT( src, bitnum ); + } + + /* Find the correct value in the correct SBox[] + * and copy it into the destination. + * Left shift the nibble four bytes for even values of . + */ + if( 0 == (i%2) ) + dst[i/2] |= ((SBox[i][Snum]) << 4); + else + dst[i/2] |= SBox[i][Snum]; + } + } /* sbox */ + + +static void xor( uchar *dst, const uchar *a, const uchar *b, const int count ) + /* ------------------------------------------------------------------------ ** + * Perform an XOR operation on two byte arrays. + * + * Input: dst - Destination array to which the result will be written. + * a - The first string of bytes. + * b - The second string of bytes. + * count - Number of bytes to XOR against one another. + * + * Output: none. + * + * Notes: This function operates on whole byte chunks. There's no need + * to XOR partial bytes so no need to write code to handle it. + * + * - This function essentially implements dst = a ^ b; for byte + * arrays. + * + * - may safely point to the same location as or . + * + * ------------------------------------------------------------------------ ** + */ + { + int i; + + for( i = 0; i < count; i++ ) + dst[i] = a[i] ^ b[i]; + } /* xor */ + + +/* -------------------------------------------------------------------------- ** + * Functions: + */ + +uchar *auth_DESkey8to7( uchar *dst, const uchar *key ) + /* ------------------------------------------------------------------------ ** + * Compress an 8-byte DES key to its 7-byte form. + * + * Input: dst - Pointer to a memory location (minimum 7 bytes) to accept + * the compressed key. + * key - Pointer to an 8-byte DES key. See the notes below. + * + * Output: A pointer to the compressed key (same as ) or NULL if + * either or were NULL. + * + * Notes: There are no checks done to ensure that and point + * to sufficient space. Please be carefull. + * + * The two pointers, and may point to the same + * memory location. Internally, a temporary buffer is used and + * the results are copied back to . + * + * The DES algorithm uses 8 byte keys by definition. The first + * step in the algorithm, however, involves removing every eigth + * bit to produce a 56-bit key (seven bytes). SMB authentication + * skips this step and uses 7-byte keys. The + * algorithm in this module expects 7-byte keys. This function + * is used to convert an 8-byte DES key into a 7-byte SMB DES key. + * + * ------------------------------------------------------------------------ ** + */ + { + int i; + uchar tmp[7]; + static const uint8_t map8to7[56] = + { + 0, 1, 2, 3, 4, 5, 6, + 8, 9, 10, 11, 12, 13, 14, + 16, 17, 18, 19, 20, 21, 22, + 24, 25, 26, 27, 28, 29, 30, + 32, 33, 34, 35, 36, 37, 38, + 40, 41, 42, 43, 44, 45, 46, + 48, 49, 50, 51, 52, 53, 54, + 56, 57, 58, 59, 60, 61, 62 + }; + + if( (NULL == dst) || (NULL == key) ) + return( NULL ); + + Permute( tmp, key, map8to7, 7 ); + for( i = 0; i < 7; i++ ) + dst[i] = tmp[i]; + + return( dst ); + } /* auth_DESkey8to7 */ + + +uchar *auth_DEShash( uchar *dst, const uchar *key, const uchar *src ) + /* ------------------------------------------------------------------------ ** + * DES encryption of the input data using the input key. + * + * Input: dst - Destination buffer. It *must* be at least eight bytes + * in length, to receive the encrypted result. + * key - Encryption key. Exactly seven bytes will be used. + * If your key is shorter, ensure that you pad it to seven + * bytes. + * src - Source data to be encrypted. Exactly eight bytes will + * be used. If your source data is shorter, ensure that + * you pad it to eight bytes. + * + * Output: A pointer to the encrpyted data (same as ). + * + * Notes: In SMB, the DES function is used as a hashing function rather + * than an encryption/decryption tool. When used for generating + * the LM hash the input is the known value "KGS!@#$%" and + * the key is derived from the password entered by the user. + * When used to generate the LM or NTLM response, the is + * derived from the LM or NTLM hash, and the challenge is used + * as the input. + * See: http://ubiqx.org/cifs/SMB.html#SMB.8.3 + * + * - This function is called "DEShash" rather than just "DES" + * because it is only used for creating LM hashes and the + * LM/NTLM responses. For all practical purposes, however, it + * is a full DES encryption implementation. + * + * - This DES implementation does not need to be fast, nor is a + * DES decryption function needed. The goal is to keep the + * code small, simple, and well documented. + * + * - The input values are copied and refiddled within the module + * and the result is not written to until the very last + * step, so it's okay if points to the same memory as + * or . + * + * ------------------------------------------------------------------------ ** + */ + { + int i; /* Loop counter. */ + uchar K[7]; /* Holds the key, as we manipulate it. */ + uchar D[8]; /* The data block, as we manipulate it. */ + + /* Create the permutations of the key and the source. + */ + Permute( K, key, KeyPermuteMap, 7 ); + Permute( D, src, InitialPermuteMap, 8 ); + + /* DES encryption proceeds in 16 rounds. + * The stuff inside the loop is known in the literature as "function f". + */ + for( i = 0; i < 16; i++ ) + { + int j; + uchar *L = D; /* The left 4 bytes (half) of the data block. */ + uchar *R = &(D[4]); /* The right half of the ciphertext block. */ + uchar Rexp[6]; /* Expanded right half. */ + uchar Rn[4]; /* New value of R, as we manipulate it. */ + uchar SubK[6]; /* The 48-bit subkey. */ + + /* Generate the subkey for this round. + */ + KeyShift( K, KeyRotation[i] ); + Permute( SubK, K, KeyCompression, 6 ); + + /* Expand the right half (R) of the data block to 48 bytes, + * then XOR the result with the Subkey for this round. + */ + Permute( Rexp, R, DataExpansion, 6 ); + xor( Rexp, Rexp, SubK, 6 ); + + /* S-Box substitutions, P-Box permutation, and final XOR. + * The S-Box substitutions return a 32-bit value, which is then + * run through the 32-bit to 32-bit P-Box permutation. The P-Box + * result is then XOR'd with the left-hand half of the key. + * (Rexp is used as a temporary variable between the P-Box & XOR). + */ + sbox( Rn, Rexp ); + Permute( Rexp, Rn, PBox, 4 ); + xor( Rn, L, Rexp, 4 ); + + /* The previous R becomes the new L, + * and Rn is moved into R ready for the next round. + */ + for( j = 0; j < 4; j++ ) + { + L[j] = R[j]; + R[j] = Rn[j]; + } + } + + /* The encryption is complete. + * Now reverse-permute the ciphertext to produce the final result. + * We actually combine two steps here. The penultimate step is to + * swap the positions of L and R in the result of the 16 rounds, + * after which the reverse of the Initial Permutation is applied. + * To save a step, the FinalPermuteMap applies both the L/R swap + * and the inverse of the Initial Permutation. + */ + Permute( dst, D, FinalPermuteMap, 8 ); + return( dst ); + } /* auth_DEShash */ + +/* ========================================================================== */ diff --git a/source/smb/DES.h b/source/smb/DES.h new file mode 100644 index 0000000..d1b7f2e --- /dev/null +++ b/source/smb/DES.h @@ -0,0 +1,179 @@ +#ifndef AUTH_DES_H +#define AUTH_DES_H +/* ========================================================================== ** + * + * DES.h + * + * Copyright: + * Copyright (C) 2003, 2004 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: DES.h,v 0.5 2004/05/30 02:31:47 crh Exp $ + * + * -------------------------------------------------------------------------- ** + * + * Description: + * + * Implements DES encryption, but not decryption. + * DES is used to create LM password hashes and both LM and NTLM Responses. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * This implementation was created by studying many existing examples + * found in Open Source, in the public domain, and in various documentation. + * The SMB protocol makes minimal use of the DES function, so this is a + * minimal implementation. That which is not required has been removed. + * + * The SMB protocol uses the DES algorithm as a hash function, not an + * encryption function. The auth_DEShash() implemented here is a one-way + * function. The reverse is not implemented in this module. Also, there + * is no attempt at making this either fast or efficient. There is no + * need, as the auth)DEShash() function is used for generating the LM + * Response from a 7-byte key and an 8-byte challenge. It is not intended + * for use in encrypting large blocks of data or data streams. + * + * As stated above, this implementation is based on studying existing work + * in the public domain or under Open Source (specifically LGPL) license. + * The code, however, is written from scratch. Obviously, I make no claim + * with regard to those earlier works (except to claim that I am grateful + * to the previous implementors whose work I studied). See the list of + * references below for resources I used. + * + * References: + * I read through the libmcrypt code to see how they put the pieces + * together. See: http://mcrypt.hellug.gr/ + * Libmcrypt is available under the terms of the LGPL. + * + * The libmcrypt implementation includes the following credits: + * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted + * from the 1977 public-domain program by Jim Gillogly + * Modified for additional speed - 6 December 1988 Phil Karn + * Modified for parameterized key schedules - Jan 1991 Phil Karn + * modified in order to use the libmcrypt API by Nikos Mavroyanopoulos + * All modifications are placed under the license of libmcrypt. + * + * See also Phil Karn's privacy and security page: + * http://www.ka9q.net/privacy.html + * + * I relied heavily upon: + * Applied Cryptography, Second Edition: + * Protocols, Algorithms, and Source Code in C + * by Bruce Schneier. ISBN 0-471-11709-9, John Wiley & Sons, Inc., 1996 + * Particularly Chapter 12. + * + * Here's one more DES resource, which I found quite helpful (aside from + * the Clinton jokes): + * http://www.aci.net/kalliste/des.htm + * + * Finally, the use of DES in SMB is covered in: + * Implementing CIFS - the Common Internet File System + * by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003 + * Section 15.3, in particular. + * (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3) + * + * ========================================================================== ** + */ + +//#include "auth_common.h" +#include +typedef unsigned char uchar; +typedef unsigned char uint8_t; + +/* -------------------------------------------------------------------------- ** + * Functions: + */ + +uchar *auth_DESkey8to7( uchar *dst, const uchar *key ); + /* ------------------------------------------------------------------------ ** + * Compress an 8-byte DES key to its 7-byte form. + * + * Input: dst - Pointer to a memory location (minimum 7 bytes) to accept + * the compressed key. + * key - Pointer to an 8-byte DES key. See the notes below. + * + * Output: A pointer to the compressed key (same as ) or NULL if + * either or were NULL. + * + * Notes: There are no checks done to ensure that and point + * to sufficient space. Please be carefull. + * + * The two pointers, and may point to the same + * memory location. Internally, a temporary buffer is used and + * the results are copied back to . + * + * The DES algorithm uses 8 byte keys by definition. The first + * step in the algorithm, however, involves removing every eigth + * bit to produce a 56-bit key (seven bytes). SMB authentication + * skips this step and uses 7-byte keys. The + * algorithm in this module expects 7-byte keys. This function + * is used to convert an 8-byte DES key into a 7-byte SMB DES key. + * + * ------------------------------------------------------------------------ ** + */ + + +uchar *auth_DEShash( uchar *dst, const uchar *key, const uchar *src ); + /* ------------------------------------------------------------------------ ** + * DES encryption of the input data using the input key. + * + * Input: dst - Destination buffer. It *must* be at least eight bytes + * in length, to receive the encrypted result. + * key - Encryption key. Exactly seven bytes will be used. + * If your key is shorter, ensure that you pad it to seven + * bytes. + * src - Source data to be encrypted. Exactly eight bytes will + * be used. If your source data is shorter, ensure that + * you pad it to eight bytes. + * + * Output: A pointer to the encrpyted data (same as ). + * + * Notes: In SMB, the DES function is used as a hashing function rather + * than an encryption/decryption tool. When used for generating + * the LM hash the input is the known value "KGS!@#$%" and + * the key is derived from the password entered by the user. + * When used to generate the LM or NTLM response, the is + * derived from the LM or NTLM hash, and the challenge is used + * as the input. + * See: http://ubiqx.org/cifs/SMB.html#SMB.8.3 + * + * - This function is called "DEShash" rather than just "DES" + * because it is only used for creating LM hashes and the + * LM/NTLM responses. For all practical purposes, however, it + * is a full DES encryption implementation. + * + * - This DES implementation does not need to be fast, nor is a + * DES decryption function needed. The goal is to keep the + * code small, simple, and well documented. + * + * - The input values are copied and refiddled within the module + * and the result is not written to until the very last + * step, so it's okay if points to the same memory as + * or . + * + * ------------------------------------------------------------------------ ** + */ + + +/* ========================================================================== */ +#endif /* AUTH_DES_H */ diff --git a/source/smb/LMhash.c b/source/smb/LMhash.c new file mode 100644 index 0000000..20cc6b6 --- /dev/null +++ b/source/smb/LMhash.c @@ -0,0 +1,169 @@ +/* ========================================================================== ** + * + * LMhash.c + * + * Copyright: + * Copyright (C) 2004 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: LMhash.c,v 0.1 2004/05/30 02:26:31 crh Exp $ + * + * -------------------------------------------------------------------------- ** + * + * Description: + * + * Implemention of the LAN Manager hash (LM hash) and LM response + * algorithms. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * This module implements the LM hash. The NT hash is simply the MD4() of + * the password, so we don't need a separate implementation of that. This + * module also implements the LM response, which can be combined with the + * NT hash to produce the NTLM response. + * + * This implementation was created based on the description in my own book. + * The book description was, in turn, written after studying many existing + * examples in various documentation. Jeremy Allison and Andrew Tridgell + * deserve lots of credit for having figured out the secrets of Lan Manager + * authentication many years ago. + * + * See: + * Implementing CIFS - the Common Internet File System + * by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003 + * Section 15.3, in particular. + * (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3) + * + * ========================================================================== ** + */ + +#include "DES.h" +#include "LMhash.h" + + +/* -------------------------------------------------------------------------- ** + * Static Constants: + * + * SMB_LMhash_Magic - This is the plaintext "magic string" that is used to + * generate the LM Hash from the user's password. This + * value was a Microsoft "secret" for many years. + */ + +static const uchar SMB_LMhash_Magic[8] = + { 'K', 'G', 'S', '!', '@', '#', '$', '%' }; + + +/* -------------------------------------------------------------------------- ** + * Functions: + */ + +uchar *auth_LMhash( uchar *dst, const uchar *pwd, const int pwdlen ) + /* ------------------------------------------------------------------------ ** + * Generate an LM Hash from the input password. + * + * Input: dst - Pointer to a location to which to write the LM Hash. + * Requires 16 bytes minimum. + * pwd - Source password. Should be in OEM charset (extended + * ASCII) format in all upper-case, but this + * implementation doesn't really care. See the notes + * below. + * pwdlen - Length, in bytes, of the password. Normally, this + * will be strlen( pwd ). + * + * Output: Pointer to the resulting LM hash (same as ). + * + * Notes: This function does not convert the input password to upper + * case. The upper-case conversion should be done before the + * password gets this far. DOS codepage handling and such + * should be taken into consideration. Rather than attempt to + * work out all those details here, the function assumes that + * the password is in the correct form before it reaches this + * point. + * + * ------------------------------------------------------------------------ ** + */ + { + int i, + max14; + uint8_t tmp_pwd[14] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + /* Copy at most 14 bytes of into . + * If the password is less than 14 bytes long + * the rest will be nul padded. + */ + max14 = pwdlen > 14 ? 14 : pwdlen; + for( i = 0; i < max14; i++ ) + tmp_pwd[i] = pwd[i]; + + /* The password is split into two 7-byte keys, each of which + * are used to DES-encrypt the magic string. The results are + * concatonated to produce the 16-byte LM Hash. + */ + (void)auth_DEShash( dst, tmp_pwd, SMB_LMhash_Magic ); + (void)auth_DEShash( &dst[8], &tmp_pwd[7], SMB_LMhash_Magic ); + + /* Return a pointer to the result. + */ + return( dst ); + } /* auth_LMhash */ + + +uchar *auth_LMresponse( uchar *dst, const uchar *hash, const uchar *challenge ) + /* ------------------------------------------------------------------------ ** + * Generate the LM (or NTLM) response from the password hash and challenge. + * + * Input: dst - Pointer to memory into which to write the response. + * Must have 24 bytes available. + * hash - Pointer to the 16-byte password hash. + * challenge - Pointer to the 8-byte challenge. + * + * Output: A pointer to the 24-byte response (same as ). + * + * Notes: The function does not check the lengths of the input or output + * parameters. The byte sizes given above must be respected by + * calling function. + * + * ------------------------------------------------------------------------ ** + */ + { + uchar tmp[7] = + { hash[14], hash[15], 0,0,0,0,0 }; /* 3rd key is nul-padded. */ + + /* It's painfully simple... + * The challenge is DES encrypted three times. + * The first time, the first 7 bytes of the hash are used. + * The second time, the second 7 bytes of the hash are used. + * The third time, the two remaining hash bytes plus five nuls are used. + * The three 8-byte results are concatonated to form the 24-byte response. + */ + (void)auth_DEShash( dst, hash, challenge ); + (void)auth_DEShash( &dst[8], &hash[7], challenge ); + (void)auth_DEShash( &dst[16], tmp, challenge ); + + /* Return the result. + */ + return( dst ); + } /* auth_LMresponse */ + +/* ========================================================================== */ diff --git a/source/smb/LMhash.h b/source/smb/LMhash.h new file mode 100644 index 0000000..ad94f6a --- /dev/null +++ b/source/smb/LMhash.h @@ -0,0 +1,115 @@ +#ifndef AUTH_LMHASH_H +#define AUTH_LMHASH_H +/* ========================================================================== ** + * + * LMhash.h + * + * Copyright: + * Copyright (C) 2004 by Christopher R. Hertel + * + * Email: crh@ubiqx.mn.org + * + * $Id: LMhash.h,v 0.1 2004/05/30 02:26:31 crh Exp $ + * + * -------------------------------------------------------------------------- ** + * + * Description: + * + * Implemention of the LAN Manager hash (LM hash) and LM response + * algorithms. + * + * -------------------------------------------------------------------------- ** + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- ** + * + * Notes: + * + * This module implements the LM hash. The NT hash is simply the MD4() of + * the password, so we don't need a separate implementation of that. This + * module also implements the LM response, which can be combined with the + * NT hash to produce the NTLM response. + * + * This implementation was created based on the description in my own book. + * The book description was, in turn, written after studying many existing + * examples in various documentation. Jeremy Allison and Andrew Tridgell + * deserve lots of credit for having figured out the secrets of Lan Manager + * authentication many years ago. + * + * See: + * Implementing CIFS - the Common Internet File System + * by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003 + * Section 15.3, in particular. + * (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3) + * + * ========================================================================== ** + */ + + +/* -------------------------------------------------------------------------- ** + * Functions: + */ + +uchar *auth_LMhash( uchar *dst, const uchar *pwd, const int pwdlen ); + /* ------------------------------------------------------------------------ ** + * Generate an LM Hash from the input password. + * + * Input: dst - Pointer to a location to which to write the LM Hash. + * Requires 16 bytes minimum. + * pwd - Source password. Should be in OEM charset (extended + * ASCII) format in all upper-case, but this + * implementation doesn't really care. See the notes + * below. + * pwdlen - Length, in bytes, of the password. Normally, this + * will be strlen( pwd ). + * + * Output: Pointer to the resulting LM hash (same as ). + * + * Notes: This function does not convert the input password to upper + * case. The upper-case conversion should be done before the + * password gets this far. DOS codepage handling and such + * should be taken into consideration. Rather than attempt to + * work out all those details here, the function assumes that + * the password is in the correct form before it reaches this + * point. + * + * ------------------------------------------------------------------------ ** + */ + + +uchar *auth_LMresponse( uchar *dst, const uchar *hash, const uchar *challenge ); + /* ------------------------------------------------------------------------ ** + * Generate the LM (or NTLM) response from the password hash and challenge. + * + * Input: dst - Pointer to memory into which to write the response. + * Must have 24 bytes available. + * hash - Pointer to the 16-byte password hash. + * challenge - Pointer to the 8-byte challenge. + * + * Output: A pointer to the 24-byte response (same as ). + * + * Notes: The function does not check the lengths of the input or output + * parameters. The byte sizes given above must be respected by + * calling function. + * + * ------------------------------------------------------------------------ ** + */ + + +/* ========================================================================== */ +#endif /* AUTH_LMHASH_H */ diff --git a/source/smb/readme1st.txt b/source/smb/readme1st.txt new file mode 100644 index 0000000..8e6e1bc --- /dev/null +++ b/source/smb/readme1st.txt @@ -0,0 +1,112 @@ +TinySMB-GC 0.1 +May 2006 + +Developer Documentation + +What is TinySMB-GC? + +TinySMB-GC is a minimal implementation of the SMB protocol for the Nintendo Gamecube. + +What does it do? + +Essentially, TinySMB-GC enables network share support. This means that it will allow the +GameCube to connect to a shared folder on a Windows XP or linux samba box, and perform +basic file functions. + +Known Restrictions + +TinySMB-GC only supports the LM1.2X002 protocol. THIS IS NOT THE MOST SECURE! +However, it does NOT transmit your password over the wire, so it's reasonably safe. + +How do I use it? + +TinySMB-GC is developed with devkitPPC and libOGC, therefore you should be using this +development environment. Put simply, it won't work with anything else! + +TinySMB-GC uses the TCP-raw form of SMB on port 445. + +The Functions. + +int SMB_Init (char *user, /*** The logon user - MUST have share access rights ***/ + char *password, /*** PLEASE USE PASSWORD SECURITY! ***/ + char *client, /*** Machine ID, whatever you want to call the GC ***/ + char *server, /*** Machine ID of share server ***/ + char *share, /*** Share ID ***/ + char *IP); /*** IP of share server ***/ + +SMB_Init is used to establish the connection, authenticate and attach to the share. +Obviously, this must be called successfully before any other function. + +void SMB_Destroy (); + +SMB_Destroy takes care of releasing the internal socket of TinySMB-GC and should be +called when the SMB functions are no longer required. + +int SMB_FindFirst (char *filename, /*** The file mask to search for ***/ + unsigned short flags, /*** Search criteria flags ***/ + SMBDIRENTRY * sdir); /*** An SMBDIRENTRY to hold directory information ***/ + +Similar to MS-Windows, to search for a file or directory, use this function to determine if the +file already exists. The SMBDIRENTRY simply holds basic information on each entry retrieved. + +int SMB_FindNext (SMBDIRENTRY * sdir); + +Called to continue a search started with SMB_FindFirst. + +int SMB_FindClose (); + +When all searches have completed, call SMB_FindClose to dispense with the search handle. + +SMBFILE SMB_Open (char *filename, /*** The filename to open ***/ + unsigned short access, /*** Access method ***/ + unsigned short creation); /*** Creation flags ***/ + +This call will open a file on the share. Both reading and writing are supported. +Look at smb.h for information on the access and creation flags. + +void SMB_Close (SMBFILE sfid); + +Close a file previously opened with SMB_Open + +int SMB_Read (char *buffer, int size, int offset, SMBFILE sfile); + +Read from the file opened with SMB_Open. + +int SMB_Write (char *buffer, int size, int offset, SMBFILE sfile); + +Write to the file opened with SMB_Open. + +NOTE: The offset value provides the missing seek function. However, the onus +is on the developer to maintain the offset value when reading / writing +sequentially. + +You should also be aware that these functions should only be used to read/write +blocks up to 62Kbytes. Although it allows reading and writing of 4Gb files, it +does not support blocks larger then 16-bit - go figure! + +Credits + +TinySMB-GC Copyright softdev@tehskeen.com + Please respect this copyright! + NOTE WELL: This software is released under GPL 2.1 + YOU MAY NOT STEAL IT AND HIDE IT IN YOUR + CLOSED SOURCE PRODUCT. + +libOGC shagkur + +devkitPPC wntrmute + +CIFS Info Christopher R Hertel + http://www.ubiqx.com + Storage Networking Industry Association + http://www.snia.com + Ethereal - Packet Capture + http://www.ethereal.com + +Thanks + +Cedy_NL, for testing and helping get this off the ground. +brakken, web hosting and promotion. + +Everyone who has participated in the Genesis Plus Project - keep up the good work ! + \ No newline at end of file diff --git a/source/smb/smb.c b/source/smb/smb.c new file mode 100644 index 0000000..4d9a5b8 --- /dev/null +++ b/source/smb/smb.c @@ -0,0 +1,932 @@ +/**************************************************************************** + * TinySMB-GC + * + * Nintendo Gamecube SaMBa implementation. + * + * Copyright softdev@tehskeen.com + * + * Authentication modules, LMhash and DES are + * + * Copyright Christopher R Hertel. + * http://www.ubiqx.org + * + * You WILL find Ethereal, available from http://www.ethereal.com + * invaluable for debugging each new SAMBA implementation. + * + * Recommended Reading + * Implementing CIFS - Christopher R Hertel + * SNIA CIFS Documentation - http://www.snia.org + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ****************************************************************************/ + +#include +#include +#include "smb.h" +#include "DES.h" +#include "LMhash.h" +#include + +/** + * A few little bits for libOGC + */ +typedef int SOCKET; +#define recv net_recv +#define send net_send +#define closesocket net_close +#define connect net_connect +#define setsockopt net_setsockopt +#define socket net_socket + +/** + * Client and server SMB + */ +NBTSMB c; +NBTSMB s; +SMBSESSION session; +SOCKET smbsock; +static struct sockaddr_in smbs; +static int smbcheckbytes = 0; + +/** + * SMB Endian aware supporting functions + * + * SMB always uses Intel Little-Endian values, so htons etc are + * of little or no use :) ... Thanks M$ + */ +/*** get unsigned char ***/ +static unsigned char +getUChar (unsigned char *buffer, int offset) +{ + return buffer[offset]; +} + +/*** set unsigned char ***/ +static void +setUChar (unsigned char *buffer, int offset, unsigned char value) +{ + buffer[offset] = value; +} + +/*** get unsigned short ***/ +static unsigned short +getUShort (unsigned char *buffer, int offset) +{ + unsigned short t; + t = buffer[offset]; + t |= (buffer[offset + 1] << 8); + + return t; +} + +/*** set unsigned short ***/ +static void +setUShort (unsigned char *buffer, int offset, unsigned short value) +{ + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value & 0xff00) >> 8; +} + +/*** get unsigned int ***/ +static unsigned int +getUInt (unsigned char *buffer, int offset) +{ + unsigned int t; + + t = buffer[offset]; + t |= (buffer[offset + 1] << 8); + t |= (buffer[offset + 2] << 16); + t |= (buffer[offset + 3] << 24); + + return t; +} + +/*** set unsigned int ***/ +static void +setUInt (unsigned char *buffer, int offset, int value) +{ + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value & 0xff00) >> 8; + buffer[offset + 2] = (value & 0xff0000) >> 16; + buffer[offset + 3] = (value & 0xff000000) >> 24; +} + +/** + * MakeSMBHdr + * + * Generate the SMB header for each request. + * Uses 'c' NBTSMB + */ +static void +MakeSMBHdr (unsigned char command) +{ + int pos = 0; + + /*** Clear client packet ***/ + memset (&c, 0, sizeof (c)); + + /*** Add protocol SMB ***/ + setUInt (c.smb, pos, SMB_PROTO); + pos += 4; + setUChar (c.smb, pos, command); + pos++; + pos++; /*** Error class ***/ + pos++; /*** Reserved ***/ + pos += 2; /*** Error Code ***/ + setUChar (c.smb, pos, 0x8); + pos++; /*** Flags == 8 == Case Insensitive ***/ + setUShort (c.smb, pos, 0x1); + pos += 2; /*** Flags2 == 1 == LFN ***/ + pos += 2; /*** Process ID High ***/ + pos += 8; /*** Signature ***/ + pos += 2; /*** Reserved ***/ + setUShort (c.smb, pos, session.TID); + pos += 2; + setUShort (c.smb, pos, session.PID); + pos += 2; + setUShort (c.smb, pos, session.UID); + pos += 2; + setUShort (c.smb, pos, session.MID); +} + +/** + * MakeTRANS2Hdr + */ +static void +MakeTRANS2Hdr (unsigned char subcommand) +{ + setUChar (c.smb, T2_WORD_CNT, 15); + setUShort (c.smb, T2_MAXPRM_CNT, 10); + setUShort (c.smb, T2_MAXBUFFER, session.MaxBuffer); + setUChar (c.smb, T2_SSETUP_CNT, 1); + setUShort (c.smb, T2_SUB_CMD, subcommand); +} + +/** + * SMBCheck + * + * Do very basic checking on the return SMB + */ +static int +SMBCheck (unsigned char command, int readlen) +{ + int ret; + + memset (&s, 0, sizeof (s)); + + smbcheckbytes = ret = recv (smbsock, (char *) &s, readlen, 0); + + if (ret < 12) + return 0; + + /*** Do basic SMB Header checks ***/ + ret = getUInt (s.smb, 0); + if (ret != SMB_PROTO) + return BAD_PROTOCOL; + + if (getUChar (s.smb, 4) != command) + return SMB_BAD_COMMAND; + + ret = getUInt (s.smb, SMB_OFFSET_NTSTATUS); + + if (ret) + return SMB_ERROR; + + return SMB_SUCCESS; + +} + +/** + * SMB_NegotiateProtocol + * + * The only protocol we admit to is 'DOS LANMAN 2.1' + */ +static int +SMB_NegotiateProtocol () +{ + int pos; + int bcpos; + int ret; + char proto[] = "\2LM1.2X002"; /*** Seems to work with Samba and XP Home ***/ + unsigned short bytecount; + + /*** Clear session variables ***/ + memset (&session, 0, sizeof (session)); + session.PID = 0xdead; + session.MID = 1; + + MakeSMBHdr (SMB_NEG_PROTOCOL); + pos = SMB_HEADER; + + pos++; /*** Add word count ***/ + bcpos = pos; + pos += 2; /*** Byte count - when known ***/ + + strcpy (&c.smb[pos], proto); + + pos += strlen (proto) + 1; + + /*** Update byte count ***/ + setUShort (c.smb, bcpos, (pos - bcpos) - 2); + + /*** Set NBT information ***/ + c.msg = SESS_MSG; + c.length = htons (pos); + + pos += 4; + ret = send (smbsock, (char *) &c, pos, 0); + + /*** Check response ***/ + if (SMBCheck (SMB_NEG_PROTOCOL, sizeof (s)) == SMB_SUCCESS) + { + pos = SMB_HEADER; + /*** Collect information ***/ + if (getUChar (s.smb, pos) != 13) + return SMB_PROTO_FAIL; + + pos++; + if (getUShort (s.smb, pos)) + return SMB_PROTO_FAIL; + + pos += 2; + if (getUShort (s.smb, pos) != 3) + return SMB_NOT_USER; + + pos += 2; + session.MaxBuffer = getUShort (s.smb, pos); + pos += 2; + if (session.MaxBuffer > 2916) + session.MaxBuffer = 2916; + session.MaxMpx = getUShort (s.smb, pos); + pos += 2; + session.MaxVCS = getUShort (s.smb, pos); + pos += 2; + pos += 2; /*** Raw Mode ***/ + pos += 4; /*** Session Key ***/ + pos += 6; /*** Time information ***/ + if (getUShort (s.smb, pos) != 8) + return SMB_BAD_KEYLEN; + + pos += 2; + pos += 2; /*** Reserved ***/ + + bytecount = getUShort (s.smb, pos); + pos += 2; + + /*** Copy challenge key ***/ + memcpy (&session.challenge, &s.smb[pos], 8); + pos += 8; + /*** Primary domain ***/ + strcpy (session.p_domain, &s.smb[pos]); + + return SMB_SUCCESS; + } + + return 0; + +} + +/** + * SMB_SetupAndX + * + * Setup the SMB session, including authentication with the + * magic 'LM Response' + */ +static int +SMB_SetupAndX (char *user, char *password) +{ + int pos; + int bcpos; + char pwd[24], LMh[24], LMr[24]; + int i, ret; + + MakeSMBHdr (SMB_SETUP_ANDX); + pos = SMB_HEADER; + + setUChar (c.smb, pos, 10); + pos++; /*** Word Count ***/ + setUChar (c.smb, pos, 0xff); + pos++; /*** Next AndX ***/ + pos++; /*** Reserved ***/ + pos += 2; /*** Next AndX Offset ***/ + setUShort (c.smb, pos, session.MaxBuffer); + pos += 2; + setUShort (c.smb, pos, session.MaxMpx); + pos += 2; + setUShort (c.smb, pos, session.MaxVCS); + pos += 2; + pos += 4; /*** Session key, unknown at this point ***/ + setUShort (c.smb, pos, 24); + pos += 2; /*** Password length ***/ + pos += 4; /*** Reserved ***/ + bcpos = pos; + pos += 2; /*** Byte count ***/ + + /*** The magic 'LM Response' ***/ + strcpy (pwd, password); + for (i = 0; i < strlen (pwd); i++) + pwd[i] = toupper (pwd[i]); + + auth_LMhash (LMh, pwd, strlen (pwd)); + auth_LMresponse (LMr, LMh, session.challenge); + + /*** Build information ***/ + memcpy (&c.smb[pos], LMr, 24); + pos += 24; + + /*** Account ***/ + strcpy (pwd, user); + for (i = 0; i < strlen (user); i++) + pwd[i] = toupper (pwd[i]); + memcpy (&c.smb[pos], pwd, strlen (pwd)); + pos += strlen (pwd) + 1; + + /*** Primary Domain ***/ + memcpy (&c.smb[pos], &session.p_domain, strlen (session.p_domain)); + pos += strlen (session.p_domain) + 1; + + /*** Native OS ***/ + strcpy (pwd, "Unix (libOGC)"); + memcpy (&c.smb[pos], pwd, strlen (pwd)); + pos += strlen (pwd) + 1; + + /*** Native LAN Manager ***/ + strcpy (pwd, "Nintendo GameCube 0.1"); + memcpy (&c.smb[pos], pwd, strlen (pwd)); + pos += strlen (pwd) + 1; + + /*** Update byte count ***/ + setUShort (c.smb, bcpos, (pos - bcpos) - 2); + + c.msg = SESS_MSG; + c.length = htons (pos); + pos += 4; + + ret = send (smbsock, (char *) &c, pos, 0); + + if (SMBCheck (SMB_SETUP_ANDX, sizeof (s)) == SMB_SUCCESS) + { + /*** Collect UID ***/ + session.UID = getUShort (s.smb, SMB_OFFSET_UID); + + return SMB_SUCCESS; + } + + return 0; +} + +/** + * SMB_TreeAndX + * + * Finally, connect to the remote share + */ +static int +SMB_TreeAndX (char *server, char *share) +{ + int pos, bcpos, ret; + char path[256]; + + MakeSMBHdr (SMB_TREEC_ANDX); + pos = SMB_HEADER; + + setUChar (c.smb, pos, 4); + pos++; /*** Word Count ***/ + setUChar (c.smb, pos, 0xff); + pos++; /*** Next AndX ***/ + pos++; /*** Reserved ***/ + pos += 2; /*** Next AndX Offset ***/ + pos += 2; /*** Flags ***/ + setUShort (c.smb, pos, 1); + pos += 2; /*** Password Length ***/ + bcpos = pos; + pos += 2; + pos++; /*** NULL Password ***/ + + /*** Build server share path ***/ + strcpy (path, "\\\\"); + strcat (path, server); + strcat (path, "\\"); + strcat (path, share); + for (ret = 0; ret < strlen (path); ret++) + path[ret] = toupper (path[ret]); + + memcpy (&c.smb[pos], path, strlen (path)); + pos += strlen (path) + 1; + + /*** Service ***/ + strcpy (path, "?????"); + memcpy (&c.smb[pos], path, strlen (path)); + pos += strlen (path) + 1; + + /*** Update byte count ***/ + setUShort (c.smb, bcpos, (pos - bcpos) - 2); + + c.msg = SESS_MSG; + c.length = htons (pos); + pos += 4; + + ret = send (smbsock, (char *) &c, pos, 0); + + if (SMBCheck (SMB_TREEC_ANDX, sizeof (s)) == SMB_SUCCESS) + { + /*** Collect Tree ID ***/ + session.TID = getUShort (s.smb, SMB_OFFSET_TID); + return SMB_SUCCESS; + } + + return 0; +} + +/** + * SMB_FindFirst + * + * Uses TRANS2 to support long filenames + */ +int +SMB_FindFirst (char *filename, unsigned short flags, SMBDIRENTRY * sdir) +{ + int pos; + int ret; + int bpos; + + MakeSMBHdr (SMB_TRANS2); + MakeTRANS2Hdr (SMB_FIND_FIRST2); + pos = T2_BYTE_CNT + 2; + bpos = pos; + pos += 3; /*** Padding ***/ + + setUShort (c.smb, pos, flags); + pos += 2; /*** Flags ***/ + setUShort (c.smb, pos, 1); + pos += 2; /*** Count ***/ + setUShort (c.smb, pos, 6); + pos += 2; /*** Internal Flags ***/ + setUShort (c.smb, pos, 260); + pos += 2; /*** Level of Interest ***/ + pos += 4; /*** Storage Type == 0 ***/ + memcpy (&c.smb[pos], filename, strlen (filename)); + pos += strlen (filename) + 1; /*** Include padding ***/ + + /*** Update counts ***/ + setUShort (c.smb, T2_PRM_CNT, 13 + strlen (filename)); + setUShort (c.smb, T2_SPRM_CNT, 13 + strlen (filename)); + setUShort (c.smb, T2_SPRM_OFS, 68); + setUShort (c.smb, T2_SDATA_OFS, 81 + strlen (filename)); + setUShort (c.smb, T2_BYTE_CNT, pos - bpos); + + c.msg = SESS_MSG; + c.length = htons (pos); + + pos += 4; + + ret = send (smbsock, (char *) &c, pos, 0); + session.sid = 0; + session.count = 0; + session.eos = 1; + + if (SMBCheck (SMB_TRANS2, sizeof (s)) == SMB_SUCCESS) + { + /*** Get parameter offset ***/ + pos = getUShort (s.smb, SMB_HEADER + 9); + session.sid = getUShort (s.smb, pos); + pos += 2; + session.count = getUShort (s.smb, pos); + pos += 2; + session.eos = getUShort (s.smb, pos); + pos += 2; + pos += 46; + + if (session.count) + { + sdir->size_low = getUInt (s.smb, pos); + pos += 4; + sdir->size_high = getUInt (s.smb, pos); + pos += 4; + pos += 8; + sdir->attributes = getUInt (s.smb, pos); + pos += 38; + strcpy (sdir->name, &s.smb[pos]); + + return SMB_SUCCESS; + } + } + + return 0; + +} + +/** + * SMB_FindNext + */ +int +SMB_FindNext (SMBDIRENTRY * sdir) +{ + int pos; + int ret; + int bpos; + + if (session.eos) + return 0; + + if (session.sid == 0) + return 0; + + MakeSMBHdr (SMB_TRANS2); + MakeTRANS2Hdr (SMB_FIND_NEXT2); + pos = T2_BYTE_CNT + 2; + bpos = pos; + pos += 3; /*** Padding ***/ + + setUShort (c.smb, pos, session.sid); + pos += 2; /*** Search ID ***/ + setUShort (c.smb, pos, 1); + pos += 2; /*** Count ***/ + setUShort (c.smb, pos, 260); + pos += 2; /*** Level of Interest ***/ + pos += 4; /*** Storage Type == 0 ***/ + setUShort (c.smb, pos, 12); + pos += 2; /*** Search flags ***/ + pos++; + + /*** Update counts ***/ + setUShort (c.smb, T2_PRM_CNT, 13); + setUShort (c.smb, T2_SPRM_CNT, 13); + setUShort (c.smb, T2_SPRM_OFS, 68); + setUShort (c.smb, T2_SDATA_OFS, 81); + setUShort (c.smb, T2_BYTE_CNT, pos - bpos); + + c.msg = SESS_MSG; + c.length = htons (pos); + + pos += 4; + + ret = send (smbsock, (char *) &c, pos, 0); + + if (SMBCheck (SMB_TRANS2, sizeof (s)) == SMB_SUCCESS) + { + /*** Get parameter offset ***/ + pos = getUShort (s.smb, SMB_HEADER + 9); + session.count = getUShort (s.smb, pos); + pos += 2; + session.eos = getUShort (s.smb, pos); + pos += 2; + pos += 44; + + if (session.count) + { + sdir->size_low = getUInt (s.smb, pos); + pos += 4; + sdir->size_high = getUInt (s.smb, pos); + pos += 4; + pos += 8; + sdir->attributes = getUInt (s.smb, pos); + pos += 38; + strcpy (sdir->name, &s.smb[pos]); + + return SMB_SUCCESS; + } + } + + return 0; + +} + +/** + * SMB_FindClose + */ +int +SMB_FindClose () +{ + int pos = SMB_HEADER; + int ret; + + if (session.sid == 0) + return 0; + + MakeSMBHdr (SMB_FIND_CLOSE2); + + setUChar (c.smb, pos, 1); + pos++; /*** Word Count ***/ + setUShort (c.smb, pos, session.sid); + pos += 2; + pos += 2; /*** Byte Count ***/ + + c.msg = SESS_MSG; + c.length = htons (pos); + pos += 4; + ret = send (smbsock, (char *) &c, pos, 0); + + return SMBCheck (SMB_FIND_CLOSE2, sizeof (s)); + +} + +/** + * SMB_Open + */ +SMBFILE +SMB_Open (char *filename, unsigned short access, unsigned short creation) +{ + int pos = SMB_HEADER; + int bpos, ret; + char realfile[256]; + unsigned short fid; + + MakeSMBHdr (SMB_OPEN_ANDX); + + setUChar (c.smb, pos, 15); + pos++; /*** Word Count ***/ + setUChar (c.smb, pos, 0xff); + pos++; /*** Next AndX ***/ + pos += 3; /*** Next AndX Offset ***/ + + pos += 2; /*** Flags ***/ + setUShort (c.smb, pos, access); + pos += 2; /*** Access mode ***/ + setUShort (c.smb, pos, 0x6); + pos += 2; /*** Type of file ***/ + pos += 2; /*** Attributes ***/ + pos += 4; /*** File time - don't care - let server decide ***/ + setUShort (c.smb, pos, creation); + pos += 2; /*** Creation flags ***/ + pos += 4; /*** Allocation size ***/ + pos += 8; /*** Reserved ***/ + pos += 2; /*** Byte Count ***/ + bpos = pos; + + if (filename[0] != '\\') + { + strcpy (realfile, "\\"); + strcat (realfile, filename); + } + else + strcpy (realfile, filename); + + memcpy (&c.smb[pos], realfile, strlen (realfile)); + pos += strlen (realfile) + 1; + + setUShort (c.smb, bpos - 2, (pos - bpos)); + + c.msg = SESS_MSG; + c.length = htons (pos); + + pos += 4; + ret = send (smbsock, (char *) &c, pos, 0); + + if (SMBCheck (SMB_OPEN_ANDX, sizeof (s)) == SMB_SUCCESS) + { + /*** Check file handle ***/ + fid = getUShort (s.smb, SMB_HEADER + 5); + + if (fid) + return fid; + } + + return 0; +} + +/** + * SMB_Close + */ +void +SMB_Close (SMBFILE sfid) +{ + int pos, ret; + + MakeSMBHdr (SMB_CLOSE); + pos = SMB_HEADER; + + setUChar (c.smb, pos, 3); + pos++; /** Word Count **/ + setUShort (c.smb, pos, sfid); + pos += 2; + setUInt (c.smb, pos, 0xffffffff); + pos += 4; /*** Last Write ***/ + pos += 2; /*** Byte Count ***/ + + c.msg = SESS_MSG; + c.length = htons (pos); + pos += 4; + ret = send (smbsock, (char *) &c, pos, 0); + + SMBCheck (SMB_CLOSE, sizeof (s)); +} + +/** + * SMB_Read + */ +int +SMB_Read (char *buffer, int size, int offset, SMBFILE sfile) +{ + int pos, ret, ofs; + unsigned short length = 0; + + MakeSMBHdr (SMB_READ_ANDX); + pos = SMB_HEADER; + + /*** Don't let the size exceed! ***/ + if (size > 62 * 1024) + return 0; + + setUChar (c.smb, pos, 10); + pos++; /*** Word count ***/ + setUChar (c.smb, pos, 0xff); + pos++; + pos += 3; /*** Reserved, Next AndX Offset ***/ + setUShort (c.smb, pos, sfile); + pos += 2; /*** FID ***/ + setUInt (c.smb, pos, offset); + pos += 4; /*** Offset ***/ + + setUShort (c.smb, pos, size & 0xffff); + pos += 2; + setUShort (c.smb, pos, size & 0xffff); + pos += 2; + setUInt (c.smb, pos, 0); + pos += 4; + pos += 2; /*** Remaining ***/ + pos += 2; /*** Byte count ***/ + + c.msg = SESS_MSG; + c.length = htons (pos); + + pos += 4; + ret = send (smbsock, (char *) &c, pos, 0); + + /*** SMBCheck should now only read up to the end of a standard header ***/ + if (SMBCheck (SMB_READ_ANDX, SMB_HEADER + 27 + 4) == SMB_SUCCESS) + { + /*** Retrieve data length for this packet ***/ + length = getUShort (s.smb, SMB_HEADER + 11); + /*** Retrieve offset to data ***/ + ofs = getUShort (s.smb, SMB_HEADER + 13); + + /*** Default offset, with no padding is 59, so grab any outstanding padding ***/ + if (ofs > 59) + { + char pad[1024]; + ret = recv (smbsock, pad, ofs - 59, 0); + } + + /*** Finally, go grab the data ***/ + ofs = 0; + + if (length) + { + while (((ret = recv (smbsock, buffer + ofs, length, 0)) > 0)) + { + ofs += ret; + if (ofs == length) + break; + } + } + + return ofs; + + } + + return 0; + +} + +/** + * SMB_Write + */ +int +SMB_Write (char *buffer, int size, int offset, SMBFILE sfile) +{ + int pos, ret; + int blocks64; + + MakeSMBHdr (SMB_WRITE_ANDX); + pos = SMB_HEADER; + + setUChar (c.smb, pos, 12); + pos++; /*** Word Count ***/ + setUChar (c.smb, pos, 0xff); + pos += 2; /*** Next AndX ***/ + pos += 2; /*** Next AndX Offset ***/ + + setUShort (c.smb, pos, sfile); + pos += 2; + setUInt (c.smb, pos, offset); + pos += 4; + pos += 4; /*** Reserved ***/ + pos += 2; /*** Write Mode ***/ + pos += 2; /*** Remaining ***/ + + blocks64 = size >> 16; + + setUShort (c.smb, pos, blocks64); + pos += 2; /*** Length High ***/ + setUShort (c.smb, pos, size & 0xffff); + pos += 2; /*** Length Low ***/ + setUShort (c.smb, pos, 59); + pos += 2; /*** Data Offset ***/ + setUShort (c.smb, pos, size & 0xffff); + pos += 2; /*** Data Byte Count ***/ + + c.msg = SESS_MSG; + c.length = htons (pos + size); + + /*** Will this fit in a single send? ***/ + if (size <= 2916) + { + memcpy (&c.smb[pos], buffer, size); + pos += size; + } + else + { + memcpy (&c.smb[pos], buffer, 2916); + pos += 2916; + } + + pos += 4; + + /*** Send Header Information ***/ + ret = send (smbsock, (char *) &c, pos, 0); + + if (size > 2916) + { + /*** Send the data ***/ + ret = send (smbsock, buffer + 2916, size - 2916, 0); + } + + if (SMBCheck (SMB_WRITE_ANDX, sizeof (s)) == SMB_SUCCESS) + { + return (int) getUShort (s.smb, SMB_HEADER + 5); + } + + return 0; + +} + +/**************************************************************************** + * Primary setup, logon and connection all in one :) + ****************************************************************************/ +int +SMB_Init (char *user, char *password, char *client, + char *server, char *share, char *IP) +{ + int ret; + int nodelay; + + /*** Create the global socket ***/ + smbsock = socket (AF_INET, SOCK_STREAM, IPPROTO_IP); + + /*** Switch off Nagle, ON TCP_NODELAY ***/ + nodelay = 1; + ret = setsockopt (smbsock, IPPROTO_TCP, TCP_NODELAY, + (char *) &nodelay, sizeof (char)); + + /*** Attempt to connect to the server IP ***/ + memset (&smbs, 0, sizeof (client)); + smbs.sin_family = AF_INET; + smbs.sin_port = htons (445); + smbs.sin_addr.s_addr = inet_addr (IP); + + ret = connect (smbsock, (struct sockaddr *) &smbs, sizeof (smbs)); + + if (ret) + { + closesocket (smbsock); + return 0; + } + + if (SMB_NegotiateProtocol () == SMB_SUCCESS) + { + if (SMB_SetupAndX (user, password) == SMB_SUCCESS) + { + if (SMB_TreeAndX (server, share) == SMB_SUCCESS) + return SMB_SUCCESS; + } + } + + return 0; + +} + +/**************************************************************************** + * SMB_Destroy + * + * Probably NEVER called on GameCube, but here for completeness + ****************************************************************************/ +void +SMB_Destroy () +{ + if (smbsock) + closesocket (smbsock); +} diff --git a/source/smb/smb.h b/source/smb/smb.h new file mode 100644 index 0000000..a755cd9 --- /dev/null +++ b/source/smb/smb.h @@ -0,0 +1,219 @@ +/**************************************************************************** + * TinySMB-GC + * + * Nintendo Gamecube SaMBa implementation. + * + * Copyright softdev@tehskeen.com + * + * Authentication modules, LMhash and DES are + * + * Copyright Christopher R Hertel. + * http://www.ubiqx.org + * + * You WILL find Ethereal, available from http://www.ethereal.com + * invaluable for debugging each new SAMBA implementation. + * + * Recommended Reading + * Implementing CIFS - Christopher R Hertel + * SNIA CIFS Documentation - http://www.snia.org + * + * License: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ****************************************************************************/ +#ifndef NBTSMB_INC +#define NBTSMB_INC +#include +#include +#include + +/** + * NBT/SMB Wrapper + */ +typedef struct +{ + unsigned char msg; /*** NBT Message ***/ + unsigned char flags; /*** Not much here really ***/ + unsigned short length; /*** Length, excluding NBT ***/ + char smb[2916]; /*** GC Actual is 2920 bytes ***/ +} +NBTSMB; + +/** + * Session Information + */ +typedef struct +{ + unsigned short TID; + unsigned short PID; + unsigned short UID; + unsigned short MID; + unsigned short sKey; + unsigned short MaxBuffer; + unsigned short MaxMpx; + unsigned short MaxVCS; + unsigned char challenge[10]; + char p_domain[64]; + unsigned short sid; + unsigned short count; + unsigned short eos; +} +SMBSESSION; + +/*** SMB_FILEENTRY + SMB Long Filename Directory Entry + ***/ +typedef struct +{ + unsigned int size_low; + unsigned int size_high; + unsigned int attributes; + char name[256]; +} +SMBDIRENTRY; + +/*** + * SMB File Handle + */ +typedef unsigned short SMBFILE; + +#define SMB_HEADER 32 /*** SMB Headers are always 32 bytes long ***/ +#define SMB_PROTO 0x424d53ff + +/** + * Field offsets. + */ +#define SMB_OFFSET_CMD 4 +#define SMB_OFFSET_NTSTATUS 5 +#define SMB_OFFSET_ECLASS 5 +#define SMB_OFFSET_ECODE 7 +#define SMB_OFFSET_FLAGS 9 +#define SMB_OFFSET_FLAGS2 10 +#define SMB_OFFSET_EXTRA 12 +#define SMB_OFFSET_TID 24 +#define SMB_OFFSET_PID 26 +#define SMB_OFFSET_UID 28 +#define SMB_OFFSET_MID 30 + +/** + * Message / Commands + */ +#define SESS_MSG 0x00 +#define SMB_NEG_PROTOCOL 0x72 +#define SMB_SETUP_ANDX 0x73 +#define SMB_TREEC_ANDX 0x75 + +/** + * SMBTrans2 + */ +#define SMB_TRANS2 0x32 + +#define SMB_OPEN2 0 +#define SMB_FIND_FIRST2 1 +#define SMB_FIND_NEXT2 2 +#define SMB_QUERY_FS_INFO 3 +#define SMB_QUERY_PATH_INFO 5 +#define SMB_SET_PATH_INFO 6 +#define SMB_QUERY_FILE_INFO 7 +#define SMB_SET_FILE_INFO 8 +#define SMB_CREATE_DIR 13 +#define SMB_FIND_CLOSE2 0x34 + +/** + * File I/O + */ +#define SMB_OPEN_ANDX 0x2d +#define SMB_WRITE_ANDX 0x2f +#define SMB_READ_ANDX 0x2e +#define SMB_CLOSE 4 + +/** + * SMB File Access Modes + */ +#define SMB_OPEN_READING 0 +#define SMB_OPEN_WRITING 1 +#define SMB_OPEN_READWRITE 2 +#define SMB_OPEN_COMPATIBLE 0 +#define SMB_DENY_READWRITE 0x10 +#define SMB_DENY_WRITE 0x20 +#define SMB_DENY_READ 0x30 +#define SMB_DENY_NONE 0x40 + +/** + * SMB File Open Function + */ +#define SMB_OF_OPEN 1 +#define SMB_OF_TRUNCATE 2 +#define SMB_OF_CREATE 16 + +/** + * FileSearch + */ +#define SMB_SRCH_DIRECTORY 16 +#define SMB_SRCH_READONLY 1 +#define SMB_SRCH_HIDDEN 2 +#define SMB_SRCH_SYSTEM 4 +#define SMB_SRCH_VOLUME 8 + +/** + * SMB Error codes + */ +#define SMB_SUCCESS 1 +#define BAD_PROTOCOL -1 +#define SMB_ERROR -2 +#define SMB_BAD_COMMAND -3 +#define SMB_PROTO_FAIL -4 +#define SMB_NOT_USER -5 +#define SMB_BAD_KEYLEN -6 + +/** + * TRANS2 Offsets + */ +#define T2_WORD_CNT SMB_HEADER +#define T2_PRM_CNT T2_WORD_CNT + 1 +#define T2_DATA_CNT T2_PRM_CNT + 2 +#define T2_MAXPRM_CNT T2_DATA_CNT + 2 +#define T2_MAXBUFFER T2_MAXPRM_CNT + 2 +#define T2_SETUP_CNT T2_MAXBUFFER + 2 +#define T2_SPRM_CNT T2_SETUP_CNT + 10 +#define T2_SPRM_OFS T2_SPRM_CNT + 2 +#define T2_SDATA_CNT T2_SPRM_OFS + 2 +#define T2_SDATA_OFS T2_SDATA_CNT + 2 +#define T2_SSETUP_CNT T2_SDATA_OFS + 2 +#define T2_SUB_CMD T2_SSETUP_CNT + 2 +#define T2_BYTE_CNT T2_SUB_CMD + 2 + +/** + * Prototypes + */ + +/*** Session ***/ +int SMB_Init (char *user, char *password, char *client, + char *server, char *share, char *IP); +void SMB_Destroy (); + +/*** File Find ***/ +int SMB_FindFirst (char *filename, unsigned short flags, SMBDIRENTRY * sdir); +int SMB_FindNext (SMBDIRENTRY * sdir); +int SMB_FindClose (); + +/*** File I/O ***/ +SMBFILE SMB_Open (char *filename, unsigned short access, + unsigned short creation); +void SMB_Close (SMBFILE sfid); +int SMB_Read (char *buffer, int size, int offset, SMBFILE sfile); +int SMB_Write (char *buffer, int size, int offset, SMBFILE sfile); + +#endif diff --git a/source/snes9x/3d.h b/source/snes9x/3d.h new file mode 100644 index 0000000..cec9344 --- /dev/null +++ b/source/snes9x/3d.h @@ -0,0 +1,205 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _3D_H_ +#define _3D_H_ + +#if defined(USE_OPENGL) +#include +#include + +#ifdef __linux__ +#include +#endif + +typedef struct +{ + bool8 packed_pixels_extension_present; + bool8 draw_cube; + uint32 version; + // Texture format + GLint internal_format; + GLint format; + GLint type; + + GLint max_texture_size;// 256 or 512 + GLint texture_size; + uint32 num_textures; // 1 if max_texture_size == 256, 2 otherwise + GLuint textures [2]; +} OpenGLData; + +extern OpenGLData OpenGL; + +bool8 S9xOpenGLInit (); +bool8 S9xOpenGLInit2 (); +void S9xOpenGLPutImage (int width, int height); +void S9xOpenGLDeinit (); + +#endif + +#ifdef USE_GLIDE +#include + +typedef struct +{ + bool8 voodoo_present; + GrVertex sq[4]; + GrTexInfo texture; + int32 texture_mem_size; + int32 texture_mem_start; + float x_offset, y_offset; + float x_scale, y_scale; + float voodoo_width; + float voodoo_height; +} GlideData; + +extern GlideData Glide; +bool8 S9xGlideEnable (bool8 enable); +void S9xGlideDeinit (); +bool8 S9xGlideInit (); +bool8 S9xVoodooInitialise (); +#endif + +#endif + diff --git a/source/snes9x/65c816.h b/source/snes9x/65c816.h new file mode 100644 index 0000000..9c45fc1 --- /dev/null +++ b/source/snes9x/65c816.h @@ -0,0 +1,243 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _65c816_h_ +#define _65c816_h_ + +#define AL A.B.l +#define AH A.B.h +#define XL X.B.l +#define XH X.B.h +#define YL Y.B.l +#define YH Y.B.h +#define SL S.B.l +#define SH S.B.h +#define DL D.B.l +#define DH D.B.h +#define PL P.B.l +#define PH P.B.h + +#define Carry 1 +#define Zero 2 +#define IRQ 4 +#define Decimal 8 +#define IndexFlag 16 +#define MemoryFlag 32 +#define Overflow 64 +#define Negative 128 +#define Emulation 256 + +#define ClearCarry() (ICPU._Carry = 0) +#define SetCarry() (ICPU._Carry = 1) +#define SetZero() (ICPU._Zero = 0) +#define ClearZero() (ICPU._Zero = 1) +#define SetIRQ() (Registers.PL |= IRQ) +#define ClearIRQ() (Registers.PL &= ~IRQ) +#define SetDecimal() (Registers.PL |= Decimal) +#define ClearDecimal() (Registers.PL &= ~Decimal) +#define SetIndex() (Registers.PL |= IndexFlag) +#define ClearIndex() (Registers.PL &= ~IndexFlag) +#define SetMemory() (Registers.PL |= MemoryFlag) +#define ClearMemory() (Registers.PL &= ~MemoryFlag) +#define SetOverflow() (ICPU._Overflow = 1) +#define ClearOverflow() (ICPU._Overflow = 0) +#define SetNegative() (ICPU._Negative = 0x80) +#define ClearNegative() (ICPU._Negative = 0) + +#define CheckZero() (ICPU._Zero == 0) +#define CheckCarry() (ICPU._Carry) +#define CheckIRQ() (Registers.PL & IRQ) +#define CheckDecimal() (Registers.PL & Decimal) +#define CheckIndex() (Registers.PL & IndexFlag) +#define CheckMemory() (Registers.PL & MemoryFlag) +#define CheckOverflow() (ICPU._Overflow) +#define CheckNegative() (ICPU._Negative & 0x80) +#define CheckEmulation() (Registers.P.W & Emulation) + +#define ClearFlags(f) (Registers.P.W &= ~(f)) +#define SetFlags(f) (Registers.P.W |= (f)) +#define CheckFlag(f) (Registers.PL & (f)) + +typedef union +{ +#ifdef LSB_FIRST + struct { uint8 l,h; } B; +#else + struct { uint8 h,l; } B; +#endif + uint16 W; +} pair; + +typedef union { +#ifdef LSB_FIRST + struct { uint8 xPCl, xPCh, xPB, z; } B; + struct { uint16 xPC, d; } W; +#else + struct { uint8 z, xPB, xPCh, xPCl; } B; + struct { uint16 d, xPC; } W; +#endif + uint32 xPBPC; +} PC_t; + +struct SRegisters{ + uint8 DB; + pair P; + pair A; + pair D; + pair S; + pair X; + pair Y; + PC_t PC; +}; + +#define PBPC PC.xPBPC +#define PCw PC.W.xPC +#define PCh PC.B.xPCh +#define PCl PC.B.xPCl +#define PB PC.B.xPB + +EXTERN_C struct SRegisters Registers; + +#endif + diff --git a/source/snes9x/apu.cpp b/source/snes9x/apu.cpp new file mode 100644 index 0000000..ad4620e --- /dev/null +++ b/source/snes9x/apu.cpp @@ -0,0 +1,1008 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifdef __DJGPP +#include +#undef TRUE +#endif + +#include "snes9x.h" +#include "spc700.h" +#include "apu.h" +#include "soundux.h" +#include "display.h" +#ifdef DEBUGGER +#include "cpuexec.h" +#endif + +/* For note-triggered SPC dump support */ +#include "snapshot.h" + +extern int32 env_counter_table[32]; + +int spc_is_dumping=0; +int spc_is_dumping_temp; +uint8 spc_dump_dsp[0x100]; + +#ifdef DEBUGGER +void S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0, + int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0); +#endif + +bool8 S9xInitAPU () +{ + IAPU.RAM = (uint8 *) malloc (0x10000); + IAPU.ShadowRAM = (uint8 *) malloc (0x10000); + IAPU.CachedSamples = (uint8 *) malloc (0x40000); + + if (!IAPU.RAM || !IAPU.ShadowRAM || !IAPU.CachedSamples) + { + S9xDeinitAPU (); + return (FALSE); + } + + memset(IAPU.RAM, 0, 0x10000); + memset(IAPU.ShadowRAM, 0, 0x10000); + memset(IAPU.CachedSamples, 0, 0x40000); + + return (TRUE); +} + +void S9xDeinitAPU () +{ + if (IAPU.RAM) + { + free ((char *) IAPU.RAM); + IAPU.RAM = NULL; + } + if (IAPU.ShadowRAM) + { + free ((char *) IAPU.ShadowRAM); + IAPU.ShadowRAM = NULL; + } + if (IAPU.CachedSamples) + { + free ((char *) IAPU.CachedSamples); + IAPU.CachedSamples = NULL; + } +} + +EXTERN_C uint8 APUROM [64]; + +void S9xResetAPU () +{ + + int i; + + Settings.APUEnabled = Settings.NextAPUEnabled; + + ZeroMemory(spc_dump_dsp, 0x100); + ZeroMemory(IAPU.RAM, 0x100); + memset(IAPU.RAM+0x20, 0xFF, 0x20); + memset(IAPU.RAM+0x60, 0xFF, 0x20); + memset(IAPU.RAM+0xA0, 0xFF, 0x20); + memset(IAPU.RAM+0xE0, 0xFF, 0x20); + + for(i=1;i<256;i++) + { + memcpy(IAPU.RAM+(i<<8), IAPU.RAM, 0x100); + } + + memcpy (IAPU.ShadowRAM, IAPU.RAM, 0x10000); + + ZeroMemory (IAPU.CachedSamples, 0x40000); + ZeroMemory (APU.OutPorts, 4); + IAPU.DirectPage = IAPU.RAM; + memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM)); + memmove (APU.ExtraRAM, APUROM, sizeof (APUROM)); + IAPU.PC = IAPU.RAM + IAPU.RAM [0xfffe] + (IAPU.RAM [0xffff] << 8); + APU.Cycles = 0; + APURegisters.YA.W = 0; + APURegisters.X = 0; + APURegisters.S = 0xff; + APURegisters.P = 0; + S9xAPUUnpackStatus (); + APURegisters.PC = 0; + IAPU.APUExecuting = Settings.APUEnabled; +#ifdef SPC700_SHUTDOWN + IAPU.WaitAddress1 = NULL; + IAPU.WaitAddress2 = NULL; + IAPU.WaitCounter = 0; +#endif + IAPU.NextAPUTimerPos = 0; + IAPU.APUTimerCounter = 0; + APU.ShowROM = TRUE; + IAPU.RAM [0xf1] = 0x80; + + for (i = 0; i < 3; i++) + { + APU.TimerEnabled [i] = FALSE; + APU.TimerValueWritten [i] = 0; + APU.TimerTarget [i] = 0; + APU.Timer [i] = 0; + } + for (int j = 0; j < 0x80; j++) + APU.DSP [j] = 0; + + IAPU.TwoCycles = IAPU.OneCycle * 2; + + for (i = 0; i < 256; i++) + S9xAPUCycles [i] = S9xAPUCycleLengths [i] * IAPU.OneCycle; + + APU.DSP [APU_ENDX] = 0; + APU.DSP [APU_KOFF] = 0; + APU.DSP [APU_KON] = 0; + APU.DSP [APU_FLG] = APU_MUTE | APU_ECHO_DISABLED; + APU.KeyedChannels = 0; + + S9xResetSound (TRUE); + S9xSetEchoEnable (0); +} + +void S9xSetAPUDSP (uint8 byte) +{ + uint8 reg = IAPU.RAM [0xf2]; + static uint8 KeyOn; + static uint8 KeyOnPrev; + + spc_dump_dsp[reg] = byte; + + switch (reg) + { + case APU_FLG: + if (byte & APU_SOFT_RESET) + { + APU.DSP [reg] = APU_MUTE | APU_ECHO_DISABLED | (byte & 0x1f); + APU.DSP [APU_ENDX] = 0; + APU.DSP [APU_KOFF] = 0; + APU.DSP [APU_KON] = 0; + S9xSetEchoWriteEnable (FALSE); +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] DSP reset\n", ICPU.Scanline); +#endif + // Kill sound + S9xResetSound (FALSE); + } + else + { + S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED)); + if (byte & APU_MUTE) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Mute sound\n", ICPU.Scanline); +#endif + S9xSetSoundMute (TRUE); + } + else + S9xSetSoundMute (FALSE); + + SoundData.noise_rate = env_counter_table[byte & 0x1f]; + } + break; + case APU_NON: + if (byte != APU.DSP [APU_NON]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Noise:", ICPU.Scanline); +#endif + uint8 mask = 1; + for (int c = 0; c < 8; c++, mask <<= 1) + { + int type; + if (byte & mask) + { + type = SOUND_NOISE; +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d,", c); + else + S9xTraceSoundDSP ("%d(on),", c); + } +#endif + } + else + { + type = SOUND_SAMPLE; +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d(off),", c); + } +#endif + } + S9xSetSoundType (c, type); + } +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("\n"); +#endif + } + break; + case APU_MVOL_LEFT: + if (byte != APU.DSP [APU_MVOL_LEFT]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Master volume left:%d\n", + ICPU.Scanline, (signed char) byte); +#endif + S9xSetMasterVolume ((signed char) byte, + (signed char) APU.DSP [APU_MVOL_RIGHT]); + } + break; + case APU_MVOL_RIGHT: + if (byte != APU.DSP [APU_MVOL_RIGHT]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Master volume right:%d\n", + ICPU.Scanline, (signed char) byte); +#endif + S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT], + (signed char) byte); + } + break; + case APU_EVOL_LEFT: + if (byte != APU.DSP [APU_EVOL_LEFT]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Echo volume left:%d\n", + ICPU.Scanline, (signed char) byte); +#endif + S9xSetEchoVolume ((signed char) byte, + (signed char) APU.DSP [APU_EVOL_RIGHT]); + } + break; + case APU_EVOL_RIGHT: + if (byte != APU.DSP [APU_EVOL_RIGHT]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Echo volume right:%d\n", + ICPU.Scanline, (signed char) byte); +#endif + S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT], + (signed char) byte); + } + break; + case APU_ENDX: +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Reset ENDX\n", ICPU.Scanline); +#endif + byte = 0; + break; + + case APU_KOFF: + // if (byte) + { + uint8 mask = 1; +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Key off:", ICPU.Scanline); +#endif + for (int c = 0; c < 8; c++, mask <<= 1) + { + if ((byte & mask) != 0) + { +#ifdef DEBUGGER + + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("%d,", c); +#endif + if (APU.KeyedChannels & mask) + { + { + KeyOnPrev&=~mask; + APU.KeyedChannels &= ~mask; + APU.DSP [APU_KON] &= ~mask; + //APU.DSP [APU_KOFF] |= mask; + S9xSetSoundKeyOff (c); + } + } + } + else if((KeyOnPrev&mask)!=0) + { + KeyOnPrev&=~mask; + APU.KeyedChannels |= mask; + //APU.DSP [APU_KON] |= mask; + APU.DSP [APU_KOFF] &= ~mask; + APU.DSP [APU_ENDX] &= ~mask; + S9xPlaySample (c); + } + } +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("\n"); +#endif + } + //KeyOnPrev=0; + APU.DSP [APU_KOFF] = byte; + return; + case APU_KON: + if (spc_is_dumping) + { + if (byte & ~spc_is_dumping_temp) + { + APURegisters.PC = IAPU.PC - IAPU.RAM; + S9xAPUPackStatus(); +#ifndef NGC + S9xSPCDump (S9xGetFilenameInc((".spc"), SPC_DIR)); +#endif + spc_is_dumping = 0; + } + } + if (byte) + { + uint8 mask = 1; +#ifdef DEBUGGER + + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Key on:", ICPU.Scanline); +#endif + for (int c = 0; c < 8; c++, mask <<= 1) + { + if ((byte & mask) != 0) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("%d,", c); +#endif + // Pac-In-Time requires that channels can be key-on + // regardeless of their current state. + if((APU.DSP [APU_KOFF] & mask) ==0) + { + KeyOnPrev&=~mask; + APU.KeyedChannels |= mask; + //APU.DSP [APU_KON] |= mask; + //APU.DSP [APU_KOFF] &= ~mask; + APU.DSP [APU_ENDX] &= ~mask; + S9xPlaySample (c); + } + else KeyOn|=mask; + } + } +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("\n"); +#endif + } + spc_is_dumping_temp = byte; + return; + + case APU_VOL_LEFT + 0x00: + case APU_VOL_LEFT + 0x10: + case APU_VOL_LEFT + 0x20: + case APU_VOL_LEFT + 0x30: + case APU_VOL_LEFT + 0x40: + case APU_VOL_LEFT + 0x50: + case APU_VOL_LEFT + 0x60: + case APU_VOL_LEFT + 0x70: + // At Shin Megami Tensei suggestion 6/11/00 + // if (byte != APU.DSP [reg]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d volume left: %d\n", + ICPU.Scanline, reg>>4, (signed char) byte); +#endif + S9xSetSoundVolume (reg >> 4, (signed char) byte, + (signed char) APU.DSP [reg + 1]); + } + break; + case APU_VOL_RIGHT + 0x00: + case APU_VOL_RIGHT + 0x10: + case APU_VOL_RIGHT + 0x20: + case APU_VOL_RIGHT + 0x30: + case APU_VOL_RIGHT + 0x40: + case APU_VOL_RIGHT + 0x50: + case APU_VOL_RIGHT + 0x60: + case APU_VOL_RIGHT + 0x70: + // At Shin Megami Tensei suggestion 6/11/00 + // if (byte != APU.DSP [reg]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d volume right: %d\n", + ICPU.Scanline, reg >>4, (signed char) byte); +#endif + S9xSetSoundVolume (reg >> 4, (signed char) APU.DSP [reg - 1], + (signed char) byte); + } + break; + + case APU_P_LOW + 0x00: + case APU_P_LOW + 0x10: + case APU_P_LOW + 0x20: + case APU_P_LOW + 0x30: + case APU_P_LOW + 0x40: + case APU_P_LOW + 0x50: + case APU_P_LOW + 0x60: + case APU_P_LOW + 0x70: +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d freq low: %d\n", + ICPU.Scanline, reg>>4, byte); +#endif + S9xSetSoundHertz (reg >> 4, ((byte + (APU.DSP [reg + 1] << 8)) & FREQUENCY_MASK) * 8); + break; + + case APU_P_HIGH + 0x00: + case APU_P_HIGH + 0x10: + case APU_P_HIGH + 0x20: + case APU_P_HIGH + 0x30: + case APU_P_HIGH + 0x40: + case APU_P_HIGH + 0x50: + case APU_P_HIGH + 0x60: + case APU_P_HIGH + 0x70: +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d freq high: %d\n", + ICPU.Scanline, reg>>4, byte); +#endif + S9xSetSoundHertz (reg >> 4, + (((byte << 8) + APU.DSP [reg - 1]) & FREQUENCY_MASK) * 8); + break; + + case APU_SRCN + 0x00: + case APU_SRCN + 0x10: + case APU_SRCN + 0x20: + case APU_SRCN + 0x30: + case APU_SRCN + 0x40: + case APU_SRCN + 0x50: + case APU_SRCN + 0x60: + case APU_SRCN + 0x70: +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d sample number: %d\n", + ICPU.Scanline, reg>>4, byte); +#endif + break; + + case APU_ADSR1 + 0x00: + case APU_ADSR1 + 0x10: + case APU_ADSR1 + 0x20: + case APU_ADSR1 + 0x30: + case APU_ADSR1 + 0x40: + case APU_ADSR1 + 0x50: + case APU_ADSR1 + 0x60: + case APU_ADSR1 + 0x70: + if (byte != APU.DSP [reg]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d adsr1: %02x\n", + ICPU.Scanline, reg>>4, byte); +#endif + { + S9xFixEnvelope (reg >> 4, APU.DSP [reg + 2], byte, + APU.DSP [reg + 1]); + } + } + break; + + case APU_ADSR2 + 0x00: + case APU_ADSR2 + 0x10: + case APU_ADSR2 + 0x20: + case APU_ADSR2 + 0x30: + case APU_ADSR2 + 0x40: + case APU_ADSR2 + 0x50: + case APU_ADSR2 + 0x60: + case APU_ADSR2 + 0x70: + if (byte != APU.DSP [reg]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d adsr2: %02x\n", + ICPU.Scanline, reg>>4, byte); +#endif + { + S9xFixEnvelope (reg >> 4, APU.DSP [reg + 1], APU.DSP [reg - 1], + byte); + } + } + break; + + case APU_GAIN + 0x00: + case APU_GAIN + 0x10: + case APU_GAIN + 0x20: + case APU_GAIN + 0x30: + case APU_GAIN + 0x40: + case APU_GAIN + 0x50: + case APU_GAIN + 0x60: + case APU_GAIN + 0x70: + if (byte != APU.DSP [reg]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] %d gain: %02x\n", + ICPU.Scanline, reg>>4, byte); +#endif + { + S9xFixEnvelope (reg >> 4, byte, APU.DSP [reg - 2], + APU.DSP [reg - 1]); + } + } + break; + + case APU_ENVX + 0x00: + case APU_ENVX + 0x10: + case APU_ENVX + 0x20: + case APU_ENVX + 0x30: + case APU_ENVX + 0x40: + case APU_ENVX + 0x50: + case APU_ENVX + 0x60: + case APU_ENVX + 0x70: + break; + + case APU_OUTX + 0x00: + case APU_OUTX + 0x10: + case APU_OUTX + 0x20: + case APU_OUTX + 0x30: + case APU_OUTX + 0x40: + case APU_OUTX + 0x50: + case APU_OUTX + 0x60: + case APU_OUTX + 0x70: + break; + + case APU_DIR: +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + S9xTraceSoundDSP ("[%d] Sample directory to: %02x\n", + ICPU.Scanline, byte); +#endif + break; + + case APU_PMON: + if (byte != APU.DSP [APU_PMON]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + { + S9xTraceSoundDSP ("[%d] FreqMod:", ICPU.Scanline); + uint8 mask = 1; + for (int c = 0; c < 8; c++, mask <<= 1) + { + if (byte & mask) + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d", c); + else + S9xTraceSoundDSP ("%d(on),", c); + } + else + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d(off),", c); + } + } + S9xTraceSoundDSP ("\n"); + } +#endif + S9xSetFrequencyModulationEnable (byte); + } + break; + + case APU_EON: + if (byte != APU.DSP [APU_EON]) + { +#ifdef DEBUGGER + if (Settings.TraceSoundDSP) + { + S9xTraceSoundDSP ("[%d] Echo:", ICPU.Scanline); + uint8 mask = 1; + for (int c = 0; c < 8; c++, mask <<= 1) + { + if (byte & mask) + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d", c); + else + S9xTraceSoundDSP ("%d(on),", c); + } + else + { + if (APU.DSP [reg] & mask) + S9xTraceSoundDSP ("%d(off),", c); + } + } + S9xTraceSoundDSP ("\n"); + } +#endif + S9xSetEchoEnable (byte); + } + break; + + case APU_EFB: + S9xSetEchoFeedback ((signed char) byte); + break; + + case APU_ESA: + break; + + case APU_EDL: + S9xSetEchoDelay (byte & 0xf); + break; + + case APU_C0: + case APU_C1: + case APU_C2: + case APU_C3: + case APU_C4: + case APU_C5: + case APU_C6: + case APU_C7: + S9xSetFilterCoefficient (reg >> 4, (signed char) byte); + break; + default: + // XXX + //printf ("Write %02x to unknown APU register %02x\n", byte, reg); + break; + } + + KeyOnPrev|=KeyOn; + KeyOn=0; + + if (reg < 0x80) + APU.DSP [reg] = byte; +} + +void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2) +{ + if (adsr1 & 0x80) + { + if (S9xSetSoundMode (channel, MODE_ADSR)) + S9xSetSoundADSR (channel, adsr1 & 0xf, (adsr1 >> 4) & 7, + adsr2 & 0x1f, (adsr2 >> 5) & 7); + } + else + { + if ((gain & 0x80) == 0) + { + if (S9xSetSoundMode (channel, MODE_GAIN)) + S9xSetEnvelopeHeight (channel, (gain & 0x7f) << ENV_SHIFT); + } + else + { + if (gain & 0x40) + { + if (S9xSetSoundMode (channel, (gain & 0x20) ? + MODE_INCREASE_BENT_LINE : MODE_INCREASE_LINEAR)) + S9xSetEnvelopeRate (channel, env_counter_table[gain & 0x1f], ENV_MAX); + } + else + { + if (S9xSetSoundMode (channel, (gain & 0x20) ? + MODE_DECREASE_EXPONENTIAL : MODE_DECREASE_LINEAR)) + S9xSetEnvelopeRate (channel, env_counter_table[gain & 0x1f], 0); + } + } + } +} + +void S9xSetAPUControl (uint8 byte) +{ + //if (byte & 0x40) + //printf ("*** Special SPC700 timing enabled\n"); + if ((byte & 1) != 0 && !APU.TimerEnabled [0]) + { + APU.Timer [0] = 0; + IAPU.RAM [0xfd] = 0; + if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0) + APU.TimerTarget [0] = 0x100; + } + if ((byte & 2) != 0 && !APU.TimerEnabled [1]) + { + APU.Timer [1] = 0; + IAPU.RAM [0xfe] = 0; + if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0) + APU.TimerTarget [1] = 0x100; + } + if ((byte & 4) != 0 && !APU.TimerEnabled [2]) + { + APU.Timer [2] = 0; + IAPU.RAM [0xff] = 0; + if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0) + APU.TimerTarget [2] = 0x100; + } + APU.TimerEnabled [0] = byte & 1; + APU.TimerEnabled [1] = (byte & 2) >> 1; + APU.TimerEnabled [2] = (byte & 4) >> 2; + + if (byte & 0x10) + IAPU.RAM [0xF4] = IAPU.RAM [0xF5] = 0; + + if (byte & 0x20) + IAPU.RAM [0xF6] = IAPU.RAM [0xF7] = 0; + + if (byte & 0x80) + { + if (!APU.ShowROM) + { + memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM)); + APU.ShowROM = TRUE; + } + } + else + { + if (APU.ShowROM) + { + APU.ShowROM = FALSE; + memmove (&IAPU.RAM [0xffc0], APU.ExtraRAM, sizeof (APUROM)); + } + } + IAPU.RAM [0xf1] = byte; +} + +void S9xSetAPUTimer (uint16 Address, uint8 byte) +{ + IAPU.RAM [Address] = byte; + + switch (Address) + { + case 0xfa: + if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0) + APU.TimerTarget [0] = 0x100; + APU.TimerValueWritten [0] = TRUE; + break; + case 0xfb: + if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0) + APU.TimerTarget [1] = 0x100; + APU.TimerValueWritten [1] = TRUE; + break; + case 0xfc: + if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0) + APU.TimerTarget [2] = 0x100; + APU.TimerValueWritten [2] = TRUE; + break; + } +} + +void S9xUpdateAPUTimer (void) +{ + while ((CPU.Cycles << SNES_APUTIMER_ACCURACY) >= IAPU.NextAPUTimerPos) + { + IAPU.NextAPUTimerPos += SNES_APUTIMER2_CYCLE_SHIFT; + + if (APU.TimerEnabled [2]) + { + APU.Timer [2] ++; + if (APU.Timer [2] >= APU.TimerTarget [2]) + { + IAPU.RAM [0xff] = (IAPU.RAM [0xff] + 1) & 0xf; + APU.Timer [2] = 0; + #ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; + IAPU.APUExecuting = TRUE; + #endif + } + } + + if (++IAPU.APUTimerCounter == 8) + { + IAPU.APUTimerCounter = 0; + + if (APU.TimerEnabled [0]) + { + APU.Timer [0]++; + if (APU.Timer [0] >= APU.TimerTarget [0]) + { + IAPU.RAM [0xfd] = (IAPU.RAM [0xfd] + 1) & 0xf; + APU.Timer [0] = 0; + #ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; + IAPU.APUExecuting = TRUE; + #endif + } + } + + if (APU.TimerEnabled [1]) + { + APU.Timer [1]++; + if (APU.Timer [1] >= APU.TimerTarget [1]) + { + IAPU.RAM [0xfe] = (IAPU.RAM [0xfe] + 1) & 0xf; + APU.Timer [1] = 0; + #ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; + IAPU.APUExecuting = TRUE; + #endif + } + } + } + } +} + +uint8 S9xGetAPUDSP () +{ + uint8 reg = IAPU.RAM [0xf2] & 0x7f; + uint8 byte = APU.DSP [reg]; + + switch (reg) + { + case APU_KON: + break; + case APU_KOFF: + break; + + case APU_OUTX + 0x00: + case APU_OUTX + 0x10: + case APU_OUTX + 0x20: + case APU_OUTX + 0x30: + case APU_OUTX + 0x40: + case APU_OUTX + 0x50: + case APU_OUTX + 0x60: + case APU_OUTX + 0x70: + if (SoundData.channels [reg >> 4].state == SOUND_SILENT) + return (0); + return (int8) (SoundData.channels [reg >> 4].out_sample >> 8); + + case APU_ENVX + 0x00: + case APU_ENVX + 0x10: + case APU_ENVX + 0x20: + case APU_ENVX + 0x30: + case APU_ENVX + 0x40: + case APU_ENVX + 0x50: + case APU_ENVX + 0x60: + case APU_ENVX + 0x70: + return (S9xGetEnvelopeHeight (reg >> 4)); + + case APU_ENDX: + // To fix speech in Magical Drop 2 6/11/00 + // APU.DSP [APU_ENDX] = 0; + break; + + default: + break; + } + + return (byte); +} diff --git a/source/snes9x/apu.h b/source/snes9x/apu.h new file mode 100644 index 0000000..90b562b --- /dev/null +++ b/source/snes9x/apu.h @@ -0,0 +1,272 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _apu_h_ +#define _apu_h_ + +#include "spc700.h" + +struct SIAPU +{ + uint8 *PC; + uint8 *RAM; + uint8 *DirectPage; + bool8 APUExecuting; + uint8 Bit; + uint32 Address; + uint8 *WaitAddress1; + uint8 *WaitAddress2; + uint32 WaitCounter; + uint8 *ShadowRAM; + uint8 *CachedSamples; + uint8 _Carry; + uint8 _Zero; + uint8 _Overflow; + uint32 TimerErrorCounter; + int32 NextAPUTimerPos; + int32 APUTimerCounter; + uint32 Scanline; + int32 OneCycle; + int32 TwoCycles; +}; + +struct SAPU +{ + int32 Cycles; + bool8 ShowROM; + uint32 Flags; + uint8 KeyedChannels; + uint8 OutPorts [4]; + uint8 DSP [0x80]; + uint8 ExtraRAM [64]; + uint16 Timer [3]; + uint16 TimerTarget [3]; + bool8 TimerEnabled [3]; + bool8 TimerValueWritten [3]; +}; + +EXTERN_C struct SAPU APU; +EXTERN_C struct SIAPU IAPU; +extern int spc_is_dumping; +extern int spc_is_dumping_temp; +extern uint8 spc_dump_dsp[0x100]; +STATIC inline void S9xAPUUnpackStatus() +{ + IAPU._Zero = ((APURegisters.P & Zero) == 0) | (APURegisters.P & Negative); + IAPU._Carry = (APURegisters.P & Carry); + IAPU._Overflow = (APURegisters.P & Overflow) >> 6; +} + +STATIC inline void S9xAPUPackStatus() +{ + APURegisters.P &= ~(Zero | Negative | Carry | Overflow); + APURegisters.P |= IAPU._Carry | ((IAPU._Zero == 0) << 1) | + (IAPU._Zero & 0x80) | (IAPU._Overflow << 6); +} + +START_EXTERN_C +void S9xResetAPU (void); +bool8 S9xInitAPU (); +void S9xDeinitAPU (); +void S9xDecacheSamples (); +int S9xTraceAPU (); +int S9xAPUOPrint (char *buffer, uint16 Address); +void S9xSetAPUControl (uint8 byte); +void S9xSetAPUDSP (uint8 byte); +uint8 S9xGetAPUDSP (); +void S9xSetAPUTimer (uint16 Address, uint8 byte); +void S9xUpdateAPUTimer (void); +bool8 S9xInitSound (int quality, bool8 stereo, int buffer_size); +void S9xOpenCloseSoundTracingFile (bool8); +void S9xPrintAPUState (); +extern int32 S9xAPUCycles [256]; // Scaled cycle lengths +extern int32 S9xAPUCycleLengths [256]; // Raw data. +extern void (*S9xApuOpcodes [256]) (void); +END_EXTERN_C + + +#define APU_VOL_LEFT 0x00 +#define APU_VOL_RIGHT 0x01 +#define APU_P_LOW 0x02 +#define APU_P_HIGH 0x03 +#define APU_SRCN 0x04 +#define APU_ADSR1 0x05 +#define APU_ADSR2 0x06 +#define APU_GAIN 0x07 +#define APU_ENVX 0x08 +#define APU_OUTX 0x09 + +#define APU_MVOL_LEFT 0x0c +#define APU_MVOL_RIGHT 0x1c +#define APU_EVOL_LEFT 0x2c +#define APU_EVOL_RIGHT 0x3c +#define APU_KON 0x4c +#define APU_KOFF 0x5c +#define APU_FLG 0x6c +#define APU_ENDX 0x7c + +#define APU_EFB 0x0d +#define APU_PMON 0x2d +#define APU_NON 0x3d +#define APU_EON 0x4d +#define APU_DIR 0x5d +#define APU_ESA 0x6d +#define APU_EDL 0x7d + +#define APU_C0 0x0f +#define APU_C1 0x1f +#define APU_C2 0x2f +#define APU_C3 0x3f +#define APU_C4 0x4f +#define APU_C5 0x5f +#define APU_C6 0x6f +#define APU_C7 0x7f + +#define APU_SOFT_RESET 0x80 +#define APU_MUTE 0x40 +#define APU_ECHO_DISABLED 0x20 + +#define FREQUENCY_MASK 0x3fff +#endif + diff --git a/source/snes9x/apudebug.cpp b/source/snes9x/apudebug.cpp new file mode 100644 index 0000000..58a268a --- /dev/null +++ b/source/snes9x/apudebug.cpp @@ -0,0 +1,494 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "spc700.h" +#include "apu.h" +#include "soundux.h" +#include "cpuexec.h" + +#ifdef SPCTOOL +#include "spctool/spc700.h" +#endif + +#ifdef DEBUGGER +extern int32 env_counter_table[32]; + +FILE *apu_trace = NULL; + +static char *S9xMnemonics [256] = { + "NOP", "TCALL 0", "SET1 $%02X.0", "BBS $%02X.0,$%04X", + "OR A,$%02X", "OR A,!$%04X", "OR A,(X)", "OR A,[$%02X+X]", + "OR A,#$%02X", "OR $%02X,$%02X", "OR1 C,$%04X.%d", "ASL $%02X", + "MOV !$%04X,Y", "PUSH PSW", "TSET1 !$%04X", "BRK", + "BPL $%04X", "TCALL 1", "CLR1 $%02X.0", "BBC $%02X.0,$%04X", + "OR A,$%02X+X", "OR A,!$%04X+X", "OR A,!$%04X+Y", "OR A,[$%02X]+Y", + "OR $%02X,#$%02X", "OR (X),(Y)", "DECW $%02X", "ASL $%02X+X", + "ASL A", "DEC X", "CMP X,!$%04X", "JMP [!$%04X+X]", + "CLRP", "TCALL 2", "SET1 $%02X.1", "BBS $%02X.1,$%04X", + "AND A,$%02X", "AND A,!$%04X", "AND A,(X)", "AND A,[$%02X+X]", + "AND A,#$%02X", "AND $%02X,$%02X", "OR1 C,/$%04X.%d", "ROL $%02X", + "ROL !$%04X", "PUSH A", "CBNE $%02X,$%04X", "BRA $%04X", + "BMI $%04X", "TCALL 3", "CLR1 $%02X.1", "BBC $%02X.1,$%04X", + "AND A,$%02X+X", "AND A,!$%04X+X", "AND A,!$%04X+Y", "AND A,[$%02X]+Y", + "AND $%02X,#$%02X", "AND (X),(Y)", "INCW $%02X", "ROL $%02X+X", + "ROL A", "INC X", "CMP X,$%02X", "CALL !$%04X", + "SETP", "TCALL 4", "SET1 $%02X.2", "BBS $%02X.2,$%04X", + "EOR A,$%02X", "EOR A,!$%04X", "EOR A,(X)", "EOR A,[$%02X+X]", + "EOR A,#$%02X", "EOR $%02X,$%02X", "AND1 C,$%04X.%d", "LSR $%02X", + "LSR !$%04X", "PUSH X", "TCLR1 !$%04X", "PCALL $%02X", + "BVC $%04X", "TCALL 5", "CLR1 $%02X.2", "BBC $%02X.2,$%04X", + "EOR A,$%02X+X", "EOR A,!$%04X+X", "EOR A,!$%04X+Y", "EOR A,[$%02X]+Y", + "EOR $%02X,#$%02X", "EOR (X),(Y)", "CMPW YA,$%02X", "LSR $%02X+X", + "LSR A", "MOV X,A", "CMP Y,!$%04X", "JMP !$%04X", + "CLRC", "TCALL 6", "SET1 $%02X.3", "BBS $%02X.3,$%04X", + "CMP A,$%02X", "CMP A,!$%04X", "CMP A,(X)", "CMP A,[$%02X+X]", + "CMP A,#$%02X", "CMP $%02X,$%02X", "AND1 C,/$%04X.%d", "ROR $%02X", + "ROR !$%04X", "PUSH Y", "DBNZ $%02X,$%04X", "RET", + "BVS $%04X", "TCALL 7", "CLR1 $%02X.3", "BBC $%02X.3,$%04X", + "CMP A,$%02X+X", "CMP A,!$%04X+X", "CMP A,!$%04X+Y", "CMP A,[$%02X]+Y", + "CMP $%02X,#$%02X", "CMP (X),(Y)", "ADDW YA,$%02X", "ROR $%02X+X", + "ROR A", "MOV A,X", "CMP Y,$%02X", "RET1", + "SETC", "TCALL 8", "SET1 $%02X.4", "BBS $%02X.4,$%04X", + "ADC A,$%02X", "ADC A,!$%04X", "ADC A,(X)", "ADC A,[$%02X+X]", + "ADC A,#$%02X", "ADC $%02X,$%02X", "EOR1 C,$%04X.%d", "DEC $%02X", + "DEC !$%04X", "MOV Y,#$%02X", "POP PSW", "MOV $%02X,#$%02X", + "BCC $%04X", "TCALL 9", "CLR1 $%02X.4", "BBC $%02X.4,$%04X", + "ADC A,$%02X+X", "ADC A,!$%04X+X", "ADC A,!$%04X+Y", "ADC A,[$%02X]+Y", + "ADC $%02X,#$%02X", "ADC (X),(Y)", "SUBW YA,$%02X", "DEC $%02X+X", + "DEC A", "MOV X,SP", "DIV YA,X", "XCN A", + "EI", "TCALL 10", "SET1 $%02X.5", "BBS $%02X.5,$%04X", + "SBC A,$%02X", "SBC A,!$%04X", "SBC A,(X)", "SBC A,[$%02X+X]", + "SBC A,#$%02X", "SBC $%02X,$%02X", "MOV1 C,$%04X.%d", "INC $%02X", + "INC !$%04X", "CMP Y,#$%02X", "POP A", "MOV (X)+,A", + "BCS $%04X", "TCALL 11", "CLR1 $%02X.5", "BBC $%02X.5,$%04X", + "SBC A,$%02X+X", "SBC A,!$%04X+X", "SBC A,!$%04X+Y", "SBC A,[$%02X]+Y", + "SBC $%02X,#$%02X", "SBC (X),(Y)", "MOVW YA,$%02X", "INC $%02X+X", + "INC A", "MOV SP,X", "DAS A", "MOV A,(X)+", + "DI", "TCALL 12", "SET1 $%02X.6", "BBS $%02X.6,$%04X", + "MOV $%02X,A", "MOV !$%04X,A", "MOV (X),A", "MOV [$%02X+X],A", + "CMP X,#$%02X", "MOV !$%04X,X", "MOV1 $%04X.%d,C", "MOV $%02X,Y", + "ASL !$%04X", "MOV X,#$%02X", "POP X", "MUL YA", + "BNE $%04X", "TCALL 13", "CLR1 $%02X.6", "BBC $%02X.6,$%04X", + "MOV $%02X+X,A", "MOV !$%04X+X,A", "MOV !$%04X+Y,A", "MOV [$%02X]+Y,A", + "MOV $%02X,X", "MOV $%02X+Y,X", "MOVW $%02X,YA", "MOV $%02X+X,Y", + "DEC Y", "MOV A,Y", "CBNE $%02X+X,$%04X", "DAA A", + "CLRV", "TCALL 14", "SET1 $%02X.7", "BBS $%02X.7,$%04X", + "MOV A,$%02X", "MOV A,!$%04X", "MOV A,(X)", "MOV A,[$%02X+X]", + "MOV A,#$%02X", "MOV X,!$%04X", "NOT1 $%04X.%d", "MOV Y,$%02X", + "MOV Y,!$%04X", "NOTC", "POP Y", "SLEEP", + "BEQ $%04X", "TCALL 15", "CLR1 $%02X.7", "BBC $%02X.7,$%04X", + "MOV A,$%02X+X", "MOV A,!$%04X+X", "MOV A,!$%04X+Y", "MOV A,[$%02X]+Y", + "MOV X,$%02X", "MOV X,$%02X+Y", "MOV $%02X,$%02X", "MOV Y,$%02X+X", + "INC Y", "MOV Y,A", "DBNZ Y,$%04X", "STOP" +}; + +#undef ABS + +#define DP 0 +#define ABS 1 +#define IM 2 +#define DP2DP 3 +#define DPIM 4 +#define DPREL 5 +#define ABSBIT 6 +#define REL 7 + +static uint8 Modes [256] = { + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, IM, ABS, IM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, ABS, ABS, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, IM, DPREL, REL, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, DP, ABS, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, IM, ABS, DP, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, ABS, ABS, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, IM, DPREL, IM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, DP, IM, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, DP, IM, DPIM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, IM, IM, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, DP2DP, ABSBIT, DP, + ABS, DP, IM, IM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DPIM, IM, DP, DP, + IM, IM, IM, IM, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, ABS, ABSBIT, DP, + ABS, DP, IM, IM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DP, DP, DP, DP, + IM, IM, DPREL, IM, + IM, IM, DP, DPREL, + DP, ABS, IM, DP, + DP, ABS, ABSBIT, DP, + ABS, IM, IM, IM, + REL, IM, DP, DPREL, + DP, ABS, ABS, DP, + DP, DP, DP2DP, DP, + IM, IM, REL, IM +}; + +static uint8 ModesToBytes [] = { + 2, 3, 1, 3, 3, 3, 3, 2 +}; + +static FILE *SoundTracing = NULL; + +void S9xOpenCloseSoundTracingFile (bool8 open) +{ + if (open && !SoundTracing) + { + SoundTracing = fopen ("sound_trace.log", "w"); + } + else + if (!open && SoundTracing) + { + fclose (SoundTracing); + SoundTracing = NULL; + } +} + +void S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0, + int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0) +{ + fprintf (SoundTracing, s, i1, i2, i3, i4, i5, i6, i7); +} + +int S9xTraceAPU () +{ + char buffer [200]; + + uint8 b = S9xAPUOPrint (buffer, IAPU.PC - IAPU.RAM); + if (apu_trace == NULL) + apu_trace = fopen ("apu_trace.log", "wb"); + + fprintf (apu_trace, "%s\n", buffer); + return (b); +} + +int S9xAPUOPrint (char *buffer, uint16 Address) +{ + char mnem [100]; + uint8 *p = IAPU.RAM + Address; + int mode = Modes [*p]; + int bytes = ModesToBytes [mode]; + + switch (bytes) + { + case 1: + sprintf (buffer, "%04X %02X ", p - IAPU.RAM, *p); + break; + case 2: + sprintf (buffer, "%04X %02X %02X ", p - IAPU.RAM, *p, + *(p + 1)); + break; + case 3: + sprintf (buffer, "%04X %02X %02X %02X ", p - IAPU.RAM, *p, + *(p + 1), *(p + 2)); + break; + } + + switch (mode) + { + case DP: + sprintf (mnem, S9xMnemonics [*p], *(p + 1)); + break; + case ABS: + sprintf (mnem, S9xMnemonics [*p], *(p + 1) + (*(p + 2) << 8)); + break; + case IM: + sprintf (mnem, S9xMnemonics [*p]); + break; + case DP2DP: + sprintf (mnem, S9xMnemonics [*p], *(p + 2), *(p + 1));; + break; + case DPIM: + sprintf (mnem, S9xMnemonics [*p], *(p + 2), *(p + 1));; + break; + case DPREL: + sprintf (mnem, S9xMnemonics [*p], *(p + 1), + (int) (p + 3 - IAPU.RAM) + (signed char) *(p + 2)); + break; + case ABSBIT: + sprintf (mnem, S9xMnemonics [*p], (*(p + 1) + (*(p + 2) << 8)) & 0x1fff, + *(p + 2) >> 5); + break; + case REL: + sprintf (mnem, S9xMnemonics [*p], + (int) (p + 2 - IAPU.RAM) + (signed char) *(p + 1)); + break; + } + + sprintf (buffer, "%s %-20s A:%02X X:%02X Y:%02X S:%02X P:%c%c%c%c%c%c%c%c %03ld %04ld %04d", + buffer, mnem, + APURegisters.YA.B.A, APURegisters.X, APURegisters.YA.B.Y, + APURegisters.S, + APUCheckNegative () ? 'N' : 'n', + APUCheckOverflow () ? 'V' : 'v', + APUCheckDirectPage () ? 'P' : 'p', + APUCheckBreak () ? 'B' : 'b', + APUCheckHalfCarry () ? 'H' : 'h', + APUCheckInterrupt () ? 'I' : 'i', + APUCheckZero () ? 'Z' : 'z', + APUCheckCarry () ? 'C' : 'c', + CPU.V_Counter, + CPU.Cycles, + APU.Cycles); + + return (bytes); +} + +const char *as_binary (uint8 data) +{ + static char buf [9]; + + for (int i = 7; i >= 0; i--) + buf [7 - i] = ((data & (1 << i)) != 0) + '0'; + + buf [8] = 0; + return (buf); +} + +void S9xPrintAPUState () +{ + printf ("Master volume left: %d, right: %d\n", + SoundData.master_volume_left, SoundData.master_volume_right); + printf ("Echo: %s %s, Delay: %d Feedback: %d Left: %d Right: %d\n", + SoundData.echo_write_enabled ? "on" : "off", + as_binary (SoundData.echo_enable), + SoundData.echo_buffer_size >> 9, + SoundData.echo_feedback, SoundData.echo_volume_left, + SoundData.echo_volume_right); + + printf ("Noise: %s, Frequency: %d, Pitch mod: %s\n", as_binary (APU.DSP [APU_NON]), + env_counter_table [APU.DSP [APU_FLG] & 0x1f], + as_binary (SoundData.pitch_mod)); + extern int FilterTaps [8]; + + printf ("Filter: "); + for (int i = 0; i < 8; i++) + printf ("%03d, ", FilterTaps [i]); + printf ("\n"); + for (int J = 0; J < 8; J++) + { + register Channel *ch = &SoundData.channels[J]; + + printf ("%d: ", J); + if (ch->state == SOUND_SILENT) + { + printf ("off\n"); + } + else + if (!(so.sound_switch & (1 << J))) + printf ("muted by user using channel on/off toggle\n"); + else + { + int freq = ch->hertz; + if (APU.DSP [APU_NON] & (1 << J)) //ch->type == SOUND_NOISE) + { + freq = env_counter_table [APU.DSP [APU_FLG] & 0x1f]; + printf ("noise, "); + } + else + printf ("sample %d, ", APU.DSP [APU_SRCN + J * 0x10]); + + printf ("freq: %d", freq); + if (J > 0 && (SoundData.pitch_mod & (1 << J)) && + ch->type != SOUND_NOISE) + { + printf ("(mod), "); + } + else + printf (", "); + + printf ("left: %d, right: %d, ", + ch->volume_left, ch->volume_right); + + static char* envelope [] = + { + "silent", "attack", "decay", "sustain", "release", "gain", + "inc_lin", "inc_bent", "dec_lin", "dec_exp" + }; + printf ("%s envx: %d, target: %d, %ld", ch->state > 9 ? "???" : envelope [ch->state], + ch->envx, ch->envx_target, ch->erate); + printf ("\n"); + } + } +} +#endif + + diff --git a/source/snes9x/apumem.h b/source/snes9x/apumem.h new file mode 100644 index 0000000..158fd57 --- /dev/null +++ b/source/snes9x/apumem.h @@ -0,0 +1,303 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _apumemory_h_ +#define _apumemory_h_ + +START_EXTERN_C +extern uint8 W4; +extern uint8 APUROM[64]; +END_EXTERN_C + +INLINE uint8 S9xAPUGetByteZ (uint8 Address) +{ + if (Address >= 0xf0 && IAPU.DirectPage == IAPU.RAM) + { + if (Address >= 0xf4 && Address <= 0xf7) + { +#ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; +#endif + return (IAPU.RAM [Address]); + } + if (Address >= 0xfd) + { +#ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; +#endif + uint8 t = IAPU.RAM [Address]; + IAPU.RAM [Address] = 0; + return (t); + } + else + if (Address == 0xf3) + return (S9xGetAPUDSP ()); + + return (IAPU.RAM [Address]); + } + else + return (IAPU.DirectPage [Address]); +} + +INLINE void S9xAPUSetByteZ (uint8 byte, uint8 Address) +{ + if (Address >= 0xf0 && IAPU.DirectPage == IAPU.RAM) + { + if (Address == 0xf3) + S9xSetAPUDSP (byte); + else + if (Address >= 0xf4 && Address <= 0xf7) + APU.OutPorts [Address - 0xf4] = byte; + else + if (Address == 0xf1) + S9xSetAPUControl (byte); + else + if (Address < 0xfd) + { + IAPU.RAM [Address] = byte; + if (Address >= 0xfa) + { + if (byte == 0) + APU.TimerTarget [Address - 0xfa] = 0x100; + else + APU.TimerTarget [Address - 0xfa] = byte; + } + } + } + else + IAPU.DirectPage [Address] = byte; +} + +INLINE uint8 S9xAPUGetByte (uint32 Address) +{ + Address &= 0xffff; + + if (Address <= 0xff && Address >= 0xf0) + { + if (Address >= 0xf4 && Address <= 0xf7) + { +#ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; +#endif + return (IAPU.RAM [Address]); + } + else + if (Address == 0xf3) + return (S9xGetAPUDSP ()); + if (Address >= 0xfd) + { +#ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; +#endif + uint8 t = IAPU.RAM [Address]; + IAPU.RAM [Address] = 0; + return (t); + } + return (IAPU.RAM [Address]); + } + else + return (IAPU.RAM [Address]); +} + +INLINE void S9xAPUSetByte (uint8 byte, uint32 Address) +{ + Address &= 0xffff; + + if (Address <= 0xff && Address >= 0xf0) + { + if (Address == 0xf3) + S9xSetAPUDSP (byte); + else + if (Address >= 0xf4 && Address <= 0xf7) + APU.OutPorts [Address - 0xf4] = byte; + else + if (Address == 0xf1) + S9xSetAPUControl (byte); + else + if (Address < 0xfd) + { + IAPU.RAM [Address] = byte; + if (Address >= 0xfa) + { + if (byte == 0) + APU.TimerTarget [Address - 0xfa] = 0x100; + else + APU.TimerTarget [Address - 0xfa] = byte; + } + } + } + else + { +#if 0 +if (Address >= 0x2500 && Address <= 0x2504) +printf ("%06d %04x <- %02x\n", ICPU.Scanline, Address, byte); +if (Address == 0x26c6) +{ + extern FILE *apu_trace; + extern FILE *trace; + APU.Flags |= TRACE_FLAG; + CPU.Flags |= TRACE_FLAG; + if (apu_trace == NULL) + apu_trace = fopen ("aputrace.log", "wb"); + if (trace == NULL) + trace = fopen ("trace.log", "wb"); + printf ("TRACING SWITCHED ON\n"); +} +#endif + if (Address < 0xffc0) + IAPU.RAM [Address] = byte; + else + { + APU.ExtraRAM [Address - 0xffc0] = byte; + if (!APU.ShowROM) + IAPU.RAM [Address] = byte; + } + } +} +#endif + diff --git a/source/snes9x/bsx.cpp b/source/snes9x/bsx.cpp new file mode 100644 index 0000000..d2c00eb --- /dev/null +++ b/source/snes9x/bsx.cpp @@ -0,0 +1,1176 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +// Anonymous wrote: +// Large thanks to John Weidman for all his initial research +// Thanks to Seph3 for his modem notes + +#include + +#include "memmap.h" +#include "display.h" +#include "bsx.h" + +//#define BSX_DEBUG + +#define BIOS_SIZE 0x100000 +#define FLASH_SIZE 0x200000 +#define PSRAM_SIZE 0x80000 + +#define Map Memory.Map +#define BlockIsRAM Memory.BlockIsRAM +#define BlockIsROM Memory.BlockIsROM +#define RAM Memory.RAM +#define SRAM Memory.SRAM +#define PSRAM Memory.BSRAM +#define BIOSROM Memory.BIOSROM +#define MAP_BSX Memory.MAP_BSX +#define MAP_CPU Memory.MAP_CPU +#define MAP_PPU Memory.MAP_PPU +#define MAP_NONE Memory.MAP_NONE + +struct SBSX_RTC +{ + int hours; + int minutes; + int seconds; + int ticks; +}; + +struct SBSX_RTC BSX_RTC; + +// flash card vendor information +const uint8 flashcard[20] = +{ + 0x4D, 0x00, 0x50, 0x00, // vendor id + 0x00, 0x00, // ? + 0x2B, 0x00, // 2MB Flash (1MB = 0x2A) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8 init2192[32] = // FIXME +{ + 00, 00, 00, 00, 00, // unknown + 01, 01, 00, 00, 00, + 00, // seconds (?) + 00, // minutes + 00, // hours + 10, 10, 10, 10, 10, // unknown + 10, 10, 10, 10, 10, // dummy + 00, 00, 00, 00, 00, 00, 00, 00, 00 +}; + +bool8 FlashMode; +uint32 FlashSize; +uint8 *MapROM, *FlashROM; + +static void BSX_Map_SNES(void); +static void BSX_Map_LoROM(void); +static void BSX_Map_HiROM(void); +static void BSX_Map_MMC(void); +static void BSX_Map_FlashIO(void); +static void BSX_Map_SRAM(void); +static void BSX_Map_PSRAM(void); +static void BSX_Map_BIOS(void); +static void BSX_Map_RAM(void); +static void BSX_Map_Dirty(void); +static void BSX_Map(void); +static void BSX_Set_Bypass_FlashIO(uint16, uint8); +static uint8 BSX_Get_Bypass_FlashIO(uint16); +static bool8 BSX_LoadBIOS(void); +static void map_psram_mirror_sub(uint32); +static int is_bsx(unsigned char *); + + +static void BSX_Map_SNES(void) +{ + // These maps will be partially overwritten + + int c; + + // Banks 00->3F and 80->BF + for (c = 0; c < 0x400; c += 16) + { + Map[c + 0] = Map[c + 0x800] = RAM; + Map[c + 1] = Map[c + 0x801] = RAM; + BlockIsRAM[c + 0] = BlockIsRAM[c + 0x800] = TRUE; + BlockIsRAM[c + 1] = BlockIsRAM[c + 0x801] = TRUE; + + Map[c + 2] = Map[c + 0x802] = (uint8 *) MAP_PPU; + Map[c + 3] = Map[c + 0x803] = (uint8 *) MAP_PPU; + Map[c + 4] = Map[c + 0x804] = (uint8 *) MAP_CPU; + Map[c + 5] = Map[c + 0x805] = (uint8 *) MAP_CPU; + Map[c + 6] = Map[c + 0x806] = (uint8 *) MAP_NONE; + Map[c + 7] = Map[c + 0x807] = (uint8 *) MAP_NONE; + } +} + +static void BSX_Map_LoROM(void) +{ + // These maps will be partially overwritten + + int i, c; + + // Banks 00->3F and 80->BF + for (c = 0; c < 0x400; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; + BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; + } + } + + // Banks 40->7F and C0->FF + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize]; + + for (i = c + 8; i < c + 16; i++) + Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize] - 0x8000; + + for (i = c; i < c + 16; i++) + { + BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable; + BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable; + } + } +} + +static void BSX_Map_HiROM(void) +{ + // These maps will be partially overwritten + + int i, c; + + // Banks 00->3F and 80->BF + for (c = 0; c < 0x400; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize]; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; + BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; + } + } + + // Banks 40->7F and C0->FF + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 12) % FlashSize]; + BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable; + BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable; + } + } +} + +static void BSX_Map_MMC(void) +{ + int c; + + // Banks 01->0E:5000-5FFF + for (c = 0x010; c < 0x0F0; c += 16) + { + Map[c + 5] = (uint8 *) MAP_BSX; + BlockIsRAM[c + 5] = BlockIsROM[c + 5] = FALSE; + } +} + +static void BSX_Map_FlashIO(void) +{ + int c; + + if (BSX.MMC[0x0C] || BSX.MMC[0x0D]) + { + // Bank C0:0000, 2AAA, 5555, FF00-FF1F + for (c = 0; c < 16; c++) + { + Map[c + 0xC00] = (uint8 *) MAP_BSX; + BlockIsRAM[c + 0xC00] = TRUE; + BlockIsROM[c + 0xC00] = FALSE; + } + } +} + +static void BSX_Map_SRAM(void) +{ + int c; + + // Banks 10->17:5000-5FFF + for (c = 0x100; c < 0x180; c += 16) + { + Map[c + 5] = (uint8 *) SRAM + ((c & 0x70) << 8) - 0x5000; + BlockIsRAM[c + 5] = TRUE; + BlockIsROM[c + 5] = FALSE; + } +} + +static void map_psram_mirror_sub(uint32 bank) +{ + int i, c; + + bank <<= 4; + + if (BSX.MMC[0x02]) + { + for (c = 0; c < 0x100; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + } + else + { + for (c = 0; c < 0x100; c += 16) + { + for (i = c; i < c + 8; i++) + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE]; + + for (i = c + 8; i < c + 16; i++) + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000; + + for (i = c; i < c + 16; i++) + { + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + } +} + +static void BSX_Map_PSRAM(void) +{ + int c; + + // Banks 70->77:0000-FFFF + // FIXME: could be toggled by $03 + for (c = 0; c < 0x80; c++) + { + Map[c + 0x700] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + BlockIsRAM[c + 0x700] = TRUE; + BlockIsROM[c + 0x700] = FALSE; + } + + // Banks 20->3F:6000-7FFF mirrors 70->77:6000-7FFF + for (c = 0x200; c < 0x400; c += 16) + { + Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + BlockIsRAM[c + 6] = TRUE; + BlockIsRAM[c + 7] = TRUE; + BlockIsROM[c + 6] = FALSE; + BlockIsROM[c + 7] = FALSE; + } + + if (!BSX.MMC[0x05]) + // Banks 40->4F:0000-FFFF mirrors 70->77:0000-7FFF + map_psram_mirror_sub(0x40); + + if (!BSX.MMC[0x06]) + // Banks 50->5F:0000-FFFF mirrors 70->77:0000-7FFF + map_psram_mirror_sub(0x50); + + // FIXME + if (!BSX.MMC[0x03]) + // Banks 60->6F:0000-FFFF mirrors 70->77:0000-7FFF (?) + map_psram_mirror_sub(0x60); +} + +static void BSX_Map_BIOS(void) +{ + int i,c; + + // Banks 00->1F:8000-FFFF + if (BSX.MMC[0x07]) + { + for (c = 0; c < 0x200; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000; + BlockIsRAM[i] = FALSE; + BlockIsROM[i] = TRUE; + } + } + } + + // Banks 80->9F:8000-FFFF + if (BSX.MMC[0x08]) + { + for (c = 0; c < 0x200; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i + 0x800] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000; + BlockIsRAM[i + 0x800] = FALSE; + BlockIsROM[i + 0x800] = TRUE; + } + } + } +} + +static void BSX_Map_RAM(void) +{ + int c; + + // Banks 7E->7F + for (c = 0; c < 16; c++) + { + Map[c + 0x7E0] = RAM; + Map[c + 0x7F0] = RAM + 0x10000; + BlockIsRAM[c + 0x7E0] = TRUE; + BlockIsRAM[c + 0x7F0] = TRUE; + BlockIsROM[c + 0x7E0] = FALSE; + BlockIsROM[c + 0x7F0] = FALSE; + } +} + +static void BSX_Map_Dirty(void) +{ + // for the quick bank change + + int i, c; + + // Banks 00->1F and 80->9F:8000-FFFF + if (BSX.MMC[0x02]) + { + for (c = 0; c < 0x200; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize]; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; + BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; + } + } + } + else + { + for (c = 0; c < 0x200; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; + BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; + } + } + } +} + +static void BSX_Map(void) +{ +#ifdef BSX_DEBUG + printf("BS: Remapping\n"); + for (int i = 0; i < 32; i++) + printf("BS: MMC %02X: %d\n", i, BSX.MMC[i]); +#endif + + memcpy(BSX.prevMMC, BSX.MMC, sizeof(BSX.MMC)); + + // Do a quick bank change + if (BSX.dirty2 && !BSX.dirty) + { + BSX_Map_Dirty(); + BSX_Map_BIOS(); + + BSX.dirty2 = FALSE; + + Memory.WriteProtectROM(); + return; + } + + if (BSX.MMC[0x01]) + { + MapROM = PSRAM; + FlashSize = PSRAM_SIZE; + } + else + { + MapROM = FlashROM; + FlashSize = FLASH_SIZE; + } + + BSX_Map_SNES(); + + if (BSX.MMC[0x02]) + BSX_Map_HiROM(); + else + BSX_Map_LoROM(); + + BSX_Map_PSRAM(); + BSX_Map_SRAM(); + BSX_Map_RAM(); + + BSX_Map_BIOS(); + BSX_Map_FlashIO(); + BSX_Map_MMC(); + + // Monitor new register changes + BSX.dirty = FALSE; + BSX.dirty2 = FALSE; + + Memory.WriteProtectROM(); +} + +static uint8 BSX_Get_Bypass_FlashIO(uint16 offset) +{ + if (BSX.MMC[0x02]) + return MapROM[offset]; + else + { + if (offset < 0x8000) + return MapROM[offset]; + else + return MapROM[offset - 0x8000]; + } +} + +static void BSX_Set_Bypass_FlashIO(uint16 offset, uint8 byte) +{ + if (BSX.MMC[0x02]) + MapROM[offset] = byte; + else + { + if (offset < 0x8000) + MapROM[offset] = byte; + else + MapROM[offset - 0x8000] = byte; + } +} + +uint8 S9xGetBSX(uint32 address) +{ + uint8 bank = (address >> 16) & 0xFF; + uint16 offset = address & 0xFFFF; + uint8 t = 0; + + // MMC + if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) + return BSX.MMC[bank]; + + // Flash IO + if (bank == 0xC0) + { + // default: read-through mode + t = BSX_Get_Bypass_FlashIO(offset); + + // note: may be more registers, purposes unknown + switch (offset) + { + case 0x0002: + if (BSX.flash_enable) + t = 0x80; // status register? + break; + + case 0x5555: + if (BSX.flash_enable) + t = 0x80; // ??? + break; + + case 0xFF00: + case 0xFF02: + case 0xFF04: + case 0xFF06: + case 0xFF08: + case 0xFF0A: + case 0xFF0C: + case 0xFF0E: + case 0xFF10: + case 0xFF12: + // return flash vendor information + if (BSX.read_enable) + t = flashcard[offset - 0xFF00]; + break; + } + } + + return t; +} + +void S9xSetBSX(uint8 byte, uint32 address) +{ + uint8 bank = (address >> 16) & 0xFF; + uint16 offset = address & 0xFFFF; + + // MMC + if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) + { + switch (bank) + { + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + if (BSX.MMC[bank] != byte) + { + BSX.MMC[bank] = byte; + BSX.dirty = TRUE; + } + break; + + case 0x07: + case 0x08: + if (BSX.MMC[bank] != byte) + { + BSX.MMC[bank] = byte; + BSX.dirty2 = TRUE; + } + break; + + case 0x0E: + BSX.MMC[bank] = byte; + if (byte && (BSX.dirty || BSX.dirty2)) + BSX_Map(); + break; + } + } + + // Flash IO + if (bank == 0xC0) + { + BSX.old_write = BSX.new_write; + BSX.new_write = address; + + // ???: double writes to the desired address will bypass + // flash registers + if (BSX.old_write == BSX.new_write && BSX.write_enable) + { + BSX_Set_Bypass_FlashIO(offset, byte); + return; + } + + // flash command handling + // note: incomplete + switch (offset) + { + case 0x0000: + BSX.flash_command <<= 8; + BSX.flash_command |= byte; + if ((BSX.flash_command & 0xFFFF) == 0x38D0) + { + // retrieve information about the flash card + BSX.flash_enable = TRUE; + BSX.read_enable = TRUE; + } + break; + + case 0x2AAA: + BSX.flash_command <<= 8; + BSX.flash_command |= byte; + break; + + case 0x5555: + BSX.flash_command <<= 8; + BSX.flash_command |= byte; + + switch (BSX.flash_command & 0xFFFFFF) + { + case 0xAA55F0: + // turn off flash i/o + BSX.flash_enable = FALSE; + BSX.write_enable = FALSE; + BSX.read_enable = FALSE; + break; + + case 0xAA55A0: + // enable writing to flash + BSX.old_write = 0; + BSX.new_write = 0; + BSX.flash_enable = TRUE; + BSX.write_enable = TRUE; + BSX_Map(); + break; + + case 0xAA5570: + // turn on write-protection + BSX.write_enable = FALSE; + BSX_Map(); + break; + + case 0xAA5580: + case 0xAA5510: + // ??? + break; + + } + + break; + } + } +} + +uint8 S9xGetBSXPPU(uint16 address) +{ + uint8 t = 0; + + if (address >= 0x2188 && address <= 0x219F) + { + // known read registers + switch(address) + { + // Test register low? (r/w) + case 0x2188: + t = BSX.PPU[0x2188]; + break; + + // Test register high? (r/w) + case 0x2189: + t = BSX.PPU[0x2189]; + break; + + case 0x218A: + t = BSX.PPU[0x218A]; + break; + + case 0x218C: + t = BSX.PPU[0x218C]; + break; + + // Transmission number low? (r/w) + case 0x218E: + t = BSX.PPU[0x218E]; + break; + + // Transmission number high? (r/w) + case 0x218F: + t = BSX.PPU[0x218F]; + break; + + // Status register? (r) + case 0x2190: + t = BSX.PPU[0x2190]; + break; + + // Data register? (r/w) + case 0x2192: + t = BSX.PPU[0x2192]; + + // test + t = BSX.test2192[BSX.out_index++]; + if (BSX.out_index == 32) + BSX.out_index = 0; + + BSX_RTC.ticks++; + if (BSX_RTC.ticks >= 1000) + { + BSX_RTC.ticks = 0; + BSX_RTC.seconds++; + } + if (BSX_RTC.seconds >= 60) + { + BSX_RTC.seconds = 0; + BSX_RTC.minutes++; + } + if (BSX_RTC.minutes >= 60) + { + BSX_RTC.minutes = 0; + BSX_RTC.hours++; + } + if (BSX_RTC.hours >= 24) + BSX_RTC.hours = 0; + + BSX.test2192[10] = BSX_RTC.seconds; + BSX.test2192[11] = BSX_RTC.minutes; + BSX.test2192[12] = BSX_RTC.hours; + + break; + + // Transmission status? (r/w) + case 0x2193: + // Data ready when bits 2/3 clear? + t = BSX.PPU[0x2193] & ~0x0C; + break; + + // Reset? (r/w) + case 0x2194: + t = BSX.PPU[0x2194]; + break; + + // Unknown (r) + case 0x2196: + t = BSX.PPU[0x2196]; + break; + + // Unknown (r/w) + case 0x2197: + t = BSX.PPU[0x2197]; + break; + + // Modem protocol? (r/w) + case 0x2199: + t = BSX.PPU[0x2199]; + break; + + default: + t = OpenBus; + break; + } + } + + return t; +} + +void S9xSetBSXPPU(uint8 byte, uint16 address) +{ + if (address >= 0x2188 && address <= 0x219F) + { + // known write registers + switch(address) + { + // Test register low? (r/w) + case 0x2188: + BSX.PPU[0x2188] = byte; + break; + + // Test register high? (r/w) + case 0x2189: + BSX.PPU[0x2189] = byte; + break; + + case 0x218A: + BSX.PPU[0x218A] = byte; + break; + + case 0x218B: + BSX.PPU[0x218B] = byte; + break; + + case 0x218C: + BSX.PPU[0x218C] = byte; + break; + + // Transmission number low? (r/w) + case 0x218E: + BSX.PPU[0x218E] = byte; + break; + + // Transmission number high? (r/w) + case 0x218F: + BSX.PPU[0x218F] = byte; + + // ? + BSX.PPU[0x218E] >>= 1; + BSX.PPU[0x218E] = BSX.PPU[0x218F] - BSX.PPU[0x218E]; + BSX.PPU[0x218F] >>= 1; + + BSX.PPU[0x2190] = 0x80; // ? + break; + + // Strobe assert? (w) + case 0x2191: + BSX.PPU[0x2191] = byte; + BSX.out_index = 0; + break; + + // Data register? (r/w) + case 0x2192: + BSX.PPU[0x2192] = 0x01; // ? + BSX.PPU[0x2190] = 0x80; // ? + break; + + // Transmission status? (r/w) + case 0x2193: + BSX.PPU[0x2193] = byte; + break; + + // Reset? (r/w) + case 0x2194: + BSX.PPU[0x2194] = byte; + break; + + // Unknown (r/w) + case 0x2197: + BSX.PPU[0x2197] = byte; + break; + + // Modem protocol? (r/w) + case 0x2199: + // Lots of modem strings written here when + // connection is lost or no uplink established + BSX.PPU[0x2199] = byte; + break; + } + } +} + +uint8 * S9xGetPasePointerBSX(uint32 address) +{ + return MapROM; +} + +static bool8 BSX_LoadBIOS(void) +{ +#ifndef NGC + FILE *fp; + char path[_MAX_PATH + 1]; + bool8 r = FALSE; + + strcpy(path, S9xGetDirectory(BIOS_DIR)); + strcat(path, SLASH_STR); + strcat(path, "BS-X.bios"); + + fp = fopen(path, "rb"); + if (fp) + { + size_t size; + + size = fread((void *) BIOSROM, 1, BIOS_SIZE, fp); + fclose(fp); + if (size == BIOS_SIZE) + r = TRUE; + } + +#ifdef BSX_DEBUG + if (r) + printf("BS: BIOS found.\n"); + else + printf("BS: BIOS not found!\n"); +#endif + + return r; +#else + return false; +#endif + +} + +void S9xInitBSX(void) +{ + Settings.BS = FALSE; + + if (!memcmp(&ROM[0x7FC0], "Satellaview BS-X ", 21)) + { + // BS-X itself + + Settings.BS = TRUE; + Settings.BSXItself = TRUE; + + Memory.LoROM = TRUE; + Memory.HiROM = FALSE; + + memmove(BIOSROM, ROM, BIOS_SIZE); + + FlashMode = FALSE; + FlashSize = FLASH_SIZE; + + BSX.bootup = TRUE; + } + else + { + Settings.BSXItself = FALSE; + + int r1, r2; + + r1 = (is_bsx(ROM + 0x7FC0) == 1); + r2 = (is_bsx(ROM + 0xFFC0) == 1); + Settings.BS = (r1 | r2) ? TRUE : FALSE; + + if (Settings.BS) + { + // BS games + + Memory.LoROM = r1 ? TRUE : FALSE; + Memory.HiROM = r2 ? TRUE : FALSE; + + uint8 *header = r1 ? ROM + 0x7FC0 : ROM + 0xFFC0; + + FlashMode = (header[0x18] & 0xEF) == 0x20 ? FALSE : TRUE; + FlashSize = (header[0x19] & 0x20) ? PSRAM_SIZE : FLASH_SIZE; + +#ifdef BSX_DEBUG + for (int i = 0; i <= 0x1F; i++) + printf("BS: ROM Header %02X: %02X\n", i, header[i]); + printf("BS: FlashMode: %d, FlashSize: %x\n", FlashMode, FlashSize); +#endif + + BSX.bootup = Settings.BSXBootup; + + if (!BSX_LoadBIOS()) + { + BSX.bootup = FALSE; + memset(BIOSROM, 0, BIOS_SIZE); + } + } + } + + if (Settings.BS) + { + MapROM = NULL; + FlashROM = ROM; + + time_t t; + struct tm *tmr; + + time(&t); + tmr = localtime(&t); + + BSX_RTC.ticks = 0; + memcpy(BSX.test2192, init2192, sizeof(init2192)); + BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec; + BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min; + BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour; +#ifdef BSX_DEBUG + printf("BS: Current Time: %02d:%02d:%02d\n", BSX_RTC.hours, BSX_RTC.minutes, BSX_RTC.seconds); +#endif + SNESGameFixes.SRAMInitialValue = 0x00; + } +} + +void S9xResetBSX(void) +{ + if (Settings.BSXItself) + memset(ROM, 0, FLASH_SIZE); + + memset(BSX.PPU, 0, sizeof(BSX.PPU)); + memset(BSX.MMC, 0, sizeof(BSX.MMC)); + memset(BSX.prevMMC, 0, sizeof(BSX.prevMMC)); + + BSX.dirty = FALSE; + BSX.dirty2 = FALSE; + BSX.flash_enable = FALSE; + BSX.write_enable = FALSE; + BSX.read_enable = FALSE; + BSX.flash_command = 0; + BSX.old_write = 0; + BSX.new_write = 0; + + BSX.out_index = 0; + memset(BSX.output, 0, sizeof(BSX.output)); + + // starting from the bios + if (BSX.bootup) + BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; + else + { + BSX.MMC[0x02] = FlashMode ? 0x80: 0; + + // per bios: run from psram or flash card + if (FlashSize == PSRAM_SIZE) + { + memcpy(PSRAM, FlashROM, PSRAM_SIZE); + + BSX.MMC[0x01] = 0x80; + BSX.MMC[0x03] = 0x80; + BSX.MMC[0x04] = 0x80; + BSX.MMC[0x0C] = 0x80; + BSX.MMC[0x0D] = 0x80; + } + else + { + BSX.MMC[0x03] = 0x80; + BSX.MMC[0x05] = 0x80; + BSX.MMC[0x06] = 0x80; + } + + BSX.MMC[0x0E] = 0x80; + } + + BSX_Map(); +} + +void S9xFixBSXAfterSnapshotLoad(void) +{ + uint8 temp[16]; + bool8 pd1, pd2; + + pd1 = BSX.dirty; + pd2 = BSX.dirty2; + memcpy(temp, BSX.MMC, sizeof(BSX.MMC)); + + memcpy(BSX.MMC, BSX.prevMMC, sizeof(BSX.MMC)); + BSX_Map(); + + memcpy(BSX.MMC, temp, sizeof(BSX.MMC)); + BSX.dirty = pd1; + BSX.dirty2 = pd2; +} + +static bool valid_normal_bank(unsigned char bankbyte) +{ + switch (bankbyte) + { + case 32: case 33: case 48: case 49: + return(true); + break; + } + return(false); +} + +static int is_bsx(unsigned char *p) +{ + if ((p[26] == 0x33 || p[26] == 0xFF) && + (!p[21] || (p[21] & 131) == 128) && + valid_normal_bank(p[24])) + { + unsigned char m = p[22]; + if (!m && !p[23]) + { + return(2); + } + if ((m == 0xFF && p[23] == 0xFF) || + (!(m & 0xF) && ((m >> 4) - 1 < 12))) + { + return(1); + } + } + return(0); +} + diff --git a/source/snes9x/bsx.h b/source/snes9x/bsx.h new file mode 100644 index 0000000..34ad708 --- /dev/null +++ b/source/snes9x/bsx.h @@ -0,0 +1,178 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _BSX_H_ +#define _BSX_H_ + +struct SBSX +{ + bool8 dirty; // Changed register values + bool8 dirty2; // Changed register values + bool8 bootup; // Start in bios mapping + bool8 flash_enable; // Flash state + bool8 write_enable; // ROM write protection + bool8 read_enable; // Allow card vendor reading + uint32 flash_command; // Flash command + uint32 old_write; // Previous flash write address + uint32 new_write; // Current flash write address + uint8 out_index; + uint8 output[32]; + uint8 PPU[32]; + uint8 MMC[16]; + uint8 prevMMC[16]; + uint8 test2192[32]; +}; + +extern struct SBSX BSX; + +uint8 S9xGetBSX(uint32); +void S9xSetBSX(uint8, uint32); +uint8 S9xGetBSXPPU(uint16); +void S9xSetBSXPPU(uint8, uint16); +uint8 * S9xGetPasePointerBSX(uint32); +void S9xInitBSX(void); +void S9xResetBSX(void); +void S9xFixBSXAfterSnapshotLoad(void); + +#endif diff --git a/source/snes9x/c4.cpp b/source/snes9x/c4.cpp new file mode 100644 index 0000000..312f94c --- /dev/null +++ b/source/snes9x/c4.cpp @@ -0,0 +1,301 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include +#include "c4.h" +#include "memmap.h" +extern "C" { + +short C4WFXVal; +short C4WFYVal; +short C4WFZVal; +short C4WFX2Val; +short C4WFY2Val; +short C4WFDist; +short C4WFScale; + +static double tanval; +static double c4x, c4y, c4z; +static double c4x2, c4y2, c4z2; + +void C4TransfWireFrame () +{ + c4x = (double) C4WFXVal; + c4y = (double) C4WFYVal; + c4z = (double) C4WFZVal - 0x95; + + // Rotate X + tanval = -(double) C4WFX2Val * 3.14159265 * 2 / 128; + c4y2 = c4y * cos (tanval) - c4z * sin (tanval); + c4z2 = c4y * sin (tanval) + c4z * cos (tanval); + + // Rotate Y + tanval = -(double)C4WFY2Val*3.14159265*2/128; + c4x2 = c4x * cos (tanval) + c4z2 * sin (tanval); + c4z = c4x * - sin (tanval) + c4z2 * cos (tanval); + + // Rotate Z + tanval = -(double) C4WFDist * 3.14159265*2 / 128; + c4x = c4x2 * cos (tanval) - c4y2 * sin (tanval); + c4y = c4x2 * sin (tanval) + c4y2 * cos (tanval); + + // Scale + C4WFXVal = (short) (c4x*(double)C4WFScale/(0x90*(c4z+0x95))*0x95); + C4WFYVal = (short) (c4y*(double)C4WFScale/(0x90*(c4z+0x95))*0x95); +} + +void C4TransfWireFrame2 () +{ + c4x = (double)C4WFXVal; + c4y = (double)C4WFYVal; + c4z = (double)C4WFZVal; + + // Rotate X + tanval = -(double) C4WFX2Val * 3.14159265 * 2 / 128; + c4y2 = c4y * cos (tanval) - c4z * sin (tanval); + c4z2 = c4y * sin (tanval) + c4z * cos (tanval); + + // Rotate Y + tanval = -(double) C4WFY2Val * 3.14159265 * 2 / 128; + c4x2 = c4x * cos (tanval) + c4z2 * sin (tanval); + c4z = c4x * -sin (tanval) + c4z2 * cos (tanval); + + // Rotate Z + tanval = -(double)C4WFDist * 3.14159265 * 2 / 128; + c4x = c4x2 * cos (tanval) - c4y2 * sin (tanval); + c4y = c4x2 * sin (tanval) + c4y2 * cos (tanval); + + // Scale + C4WFXVal =(short)(c4x * (double)C4WFScale / 0x100); + C4WFYVal =(short)(c4y * (double)C4WFScale / 0x100); +} + +void C4CalcWireFrame () +{ + C4WFXVal = C4WFX2Val - C4WFXVal; + C4WFYVal = C4WFY2Val - C4WFYVal; + if (abs (C4WFXVal) > abs (C4WFYVal)) + { + C4WFDist = abs (C4WFXVal) + 1; + C4WFYVal = (short) (256 * (double) C4WFYVal / abs (C4WFXVal)); + if (C4WFXVal < 0) + C4WFXVal = -256; + else + C4WFXVal = 256; + } + else + { + if (C4WFYVal != 0) + { + C4WFDist = abs(C4WFYVal)+1; + C4WFXVal = (short) (256 * (double)C4WFXVal / abs (C4WFYVal)); + if (C4WFYVal < 0) + C4WFYVal = -256; + else + C4WFYVal = 256; + } + else + C4WFDist = 0; + } +} + +short C41FXVal; +short C41FYVal; +short C41FAngleRes; +short C41FDist; +short C41FDistVal; + +void C4Op1F () +{ + if (C41FXVal == 0) + { + if (C41FYVal > 0) + C41FAngleRes = 0x80; + else + C41FAngleRes = 0x180; + } + else + { + tanval = (double) C41FYVal / C41FXVal; + C41FAngleRes = (short) (atan (tanval) / (3.141592675 * 2) * 512); + C41FAngleRes = C41FAngleRes; + if (C41FXVal< 0) + C41FAngleRes += 0x100; + C41FAngleRes &= 0x1FF; + } +} + +void C4Op15() +{ + tanval = sqrt ((double) C41FYVal * C41FYVal + (double) C41FXVal * C41FXVal); + C41FDist = (short) tanval; +} + +void C4Op0D() +{ + tanval = sqrt ((double) C41FYVal * C41FYVal + (double) C41FXVal * C41FXVal); + tanval = C41FDistVal / tanval; + C41FYVal = (short) (C41FYVal * tanval * 0.99); + C41FXVal = (short) (C41FXVal * tanval * 0.98); +} + +#ifdef ZSNES_C4 +EXTERN_C void C4LoaDMem(char *C4RAM) +{ + memmove(C4RAM+(READ_WORD(C4RAM+0x1f45)&0x1fff), + C4GetMemPointer(READ_3WORD(C4RAM+0x1f40)), + READ_WORD(C4RAM+0x1f43)); +} +#endif + +uint8 *S9xGetBasePointerC4 (uint16 Address) +{ + if((Address&~MEMMAP_MASK)>=(0x7f40&~MEMMAP_MASK) && + (Address&~MEMMAP_MASK)<=(0x7f5e&~MEMMAP_MASK)){ + return NULL; + } + return Memory.C4RAM-0x6000; +} + +}//end extern C diff --git a/source/snes9x/c4.h b/source/snes9x/c4.h new file mode 100644 index 0000000..f8349e1 --- /dev/null +++ b/source/snes9x/c4.h @@ -0,0 +1,184 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _C4_H_ +#define _C4_H_ + +#include "port.h" +#include "memmap.h" + +extern "C" { + +extern int16 C4WFXVal; +extern int16 C4WFYVal; +extern int16 C4WFZVal; +extern int16 C4WFX2Val; +extern int16 C4WFY2Val; +extern int16 C4WFDist; +extern int16 C4WFScale; + +void C4TransfWireFrame(); +void C4TransfWireFrame2(); +void C4CalcWireFrame(); + +extern int16 C41FXVal; +extern int16 C41FYVal; +extern int16 C41FAngleRes; +extern int16 C41FDist; +extern int16 C41FDistVal; + +void C4Op1F(); +void C4Op15(); +void C4Op0D(); + +extern int16 C4CosTable[]; +extern int16 C4SinTable[]; + +} + +static inline uint8 *C4GetMemPointer(uint32 Address){ + return (Memory.ROM + ((Address&0xff0000)>>1) + (Address&0x7fff)); +} + +#endif + diff --git a/source/snes9x/c4emu.cpp b/source/snes9x/c4emu.cpp new file mode 100644 index 0000000..8af64ae --- /dev/null +++ b/source/snes9x/c4emu.cpp @@ -0,0 +1,1070 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifdef HAVE_CONFIG_H + #include +#endif +#include +#include "snes9x.h" +#include "sar.h" +#include "memmap.h" +#include "ppu.h" +#include "c4.h" + +void S9xInitC4 () +{ + // Stupid zsnes code, we can't do the logical thing without breaking + // savestates +// Memory.C4RAM = &Memory.FillRAM [0x6000]; + memset(Memory.C4RAM, 0, 0x2000); +} + +uint8 S9xGetC4 (uint16 Address) +{ + if(Address==0x7f5e) return 0; + return (Memory.C4RAM [Address-0x6000]); +} + +static uint8 C4TestPattern [12 * 4] = +{ + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, + 0x80, 0xff, 0xff, 0x7f, + 0x00, 0x80, 0x00, 0xff, + 0x7f, 0x00, 0xff, 0x7f, + 0xff, 0x7f, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xff, + 0xff, 0xfe, 0x00, 0x01, + 0x00, 0xff, 0xfe, 0x00 +}; + + +static void C4ConvOAM(void){ + uint8 *OAMptr=Memory.C4RAM+(Memory.C4RAM[0x626]<<2); + for(uint8 *i=Memory.C4RAM+0x1fd; i>OAMptr; i-=4){ + // Clear OAM-to-be + *i=0xe0; + } + + uint16 globalX, globalY; + uint8 *OAMptr2; + int16 SprX, SprY; + uint8 SprName, SprAttr; + uint8 SprCount; + + globalX=READ_WORD(Memory.C4RAM+0x0621); + globalY=READ_WORD(Memory.C4RAM+0x0623); + OAMptr2=Memory.C4RAM+0x200+(Memory.C4RAM[0x626]>>2); + +#ifdef DEBUGGER + if(Memory.C4RAM[0x625]!=0) printf("$6625=%02x, expected 00\n", Memory.C4RAM[0x625]); + if((Memory.C4RAM[0x626]>>2)!=Memory.C4RAM[0x629]) printf("$6629=%02x, expected %02x\n", Memory.C4RAM[0x629], (Memory.C4RAM[0x626]>>2)); + if(((uint16)Memory.C4RAM[0x626]<<2)!=READ_WORD(Memory.C4RAM+0x627)) printf("$6627=%04x, expected %04x\n", READ_WORD(Memory.C4RAM+0x627), ((uint16)Memory.C4RAM[0x626]<<2)); +#endif + + if(Memory.C4RAM[0x0620]!=0){ + SprCount=128-Memory.C4RAM[0x626]; + uint8 offset=(Memory.C4RAM[0x626]&3)*2; + for(int prio=0x30; prio>=0; prio-=0x10){ + uint8 *srcptr=Memory.C4RAM+0x220; + for(int i=Memory.C4RAM[0x0620]; i>0 && SprCount>0; i--, srcptr+=16){ + if((srcptr[4]&0x30)!=prio) continue; + SprX=READ_WORD(srcptr)-globalX; + SprY=READ_WORD(srcptr+2)-globalY; + SprName=srcptr[5]; + SprAttr=srcptr[4] | srcptr[0x06]; // XXX: mask bits? + + uint8 *sprptr=C4GetMemPointer(READ_3WORD(srcptr+7)); + if(*sprptr!=0){ + int16 X, Y; + for(int SprCnt=*sprptr++; SprCnt>0 && SprCount>0; SprCnt--, sprptr+=4){ + X=(int8)sprptr[1]; + if(SprAttr&0x40){ // flip X + X=-X-((sprptr[0]&0x20)?16:8); + } + X+=SprX; + if(X>=-16 && X<=272){ + Y=(int8)sprptr[2]; + if(SprAttr&0x80){ + Y=-Y-((sprptr[0]&0x20)?16:8); + } + Y+=SprY; + if(Y>=-16 && Y<=224){ + OAMptr[0]=X&0xff; + OAMptr[1]=(uint8)Y; + OAMptr[2]=SprName+sprptr[3]; + OAMptr[3]=SprAttr^(sprptr[0]&0xc0); // XXX: Carry from SprName addition? + *OAMptr2 &= ~(3<0){ + OAMptr[0]=(uint8)SprX; + OAMptr[1]=(uint8)SprY; + OAMptr[2]=SprName; + OAMptr[3]=SprAttr; + *OAMptr2 &= ~(3<>12)>=w || (Y>>12)>=h){ + byte=0; + } else { + uint32 addr=(Y>>12)*w+(X>>12); + byte=Memory.C4RAM[0x600+(addr>>1)]; + if(addr&1) byte>>=4; + } + + // De-bitplanify + if(byte&1) Memory.C4RAM[outidx]|=bit; + if(byte&2) Memory.C4RAM[outidx+1]|=bit; + if(byte&4) Memory.C4RAM[outidx+16]|=bit; + if(byte&8) Memory.C4RAM[outidx+17]|=bit; + + bit>>=1; + if(bit==0){ + bit=0x80; + outidx+=32; + } + + X+=A; // Add 1 to output x => add an A and a C + Y+=C; + } + outidx+=2+row_padding; + if(outidx&0x10){ + outidx&=~0x10; + } else { + outidx-=w*4+row_padding; + } + LineX+=B; // Add 1 to output y => add a B and a D + LineY+=D; + } +} + +static void C4DrawLine(int32 X1, int32 Y1, int16 Z1, + int32 X2, int32 Y2, int16 Z2, uint8 Color){ + // Transform coordinates + C4WFXVal=(short)X1; + C4WFYVal=(short)Y1; + C4WFZVal=Z1; + C4WFScale=Memory.C4RAM[0x1f90]; + C4WFX2Val=Memory.C4RAM[0x1f86]; + C4WFY2Val=Memory.C4RAM[0x1f87]; + C4WFDist=Memory.C4RAM[0x1f88]; + C4TransfWireFrame2(); + X1=(C4WFXVal+48)<<8; + Y1=(C4WFYVal+48)<<8; + + C4WFXVal=(short)X2; + C4WFYVal=(short)Y2; + C4WFZVal=Z2; + C4TransfWireFrame2(); + X2=(C4WFXVal+48)<<8; + Y2=(C4WFYVal+48)<<8; + + // get line info + C4WFXVal=(short)(X1>>8); + C4WFYVal=(short)(Y1>>8); + C4WFX2Val=(short)(X2>>8); + C4WFY2Val=(short)(Y2>>8); + C4CalcWireFrame(); + X2=(int16)C4WFXVal; + Y2=(int16)C4WFYVal; + + // render line + for(int i=C4WFDist?C4WFDist:1; i>0; i--) + { //.loop + if(X1>0xff && Y1>0xff && X1<0x6000 && Y1<0x6000) + { + uint16 addr=((X1&~0x7ff) + (Y1&~0x7ff)*12 + (Y1&0x700))>>7; + addr=(((Y1>>8)>>3)<<8)-(((Y1>>8)>>3)<<6)+(((X1>>8)>>3)<<4)+((Y1>>8)&7)*2; + uint8 bit=0x80>>((X1>>8)&7); + Memory.C4RAM[addr+0x300]&=~bit; + Memory.C4RAM[addr+0x301]&=~bit; + if(Color&1) Memory.C4RAM[addr+0x300]|=bit; + if(Color&2) Memory.C4RAM[addr+0x301]|=bit; + } + X1+=X2; + Y1+=Y2; + } +} + +static void C4DrawWireFrame(void) +{ + uint8 *line=C4GetMemPointer(READ_3WORD(Memory.C4RAM+0x1f80)); + uint8 *point1, *point2; + int16 X1, Y1, Z1; + int16 X2, Y2, Z2; + uint8 Color; + +#ifdef DEBUGGER + if(READ_3WORD(Memory.C4RAM+0x1f8f)&0xff00ff) printf("wireframe: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8f)); + if(READ_3WORD(Memory.C4RAM+0x1fa4)!=0x001000) printf("wireframe: Unexpected value in $7fa4: %06x\n", READ_3WORD(Memory.C4RAM+0x1fa4)); +#endif + + for(int i=Memory.C4RAM[0x0295]; i>0; i--, line+=5){ + if(line[0]==0xff && line[1]==0xff){ + uint8 *tmp=line-5; + while(tmp[2]==0xff && tmp[3]==0xff) tmp-=5; + point1=C4GetMemPointer((Memory.C4RAM[0x1f82]<<16) | (tmp[2]<<8) | tmp[3]); + } else { + point1=C4GetMemPointer((Memory.C4RAM[0x1f82]<<16) | (line[0]<<8) | line[1]); + } + point2=C4GetMemPointer((Memory.C4RAM[0x1f82]<<16) | (line[2]<<8) | line[3]); + + X1=(point1[0]<<8) | point1[1]; + Y1=(point1[2]<<8) | point1[3]; + Z1=(point1[4]<<8) | point1[5]; + X2=(point2[0]<<8) | point2[1]; + Y2=(point2[2]<<8) | point2[3]; + Z2=(point2[4]<<8) | point2[5]; + Color=line[4]; + C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); + } +} + +static void C4TransformLines(void){ + C4WFX2Val=Memory.C4RAM[0x1f83]; + C4WFY2Val=Memory.C4RAM[0x1f86]; + C4WFDist=Memory.C4RAM[0x1f89]; + C4WFScale=Memory.C4RAM[0x1f8c]; + +#ifdef DEBUGGER + if(Memory.C4RAM[0x1f8a]!=0x90) printf("lines: $7f8a = %02x, expected 90\n", READ_WORD(Memory.C4RAM+0x1f8a)); +#endif + + // transform vertices + uint8 *ptr=Memory.C4RAM; + { + for(int i=READ_WORD(Memory.C4RAM+0x1f80); i>0; i--, ptr+=0x10) + { + C4WFXVal=READ_WORD(ptr+1); + C4WFYVal=READ_WORD(ptr+5); + C4WFZVal=READ_WORD(ptr+9); + C4TransfWireFrame(); + + // displace + WRITE_WORD(ptr+1, C4WFXVal+0x80); + WRITE_WORD(ptr+5, C4WFYVal+0x50); + } + } + WRITE_WORD(Memory.C4RAM+0x600, 23); + WRITE_WORD(Memory.C4RAM+0x602, 0x60); + WRITE_WORD(Memory.C4RAM+0x605, 0x40); + WRITE_WORD(Memory.C4RAM+0x600+8, 23); + WRITE_WORD(Memory.C4RAM+0x602+8, 0x60); + WRITE_WORD(Memory.C4RAM+0x605+8, 0x40); + + ptr=Memory.C4RAM+0xb02; + uint8 *ptr2=Memory.C4RAM; + { + for(int i=READ_WORD(Memory.C4RAM+0xb00); i>0; i--, ptr+=2, ptr2+=8) + { + C4WFXVal=READ_WORD(Memory.C4RAM+(ptr[0]<<4)+1); + C4WFYVal=READ_WORD(Memory.C4RAM+(ptr[0]<<4)+5); + C4WFX2Val=READ_WORD(Memory.C4RAM+(ptr[1]<<4)+1); + C4WFY2Val=READ_WORD(Memory.C4RAM+(ptr[1]<<4)+5); + C4CalcWireFrame(); + WRITE_WORD(ptr2+0x600, C4WFDist?C4WFDist:1); + WRITE_WORD(ptr2+0x602, C4WFXVal); + WRITE_WORD(ptr2+0x605, C4WFYVal); + } + } +} +static void C4BitPlaneWave(){ + static uint16 bmpdata[]={ + 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E, + 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, 0x020E, + 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E, + 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060A, 0x060C, 0x060E, + 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080A, 0x080C, 0x080E + }; + + uint8 *dst=Memory.C4RAM; + uint32 waveptr=Memory.C4RAM[0x1f83]; + uint16 mask1=0xc0c0; + uint16 mask2=0x3f3f; + +#ifdef DEBUGGER + if(READ_3WORD(Memory.C4RAM+0x1f80) != Memory.C4RAM[waveptr+0xb00]) printf("$7f80=%06x, expected %02x\n", READ_3WORD(Memory.C4RAM+0x1f80), Memory.C4RAM[waveptr+0xb00]); +#endif + + for(int j=0; j<0x10; j++){ + do { + int16 height=-((int8)Memory.C4RAM[waveptr+0xb00])-16; + for(int i=0; i<40; i++){ + uint16 tmp=READ_WORD(dst+bmpdata[i]) & mask2; + if(height>=0){ + if(height<8){ + tmp|=mask1&READ_WORD(Memory.C4RAM+0xa00+height*2); + } else { + tmp|=mask1&0xff00; + } + } + WRITE_WORD(dst+bmpdata[i], tmp); + height++; + } + waveptr=(waveptr+1)&0x7f; + mask1=(mask1>>2)|(mask1<<6); + mask2=(mask2>>2)|(mask2<<6); + } while(mask1!=0xc0c0); + dst+=16; + + do { + int16 height=-((int8)Memory.C4RAM[waveptr+0xb00])-16; + for(int i=0; i<40; i++){ + uint16 tmp=READ_WORD(dst+bmpdata[i]) & mask2; + if(height>=0){ + if(height<8){ + tmp|=mask1&READ_WORD(Memory.C4RAM+0xa10+height*2); + } else { + tmp|=mask1&0xff00; + } + } + WRITE_WORD(dst+bmpdata[i], tmp); + height++; + } + waveptr=(waveptr+1)&0x7f; + mask1=(mask1>>2)|(mask1<<6); + mask2=(mask2>>2)|(mask2<<6); + } while(mask1!=0xc0c0); + dst+=16; + } +} + +static void C4SprDisintegrate() +{ + uint8 width, height; + uint32 StartX, StartY; + uint8 *src; + int32 scaleX, scaleY; + int32 Cx, Cy; + + width=Memory.C4RAM[0x1f89]; + height=Memory.C4RAM[0x1f8c]; + Cx=(int16)READ_WORD(Memory.C4RAM+0x1f80); + Cy=(int16)READ_WORD(Memory.C4RAM+0x1f83); + +#ifdef DEBUGGER + if((Cx&~1)!=width/2 || (Cy&~1)!=height/2) printf("Center is not middle of image for disintegrate! (%d, %d) != (%d, %d)\n", Cx, Cy, width/2, height/2); +#endif + + scaleX=(int16)READ_WORD(Memory.C4RAM+0x1f86); + scaleY=(int16)READ_WORD(Memory.C4RAM+0x1f8f); + StartX=-Cx*scaleX+(Cx<<8); + StartY=-Cy*scaleY+(Cy<<8); + src=Memory.C4RAM+0x600; + + memset(Memory.C4RAM, 0, width*height/2); + + for(uint32 y=StartY, i=0; i>8)>8)>8)*width+(x>>8)<0x2000) + { + uint8 pixel=(j&1)?(*src>>4):*src; + int idx=(y>>11)*width*4+(x>>11)*32+((y>>8)&7)*2; + uint8 mask=0x80>>((x>>8)&7); + if(pixel&1) Memory.C4RAM[idx]|=mask; + if(pixel&2) Memory.C4RAM[idx+1]|=mask; + if(pixel&4) Memory.C4RAM[idx+16]|=mask; + if(pixel&8) Memory.C4RAM[idx+17]|=mask; + } + if(j&1) src++; + } + } +} + +static void S9xC4ProcessSprites() +{ + switch(Memory.C4RAM[0x1f4d]) + { + case 0x00: // Build OAM +#ifdef DEBUGGER +// printf("00 00 Build OAM!\n"); +#endif + C4ConvOAM(); + break; + + case 0x03: // Scale/Rotate +#ifdef DEBUGGER +// printf("00 03 Scale/Rotate!\n"); +#endif + C4DoScaleRotate(0); + break; + + case 0x05: // Transform Lines +#ifdef DEBUGGER +// printf("00 05 Transform Lines!\n"); +#endif + C4TransformLines(); + break; + + case 0x07: // Scale/Rotate +#ifdef DEBUGGER +// printf("00 07 Scale/Rotate!\n"); +#endif + C4DoScaleRotate(64); + break; + + case 0x08: // Draw wireframe +#ifdef DEBUGGER +// printf("00 08 Draw wireframe!\n"); +#endif + C4DrawWireFrame(); + break; + + case 0x0b: // Disintegrate +#ifdef DEBUGGER + printf("00 0b Disintegrate!\n"); +#endif + C4SprDisintegrate(); + break; + + case 0x0c: // Wave +#ifdef DEBUGGER +// printf("00 0b Wave!\n"); +#endif + C4BitPlaneWave(); + break; + + default: +#ifdef DEBUGGER + printf ("Unknown C4 sprite command (%02x)\n", Memory.C4RAM [0x1f4d]); +#endif + break; + } +} + +void S9xSetC4 (uint8 byte, uint16 Address) +{ + int i; + + Memory.C4RAM [Address-0x6000] = byte; + if (Address == 0x7f4f) + { + if(Memory.C4RAM[0x1f4d]==0x0e && byte<0x40 && (byte&3)==0) + { +#ifdef DEBUGGER + printf("Test command %02x 0e used!\n", byte); +#endif + Memory.C4RAM[0x1f80]=byte>>2; + } + else + { + switch (byte) + { + case 0x00: // Sprite + S9xC4ProcessSprites(); + break; + + case 0x01: // Draw wireframe +#ifdef DEBUGGER + //printf("01 Draw wireframe used!\n"); + if(Memory.C4RAM[0x1f4d]!=8) printf("$7f4d=%02x, expected 08 for command 01 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + memset(Memory.C4RAM+0x300, 0, 16*12*3*4); + C4DrawWireFrame(); + break; + + case 0x05: // Propulsion (?) +#ifdef DEBUGGER + printf("05 Propulsion (?)!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 05 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + int32 tmp=0x10000; + if(READ_WORD(Memory.C4RAM+0x1f83)){ + tmp=SAR((tmp/READ_WORD(Memory.C4RAM+0x1f83))*READ_WORD(Memory.C4RAM+0x1f81), 8); + } + WRITE_WORD(Memory.C4RAM+0x1f80, (uint16)tmp); + } + break; + + case 0x0d: // Set vector length +#ifdef DEBUGGER + printf("0d Set vector length!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 0d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + C41FXVal=READ_WORD(Memory.C4RAM+0x1f80); + C41FYVal=READ_WORD(Memory.C4RAM+0x1f83); + C41FDistVal=READ_WORD(Memory.C4RAM+0x1f86); + C4Op0D(); + WRITE_WORD(Memory.C4RAM+0x1f89, C41FXVal); + WRITE_WORD(Memory.C4RAM+0x1f8c, C41FYVal); + break; + + case 0x10: // Polar to rectangluar +#ifdef DEBUGGER +// printf("10 Polar->Rect!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 10 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + int32 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 16); + WRITE_3WORD(Memory.C4RAM+0x1f86, tmp); + tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 16); + WRITE_3WORD(Memory.C4RAM+0x1f89, (tmp-SAR(tmp, 6))); + } + break; + + case 0x13: // Polar to rectangluar +#ifdef DEBUGGER +// printf("13 Polar->Rect!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 13 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + int32 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 8); + WRITE_3WORD(Memory.C4RAM+0x1f86, tmp); + tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 8); + WRITE_3WORD(Memory.C4RAM+0x1f89, tmp); + } + break; + + case 0x15: // Pythagorean +#ifdef DEBUGGER + printf("15 Pythagorean!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 15 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + C41FXVal=READ_WORD(Memory.C4RAM+0x1f80); + C41FYVal=READ_WORD(Memory.C4RAM+0x1f83); + C41FDist=(int16)sqrt((double)C41FXVal*C41FXVal + (double)C41FYVal*C41FYVal); + WRITE_WORD(Memory.C4RAM+0x1f80, C41FDist); + break; + + case 0x1f: // atan +#ifdef DEBUGGER +// printf("1f atan!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 1f %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + C41FXVal=READ_WORD(Memory.C4RAM+0x1f80); + C41FYVal=READ_WORD(Memory.C4RAM+0x1f83); + C4Op1F(); + WRITE_WORD(Memory.C4RAM+0x1f86, C41FAngleRes); + break; + + case 0x22: // Trapezoid + { +#ifdef DEBUGGER +// printf("22 Trapezoid!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 22 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + int16 angle1=READ_WORD(Memory.C4RAM+0x1f8c)&0x1ff; + int16 angle2=READ_WORD(Memory.C4RAM+0x1f8f)&0x1ff; +#ifdef DEBUGGER + if(C4CosTable[angle1]==0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle1=%d\n", angle1); + if(C4CosTable[angle2]==0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle2=%d\n", angle2); +#endif + int32 tan1=(C4CosTable[angle1]!=0)?((((int32)C4SinTable[angle1])<<16)/C4CosTable[angle1]):0x80000000; + int32 tan2=(C4CosTable[angle2]!=0)?((((int32)C4SinTable[angle2])<<16)/C4CosTable[angle2]):0x80000000; + int16 y = READ_WORD(Memory.C4RAM+0x1f83) - READ_WORD(Memory.C4RAM+0x1f89); + int16 left, right; + for(int j=0; j<225; j++) + { + if(y>=0) + { + left = SAR((int32)tan1*y, 16) - + READ_WORD(Memory.C4RAM+0x1f80) + + READ_WORD(Memory.C4RAM+0x1f86); + right = SAR((int32)tan2*y, 16) - + READ_WORD(Memory.C4RAM+0x1f80) + + READ_WORD(Memory.C4RAM+0x1f86) + + READ_WORD(Memory.C4RAM+0x1f93); + + if(left<0 && right<0){ + left=1; + right=0; + } else if(left<0){ + left=0; + } else if(right<0){ + right=0; + } + if(left>255 && right>255){ + left=255; + right=254; + } else if(left>255){ + left=255; + } else if(right>255){ + right=255; + } + } + else + { + left=1; + right=0; + } + Memory.C4RAM[j+0x800] = (uint8)left; + Memory.C4RAM[j+0x900] = (uint8)right; + y++; + } + } + break; + + case 0x25: // Multiply +#ifdef DEBUGGER + printf("25 Multiply!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 25 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + int32 foo=READ_3WORD(Memory.C4RAM+0x1f80); + int32 bar=READ_3WORD(Memory.C4RAM+0x1f83); + foo*=bar; + WRITE_3WORD(Memory.C4RAM+0x1f80, foo); + } + break; + + case 0x2d: // Transform Coords +#ifdef DEBUGGER +// printf("2d Transform Coords!\n"); + if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 2d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); + if(READ_3WORD(Memory.C4RAM+0x1f8f)&0xff00ff) printf("2d transform coords: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8f)); + if(READ_3WORD(Memory.C4RAM+0x1f8c)!=0x001000) printf("0d transform coords: Unexpected value in $7f8c: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8c)); +#endif + C4WFXVal=READ_WORD(Memory.C4RAM+0x1f81); + C4WFYVal=READ_WORD(Memory.C4RAM+0x1f84); + C4WFZVal=READ_WORD(Memory.C4RAM+0x1f87); + C4WFX2Val=Memory.C4RAM[0x1f89]; + C4WFY2Val=Memory.C4RAM[0x1f8a]; + C4WFDist=Memory.C4RAM[0x1f8b]; + C4WFScale=READ_WORD(Memory.C4RAM+0x1f90); + C4TransfWireFrame2(); + WRITE_WORD(Memory.C4RAM+0x1f80, C4WFXVal); + WRITE_WORD(Memory.C4RAM+0x1f83, C4WFYVal); + break; + + case 0x40: // Sum +#ifdef DEBUGGER + printf("40 Sum!\n"); + if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 40 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + uint16 sum=0; + for(int i=0; i<0x800; sum+=Memory.C4RAM[i++]); + WRITE_WORD(Memory.C4RAM+0x1f80, sum); + } + break; + + case 0x54: // Square +#ifdef DEBUGGER + printf("54 Square!\n"); + if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 54 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + { + int64 a=SAR((int64)READ_3WORD(Memory.C4RAM+0x1f80)<<40, 40); + // printf("%08X%08X\n", (uint32)(a>>32), (uint32)(a&0xFFFFFFFF)); + a*=a; + // printf("%08X%08X\n", (uint32)(a>>32), (uint32)(a&0xFFFFFFFF)); + WRITE_3WORD(Memory.C4RAM+0x1f83, a); + WRITE_3WORD(Memory.C4RAM+0x1f86, (a>>24)); + } + break; + + case 0x5c: // Immediate Reg +#ifdef DEBUGGER + printf("5c Immediate Reg!\n"); + if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 5c %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + for (i = 0; i < 12 * 4; i++) + Memory.C4RAM [i] = C4TestPattern [i]; + break; + + case 0x89: // Immediate ROM +#ifdef DEBUGGER + printf("89 Immediate ROM!\n"); + if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 89 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]); +#endif + Memory.C4RAM [0x1f80] = 0x36; + Memory.C4RAM [0x1f81] = 0x43; + Memory.C4RAM [0x1f82] = 0x05; + break; + + default: +#ifdef DEBUGGER + printf ("Unknown C4 command (%02x)\n", byte); +#endif + break; + } + } + } else if (Address == 0x7f47) { +#ifdef DEBUGGER +// printf("C4 load memory %06x => %04x, %04x bytes\n", READ_3WORD(Memory.C4RAM+0x1f40), READ_WORD(Memory.C4RAM+0x1f45), READ_WORD(Memory.C4RAM+0x1f43)); + if(byte != 0) printf("C4 load: non-0 written to $7f47! Wrote %02x\n", byte); + if(READ_WORD(Memory.C4RAM+0x1f45) < 0x6000 || (READ_WORD(Memory.C4RAM+0x1f45) + READ_WORD(Memory.C4RAM+0x1f43)) > 0x6c00) printf("C4 load: Dest unusual! It's %04x\n", READ_WORD(Memory.C4RAM+0x1f45)); +#endif + memmove(Memory.C4RAM+(READ_WORD(Memory.C4RAM+0x1f45)&0x1fff), + C4GetMemPointer(READ_3WORD(Memory.C4RAM+0x1f40)), + READ_WORD(Memory.C4RAM+0x1f43)); + } +} + +int16 C4SinTable[512] = { + 0, 402, 804, 1206, 1607, 2009, 2410, 2811, + 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, + 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, + 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, + 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, + 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, + 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, + 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, + 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, + 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, + 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, + 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, + 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, + 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, + 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, + 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, + 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, + 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, + 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, + 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, + 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, + 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, + 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, + 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, + 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, + 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, + 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, + 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, + 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, + 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, + 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, + 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, + 0, -402, -804, -1206, -1607, -2009, -2410, -2811, + -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, + -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, + -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, + -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, + -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, + -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, + -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, + -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, + -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, + -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, + -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, + -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, + -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, + -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, + -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, + -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, + -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, + -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, + -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, + -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, + -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, + -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, + -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, + -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, + -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, + -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, + -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, + -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, + -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, + -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, + -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 +}; + +int16 C4CosTable[512] = { + 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, + 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, + 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, + 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, + 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, + 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, + 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, + 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, + 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, + 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, + 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, + 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, + 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, + 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, + 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, + 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, + 0, -402, -804, -1206, -1607, -2009, -2410, -2811, + -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, + -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, + -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, + -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, + -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, + -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, + -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, + -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, + -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, + -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, + -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, + -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, + -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, + -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, + -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, + -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, + -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, + -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, + -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, + -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, + -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, + -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, + -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, + -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, + -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, + -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, + -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, + -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, + -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, + -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, + -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, + 0, 402, 804, 1206, 1607, 2009, 2410, 2811, + 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, + 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, + 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, + 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, + 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, + 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, + 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, + 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, + 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, + 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, + 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, + 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, + 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, + 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, + 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 +}; + diff --git a/source/snes9x/clip.cpp b/source/snes9x/clip.cpp new file mode 100644 index 0000000..0196da4 --- /dev/null +++ b/source/snes9x/clip.cpp @@ -0,0 +1,328 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" + +static uint8 region_map[6][6]={ + {0, 0x01, 0x03, 0x07, 0x0f, 0x1f }, + {0, 0, 0x02, 0x06, 0x0e, 0x1e }, + {0, 0, 0, 0x04, 0x0c, 0x1c }, + {0, 0, 0, 0, 0x08, 0x18 }, + {0, 0, 0, 0, 0, 0x10 } +}; + +static inline uint8 CalcWindowMask(int i, uint8 W1, uint8 W2){ + if(!PPU.ClipWindow1Enable[i]){ + if(!PPU.ClipWindow2Enable[i]){ + return 0; + } else { + if(!PPU.ClipWindow2Inside[i]) return ~W2; + return W2; + } + } else { + if(!PPU.ClipWindow2Enable[i]){ + if(!PPU.ClipWindow1Inside[i]) return ~W1; + return W1; + } else { + if(!PPU.ClipWindow1Inside[i]) W1=~W1; + if(!PPU.ClipWindow2Inside[i]) W2=~W2; + switch(PPU.ClipWindowOverlapLogic[i]){ + case 0: // OR + return W1|W2; + case 1: // AND + return W1&W2; + case 2: // XOR + return W1^W2; + case 3: // XNOR + return ~(W1^W2); + } + } + } + + // Never get here + return 0; +} + +static inline void StoreWindowRegions(uint8 Mask, struct ClipData *Clip, int n_regions, int16 *windows, uint8 *drawing_modes, bool8 sub, bool8 StoreMode0=FALSE){ + int ct=0; + for(int j=0; j0 && Clip->Right[ct-1]==windows[j] && Clip->DrawMode[ct-1]==DrawMode){ + // This region borders with and has the same drawing mode as the + // previous region: merge them. + Clip->Right[ct-1]=windows[j+1]; + } else { + // Add a new region to the BG + Clip->Left[ct]=windows[j]; + Clip->Right[ct]=windows[j+1]; + Clip->DrawMode[ct]=DrawMode; + ct++; + } + } + Clip->Count=ct; +} + +void ComputeClipWindows () { + int16 windows[6]={0,256,256,256,256,256}; + uint8 drawing_modes[5]={0,0,0,0,0}; + int n_regions=1; + int i, j; + + // Calculate window regions. We have at most 5 regions, because we have 6 + // control points (screen edges, window 1 left & right, and window 2 left & + // right). + if(PPU.Window1Left<=PPU.Window1Right){ + if(PPU.Window1Left>0){ + windows[2]=256; + windows[1]=PPU.Window1Left; + n_regions=2; + } + if(PPU.Window1Right<255){ + windows[n_regions+1]=256; + windows[n_regions]=PPU.Window1Right+1; + n_regions++; + } + } + if(PPU.Window2Left<=PPU.Window2Right){ + for(i=0; i<=n_regions; i++){ + if(PPU.Window2Left==windows[i]) break; + if(PPU.Window2Left=i; j--){ + windows[j+1]=windows[j]; + } + windows[i]=PPU.Window2Left; + n_regions++; + break; + } + } + for(; i<=n_regions; i++){ + if(PPU.Window2Right+1==windows[i]) break; + if(PPU.Window2Right+1=i; j--){ + windows[j+1]=windows[j]; + } + windows[i]=PPU.Window2Right+1; + n_regions++; + break; + } + } + } + + // Get a bitmap of which regions correspond to each window. + uint8 W1, W2; + + if(PPU.Window1Left<=PPU.Window1Right){ + for(i=0; windows[i]!=PPU.Window1Left; i++); + for(j=i; windows[j]!=PPU.Window1Right+1; j++); + W1=region_map[i][j]; + } else { + W1=0; + } + if(PPU.Window2Left<=PPU.Window2Right){ + for(i=0; windows[i]!=PPU.Window2Left; i++); + for(j=i; windows[j]!=PPU.Window2Right+1; j++); + W2=region_map[i][j]; + } else { + W2=0; + } + + // Color Window affects the drawing mode for each region. Modes are: 3=Draw + // as normal, 2=clip color (math only), 1=no math (draw only), 0=nothing. + uint8 CW_color=0, CW_math=0; + uint8 CW=CalcWindowMask(5,W1,W2); + + switch(Memory.FillRAM[0x2130]&0xc0){ + case 0x00: + CW_color=0; + break; + case 0x40: + CW_color=~CW; + break; + case 0x80: + CW_color=CW; + break; + case 0xc0: + CW_color=0xff; + break; + } + switch(Memory.FillRAM[0x2130]&0x30){ + case 0x00: + CW_math=0; + break; + case 0x10: + CW_math=~CW; + break; + case 0x20: + CW_math=CW; + break; + case 0x30: + CW_math=0xff; + break; + } + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "snes9x.h" +#include "memmap.h" +#include "controls.h" +#include "crosshairs.h" +#include "ppu.h" +#include "display.h" +#include "cpuexec.h" +#include "snapshot.h" +#include "spc7110.h" +#include "movie.h" + +using namespace std; + +#define NONE -2 +#define MP5 -1 +#define JOYPAD0 0 +#define JOYPAD1 1 +#define JOYPAD2 2 +#define JOYPAD3 3 +#define JOYPAD4 4 +#define JOYPAD5 5 +#define JOYPAD6 6 +#define JOYPAD7 7 +#define MOUSE0 8 +#define MOUSE1 9 +#define SUPERSCOPE 10 +#define ONE_JUSTIFIER 11 +#define TWO_JUSTIFIERS 12 +#define NUMCTLS 13 // This must be LAST + +#define POLL_ALL NUMCTLS + +static map keymap; +static set pollmap[NUMCTLS+1]; +static vector multis; +struct exemulti { + int32 pos; + bool data1; + s9xcommand_t *script; +}; +static set exemultis; + +static struct { + int16 x, y; + int V_adj; bool V_var; + int H_adj; bool H_var; + bool mapped; +} pseudopointer[8]; +static uint8 pseudobuttons[256]; + +struct crosshair { + uint8 set; + uint8 img; + uint8 fg; + uint8 bg; +}; + +static uint8 turbo_time; +static struct { + uint16 buttons; + uint16 turbos; + uint16 toggleturbo; + uint16 togglestick; + uint8 turbo_ct; +} joypad[8]; +static struct { + uint8 delta_x, delta_y; + int16 old_x, old_y; + int16 cur_x, cur_y; + uint8 buttons; + uint32 ID; + struct crosshair crosshair; +} mouse[2]; + +#define SUPERSCOPE_FIRE 0x80 +#define SUPERSCOPE_CURSOR 0x40 +#define SUPERSCOPE_TURBO 0x20 +#define SUPERSCOPE_PAUSE 0x10 +#define SUPERSCOPE_OFFSCREEN 0x02 +static struct { + int16 x, y; + uint8 phys_buttons; + uint8 next_buttons; + uint8 read_buttons; + uint32 ID; + struct crosshair crosshair; +} superscope; + +#define JUSTIFIER_TRIGGER 0x80 +#define JUSTIFIER_START 0x20 +#define JUSTIFIER_SELECT 0x08 +static struct { + int16 x[2], y[2]; + uint8 buttons; + bool offscreen[2]; + uint32 ID[2]; + struct crosshair crosshair[2]; +} justifier; +static struct { + int8 pads[4]; +} mp5[2]; + +uint8 read_idx[2 /* ports */][2 /* per port */]; + +#define FLAG_IOBIT0 (Memory.FillRAM[0x4213]&0x40) +#define FLAG_IOBIT1 (Memory.FillRAM[0x4213]&0x80) +#define FLAG_IOBIT(n) ((n)?(FLAG_IOBIT1):(FLAG_IOBIT0)) +static bool FLAG_LATCH=false; +static int curcontrollers[2]={ NONE, NONE }; +static int newcontrollers[2]={ JOYPAD0, NONE }; + +/*******************/ + +// Note: these should be in asciibetical order! +static const char *command_names[]={ + "BGLayeringHack", + "BeginRecordingMovie", + "ClipWindows", + "Debugger", + "DecEmuTurbo", + "DecFrameRate", + "DecFrameTime", + "DecTurboSpeed", + "DumpSPC7110Log", + "EmuTurbo", + "EndRecordingMovie", + "ExitEmu", + "IncEmuTurbo", + "IncFrameRate", + "IncFrameTime", + "IncTurboSpeed", + "InterpolateSound", + "LoadFreezeFile", + "LoadMovie", + "LoadOopsFile", + "Mode7Interpolate", + "Pause", + "QuickLoad000", "QuickLoad001", "QuickLoad002", "QuickLoad003", "QuickLoad004", "QuickLoad005", "QuickLoad006", "QuickLoad007", "QuickLoad008", "QuickLoad009", "QuickLoad010", + "QuickSave000", "QuickSave001", "QuickSave002", "QuickSave003", "QuickSave004", "QuickSave005", "QuickSave006", "QuickSave007", "QuickSave008", "QuickSave009", "QuickSave010", + "Reset", + "SaveFreezeFile", + "SaveSPC", + "Screenshot", + "SoftReset", + "SoundChannel0", "SoundChannel1", "SoundChannel2", "SoundChannel3", "SoundChannel4", "SoundChannel5", "SoundChannel6", "SoundChannel7", + "SoundChannelsOn", + "SwapJoypads", + "SynchronizeSound", + "ToggleBG0", "ToggleBG1", "ToggleBG2", "ToggleBG3", + "ToggleEmuTurbo", + "ToggleHDMA", + "ToggleSprites", + "ToggleTransparency", + NULL // This MUST be last! +}; + +enum command_numbers { + BGLayeringHack, + BeginRecordingMovie, + ClipWindows, + Debugger, + DecEmuTurbo, + DecFrameRate, + DecFrameTime, + DecTurboSpeed, + DumpSPC7110Log, + EmuTurbo, + EndRecordingMovie, + ExitEmu, + IncEmuTurbo, + IncFrameRate, + IncFrameTime, + IncTurboSpeed, + InterpolateSound, + LoadFreezeFile, + LoadMovie, + LoadOopsFile, + Mode7Interpolate, + Pause, + QuickLoad000, QuickLoad001, QuickLoad002, QuickLoad003, QuickLoad004, QuickLoad005, QuickLoad006, QuickLoad007, QuickLoad008, QuickLoad009, QuickLoad010, + QuickSave000, QuickSave001, QuickSave002, QuickSave003, QuickSave004, QuickSave005, QuickSave006, QuickSave007, QuickSave008, QuickSave009, QuickSave010, + Reset, + SaveFreezeFile, + SaveSPC, + Screenshot, + SoftReset, + SoundChannel0, SoundChannel1, SoundChannel2, SoundChannel3, SoundChannel4, SoundChannel5, SoundChannel6, SoundChannel7, + SoundChannelsOn, + SwapJoypads, + SynchronizeSound, + ToggleBG0, ToggleBG1, ToggleBG2, ToggleBG3, + ToggleEmuTurbo, + ToggleHDMA, + ToggleSprites, + ToggleTransparency, + + LAST_COMMAND // must be last! +}; + +static const char *color_names[32]={ + "Trans", "Black", "25Grey", "50Grey", "75Grey", "White", "Red", "Orange", "Yellow", "Green", "Cyan", "Sky", "Blue", "Violet", "MagicPink", "Purple", + NULL, "tBlack", "t25Grey", "t50Grey", "t75Grey", "tWhite", "tRed", "tOrange", "tYellow", "tGreen", "tCyan", "tSky", "tBlue", "tViolet", "tMagicPink", "tPurple" +}; + +static const char *speed_names[4]={ "Var", "Slow", "Med", "Fast" }; + +static const int ptrspeeds[4]={ 1, 1, 4, 8 }; + +/*******************/ + +static char buf[256]; +static string& operator+=(string &s, int i){ + snprintf(buf, sizeof(buf), "%d", i); + s.append(buf); + return s; +} + +static string& operator+=(string &s, double d){ + snprintf(buf, sizeof(buf), "%g", d); + s.append(buf); + return s; +} + +static void S9xDisplayStateChange(const char *str, bool8 on){ + snprintf(buf, sizeof(buf), "%s %s", str, on?"on":"off"); + S9xSetInfoString(buf); +} + +static void DoGunLatch(int x, int y){ + x+=40; + if(x>295) x=295; + if(x<40) x=40; + if(y>PPU.ScreenHeight-1) y=PPU.ScreenHeight-1; + if(y<0) y=0; + + PPU.GunVLatch = (uint16) (y + 1); + PPU.GunHLatch = (uint16) x; +} + +#define MAP_UNKNOWN -1 +#define MAP_NONE 0 +#define MAP_BUTTON 1 +#define MAP_AXIS 2 +#define MAP_POINTER 3 +static int maptype(int t){ + switch(t){ + case S9xNoMapping: + return MAP_NONE; + + case S9xButtonJoypad: + case S9xButtonMouse: + case S9xButtonSuperscope: + case S9xButtonJustifier: + case S9xButtonCommand: + case S9xButtonPseudopointer: + case S9xButtonPort: + case S9xButtonMulti: + return MAP_BUTTON; + + case S9xAxisJoypad: + case S9xAxisPseudopointer: + case S9xAxisPseudobuttons: + case S9xAxisPort: + return MAP_AXIS; + + case S9xPointer: + case S9xPointerPort: + return MAP_POINTER; + + default: + return MAP_UNKNOWN; + } +} + +void S9xControlsReset(void){ + S9xControlsSoftReset(); + mouse[0].buttons&=~0x30; + mouse[1].buttons&=~0x30; + justifier.buttons&=~JUSTIFIER_SELECT; +} + +void S9xControlsSoftReset(void){ + int i, j; + + for(set::iterator it=exemultis.begin(); it!=exemultis.end(); it++){ + delete *it; + } + exemultis.clear(); + for(i=0; i<2; i++){ + for(j=0; j<2; j++){ + read_idx[i][j]=0; + } + } + FLAG_LATCH=false; +} + +void S9xUnmapAllControls(void){ + int i; + + S9xControlsReset(); + keymap.clear(); + for(i=0; i<(int)multis.size(); i++){ + free(multis[i]); + } + multis.clear(); + for(i=0; i1) return; + switch(controller){ + case CTL_NONE: + break; + case CTL_JOYPAD: + if(id1<0 || id1>7) break; + newcontrollers[port]=JOYPAD0+id1; + return; + case CTL_MOUSE: + if(id1<0 || id1>1) break; + if(!Settings.MouseMaster){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Mouse: MouseMaster disabled"); + break; + } + newcontrollers[port]=MOUSE0+id1; + return; + case CTL_SUPERSCOPE: + if(!Settings.SuperScopeMaster){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled"); + break; + } + newcontrollers[port]=SUPERSCOPE; + return; + case CTL_JUSTIFIER: + if(id1<0 || id1>1) break; + if(!Settings.JustifierMaster){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled"); + break; + } + newcontrollers[port]=ONE_JUSTIFIER+id1; + return; + case CTL_MP5: + if(id1<-1 || id1>7) break; + if(id2<-1 || id2>7) break; + if(id3<-1 || id3>7) break; + if(id4<-1 || id4>7) break; + if(!Settings.MultiPlayer5Master){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled"); + break; + } + newcontrollers[port]=MP5; + mp5[port].pads[0]=(id1<0)?NONE:JOYPAD0+id1; + mp5[port].pads[1]=(id2<0)?NONE:JOYPAD0+id2; + mp5[port].pads[2]=(id3<0)?NONE:JOYPAD0+id3; + mp5[port].pads[3]=(id4<0)?NONE:JOYPAD0+id4; + return; + default: + fprintf(stderr, "Unknown controller type %d\n", controller); + break; + } + newcontrollers[port]=NONE; + return; + +} + +bool S9xVerifyControllers(void){ + bool ret=false; + int port; + int i, used[NUMCTLS]; + + for(i=0; i0){ + snprintf(buf, sizeof(buf), "Mouse%d used more than once! Disabling extra instances", i-MOUSE0+1); + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); + newcontrollers[port]=NONE; + ret=true; + break; + } + break; + case SUPERSCOPE: + if(!Settings.SuperScopeMaster){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select SNES Superscope: SuperScopeMaster disabled"); + newcontrollers[port]=NONE; + ret=true; + break; + } + if(used[i]++>0){ + snprintf(buf, sizeof(buf), "Superscope used more than once! Disabling extra instances"); + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); + newcontrollers[port]=NONE; + ret=true; + break; + } + break; + case ONE_JUSTIFIER: case TWO_JUSTIFIERS: + if(!Settings.JustifierMaster){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select Konami Justifier: JustifierMaster disabled"); + newcontrollers[port]=NONE; + ret=true; + break; + } + if(used[ONE_JUSTIFIER]++>0){ + snprintf(buf, sizeof(buf), "Justifier used more than once! Disabling extra instances"); + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); + newcontrollers[port]=NONE; + ret=true; + break; + } + break; + case MP5: + if(!Settings.MultiPlayer5Master){ + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, "Cannot select MP5: MultiPlayer5Master disabled"); + newcontrollers[port]=NONE; + ret=true; + break; + } + for(i=0; i<4; i++){ + if(mp5[port].pads[i]!=NONE){ + if(used[mp5[port].pads[i]-JOYPAD0]++>0){ + snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", mp5[port].pads[i]-JOYPAD0+1); + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); + mp5[port].pads[i]=NONE; + ret=true; + break; + } + } + } + break; + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + if(used[i-JOYPAD0]++>0){ + snprintf(buf, sizeof(buf), "Joypad%d used more than once! Disabling extra instances", i-JOYPAD0+1); + S9xMessage(S9X_CONFIG_INFO, S9X_ERROR, buf); + newcontrollers[port]=NONE; + ret=true; + break; + } + break; + default: + break; + } + } + + return ret; +} + +void S9xGetController(int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4){ + int i; + + *controller=CTL_NONE; + *id1=*id2=*id3=*id4=0; + if(port<0 || port>1) return; + switch(i=newcontrollers[port]){ + case MP5: + *controller=CTL_MP5; + *id1=(mp5[port].pads[0]==NONE)?-1:mp5[port].pads[0]-JOYPAD0; + *id2=(mp5[port].pads[1]==NONE)?-1:mp5[port].pads[1]-JOYPAD0; + *id3=(mp5[port].pads[2]==NONE)?-1:mp5[port].pads[2]-JOYPAD0; + *id4=(mp5[port].pads[3]==NONE)?-1:mp5[port].pads[3]-JOYPAD0; + return; + + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + *controller=CTL_JOYPAD; + *id1=i-JOYPAD0; + return; + + case MOUSE0: case MOUSE1: + *controller=CTL_MOUSE; + *id1=i-MOUSE0; + return; + + case SUPERSCOPE: + *controller=CTL_SUPERSCOPE; + return; + + case ONE_JUSTIFIER: case TWO_JUSTIFIERS: + *controller=CTL_JUSTIFIER; + *id1=i-ONE_JUSTIFIER; + return; + } +} + +void S9xReportControllers(void){ + int port, i; + char buf[79], *c; + + S9xVerifyControllers(); + for(port=0; port<2; port++){ + sprintf(buf, "Controller Port %d: ", port+1); + c=buf+19; + switch(newcontrollers[port]){ + case NONE: + strcat(c, ""); + break; + + case MP5: + strcat(c, "MP5 with pads"); + c+=13; + for(i=0; i<4; i++){ + if(mp5[port].pads[i]==NONE){ + strcat(c, " "); + c+=7; + } else { + sprintf(c, " #%d", mp5[port].pads[i]+1-JOYPAD0); + c+=3; + } + } + break; + + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + sprintf(c, "Pad %d", newcontrollers[port]-JOYPAD0+1); + break; + + case MOUSE0: case MOUSE1: + sprintf(c, "Mouse %d", newcontrollers[port]-MOUSE0+1); + break; + + case SUPERSCOPE: + if(port==0) strcat(c, "Superscope (cannot fire)"); + else strcat(c, "Superscope"); + break; + + case ONE_JUSTIFIER: + if(port==0) strcat(c, "Blue Justifier (cannot fire)"); + else strcat(c, "Blue Justifier"); + break; + + case TWO_JUSTIFIERS: + if(port==0) strcat(c, "Blue and Pink Justifiers (cannot fire)"); + else strcat(c, "Blue and Pink Justifiers"); + break; + } + S9xMessage(S9X_INFO, S9X_CONFIG_INFO, buf); + } +} + + +char *S9xGetCommandName(s9xcommand_t command){ + string s; + char c; + + switch(command.type){ + case S9xButtonJoypad: + if(command.button.joypad.buttons==0) return strdup("None"); + if(command.button.joypad.buttons&0x000f) return strdup("None"); + s="Joypad"; + s+=command.button.joypad.idx+1; + c=' '; + if(command.button.joypad.toggle){ if(c) s+=c; s+="Toggle"; c=0; } + if(command.button.joypad.sticky){ if(c) s+=c; s+="Sticky"; c=0; } + if(command.button.joypad.turbo){ if(c) s+=c; s+="Turbo"; c=0; } + + c=' '; + if(command.button.joypad.buttons&SNES_UP_MASK){ s+=c; s+="Up"; c='+'; } + if(command.button.joypad.buttons&SNES_DOWN_MASK){ s+=c; s+="Down"; c='+'; } + if(command.button.joypad.buttons&SNES_LEFT_MASK){ s+=c; s+="Left"; c='+'; } + if(command.button.joypad.buttons&SNES_RIGHT_MASK){ s+=c; s+="Right"; c='+'; } + if(command.button.joypad.buttons&SNES_A_MASK){ s+=c; s+="A"; c='+'; } + if(command.button.joypad.buttons&SNES_B_MASK){ s+=c; s+="B"; c='+'; } + if(command.button.joypad.buttons&SNES_X_MASK){ s+=c; s+="X"; c='+'; } + if(command.button.joypad.buttons&SNES_Y_MASK){ s+=c; s+="Y"; c='+'; } + if(command.button.joypad.buttons&SNES_TL_MASK){ s+=c; s+="L"; c='+'; } + if(command.button.joypad.buttons&SNES_TR_MASK){ s+=c; s+="R"; c='+'; } + if(command.button.joypad.buttons&SNES_START_MASK){ s+=c; s+="Start"; c='+'; } + if(command.button.joypad.buttons&SNES_SELECT_MASK){ s+=c; s+="Select"; c='+'; } + break; + + case S9xButtonMouse: + if(!command.button.mouse.left && !command.button.mouse.right) return strdup("None"); + s="Mouse"; + s+=command.button.mouse.idx+1; + s+=" "; + if(command.button.mouse.left) s+="L"; + if(command.button.mouse.right) s+="R"; + break; + + case S9xButtonSuperscope: + if(!command.button.scope.fire && !command.button.scope.cursor && !command.button.scope.turbo && !command.button.scope.pause && !command.button.scope.aim_offscreen) return strdup("None"); + s="Superscope"; + if(command.button.scope.aim_offscreen) s+=" AimOffscreen"; + c=' '; + if(command.button.scope.fire){ s+=c; s+="Fire"; c='+'; } + if(command.button.scope.cursor){ s+=c; s+="Cursor"; c='+'; } + if(command.button.scope.turbo){ s+=c; s+="ToggleTurbo"; c='+'; } + if(command.button.scope.pause){ s+=c; s+="Pause"; c='+'; } + break; + + case S9xButtonJustifier: + if(!command.button.justifier.trigger && !command.button.justifier.start && !command.button.justifier.aim_offscreen) return strdup("None"); + s="Justifier"; + s+=command.button.justifier.idx+1; + if(command.button.justifier.aim_offscreen) s+=" AimOffscreen"; + c=' '; + if(command.button.justifier.trigger){ s+=c; s+="Trigger"; c='+'; } + if(command.button.justifier.start){ s+=c; s+="Start"; c='+'; } + break; + + case S9xButtonCommand: + if(command.button.command>=LAST_COMMAND) return strdup("None"); + return strdup(command_names[command.button.command]); + + case S9xPointer: + if(!command.pointer.aim_mouse0 && !command.pointer.aim_mouse1 && !command.pointer.aim_scope && !command.pointer.aim_justifier0 && !command.pointer.aim_justifier1) return strdup("None"); + s="Pointer"; + c=' '; + if(command.pointer.aim_mouse0){ s+=c; s+="Mouse1"; c='+'; } + if(command.pointer.aim_mouse1){ s+=c; s+="Mouse2"; c='+'; } + if(command.pointer.aim_scope){ s+=c; s+="Superscope"; c='+'; } + if(command.pointer.aim_justifier0){ s+=c; s+="Justifier1"; c='+'; } + if(command.pointer.aim_justifier1){ s+=c; s+="Justifier2"; c='+'; } + break; + + case S9xButtonPseudopointer: + if(!command.button.pointer.UD && !command.button.pointer.LR) return strdup("None"); + if(command.button.pointer.UD==-2 || command.button.pointer.LR==-2) return strdup("None"); + s="ButtonToPointer "; + s+=command.button.pointer.idx+1; + if(command.button.pointer.UD) s+=(command.button.pointer.UD==1)?'d':'u'; + if(command.button.pointer.LR) s+=(command.button.pointer.LR==1)?'r':'l'; + s+=" "; + s+=speed_names[command.button.pointer.speed_type]; + break; + + case S9xAxisJoypad: + s="Joypad"; + s+=command.axis.joypad.idx+1; + s+=" Axis "; + switch(command.axis.joypad.axis){ + case 0: + s+=(command.axis.joypad.invert?"Right/Left":"Left/Right"); + break; + case 1: + s+=(command.axis.joypad.invert?"Down/Up":"Up/Down"); + break; + case 2: + s+=(command.axis.joypad.invert?"A/Y":"Y/A"); + break; + case 3: + s+=(command.axis.joypad.invert?"B/X":"X/B"); + break; + case 4: + s+=(command.axis.joypad.invert?"R/L":"L/R"); + break; + default: + return strdup("None"); + } + s+=" T="; + s+=int((command.axis.joypad.threshold+1)*1000/256)/10.0; + s+="%"; + break; + + case S9xAxisPseudopointer: + s="AxisToPointer "; + s+=command.axis.pointer.idx+1; + s+=command.axis.pointer.HV?'v':'h'; + s+=" "; + if(command.axis.pointer.invert) s+="-"; + s+=speed_names[command.axis.pointer.speed_type]; + break; + + case S9xAxisPseudobuttons: + s="AxisToButtons "; + s+=command.axis.button.negbutton; + s+="/"; + s+=command.axis.button.posbutton; + s+=" T="; + s+=int((command.axis.button.threshold+1)*1000/256)/10.0; + s+="%"; + break; + + case S9xButtonPort: + case S9xAxisPort: + case S9xPointerPort: + return strdup("BUG: Port should have handled this instead of calling S9xGetCommandName()"); + + case S9xNoMapping: + return strdup("None"); + + case S9xButtonMulti: + { + if(command.button.multi_idx>=(int)multis.size()) return strdup("None"); + s="{"; + if(multis[command.button.multi_idx]->multi_press) s="+{"; + bool sep=false; + for(s9xcommand_t *c=multis[command.button.multi_idx]; c->multi_press!=3; c++){ + if(c->type==S9xNoMapping){ + s+=";"; + sep=false; + } else { + if(sep) s+=","; + if(c->multi_press==1) s+="+"; + if(c->multi_press==2) s+="-"; + s+=S9xGetCommandName(*c); + sep=true; + } + } + s+="}"; + } + break; + + default: + return strdup("BUG: Unknown command type"); + } + + return strdup(s.c_str()); +} + +static bool strless(const char *a, const char *b){ + return strcmp(a, b)<0; +} + +static int findstr(const char *needle, const char **haystack, int numstr){ + const char **r; + r=lower_bound(haystack, haystack+numstr, needle, strless); + if(r>=haystack+numstr || strcmp(needle,*r)) return -1; + return r-haystack; +} + +static int get_threshold(const char **ss){ + int i; + const char *s=*ss; + + if(s[0]!='T' || s[1]!='=') return -1; + s+=2; + i=0; + if(s[0]=='0'){ + if(s[1]!='.') return -1; + s++; + } else { + do { + if(*s<'0' || *s>'9') return -1; + i=i*10+10*(*s-'0'); + if(i>1000) return -1; + s++; + } while(*s!='.' && *s!='%'); + } + if(*s=='.'){ + if(s[1]<'0' || s[1]>'9' || s[2]!='%') return -1; + i+=s[1]-'0'; + } + if(i>1000) return -1; + *ss=s; + return i; +} + +s9xcommand_t S9xGetCommandT(const char *name){ + s9xcommand_t cmd; + int i, j; + const char *s; + ZeroMemory(&cmd, sizeof(cmd)); + cmd.type=S9xBadMapping; + cmd.multi_press=0; + cmd.button_norpt=0; + + if(!strcmp(name,"None")){ + cmd.type=S9xNoMapping; + } else if(!strncmp(name,"Joypad",6)){ + if(name[6]<'1' || name[6]>'8' || name[7]!=' ') return cmd; + if(!strncmp(name+8,"Axis ",5)){ + cmd.axis.joypad.idx = name[6]-'1'; + s=name+13; + if(!strncmp(s,"Left/Right ",11)){ j=0; i=0; s+=11; } + else if(!strncmp(s,"Right/Left ",11)){ j=0; i=1; s+=11; } + else if(!strncmp(s,"Up/Down ",8)){ j=1; i=0; s+=8; } + else if(!strncmp(s,"Down/Up ",8)){ j=1; i=1; s+=8; } + else if(!strncmp(s,"Y/A ",4)){ j=2; i=0; s+=4; } + else if(!strncmp(s,"A/Y ",4)){ j=2; i=1; s+=4; } + else if(!strncmp(s,"X/B ",4)){ j=3; i=0; s+=4; } + else if(!strncmp(s,"B/X ",4)){ j=3; i=1; s+=4; } + else if(!strncmp(s,"L/R ",4)){ j=4; i=0; s+=4; } + else if(!strncmp(s,"R/L ",4)){ j=4; i=1; s+=4; } + else { return cmd; } + cmd.axis.joypad.axis=j; + cmd.axis.joypad.invert=i; + i=get_threshold(&s); + if(i<0) return cmd; + cmd.axis.joypad.threshold=(i-1)*256/1000; + cmd.type=S9xAxisJoypad; + } else { + cmd.button.joypad.idx = name[6]-'1'; + s=name+8; + i=0; + if((cmd.button.joypad.toggle=strncmp(s,"Toggle",6)?0:1)) s+=i=6; + if((cmd.button.joypad.sticky=strncmp(s,"Sticky",6)?0:1)) s+=i=6; + if((cmd.button.joypad.turbo=strncmp(s,"Turbo",5)?0:1)) s+=i=5; + if(cmd.button.joypad.toggle && !(cmd.button.joypad.sticky || cmd.button.joypad.turbo)) return cmd; + if(i){ + if(*s!=' ') return cmd; + s++; + } + + i=0; + if(!strncmp(s,"Up",2)){ i|=SNES_UP_MASK; s+=2; if(*s=='+') s++; } + if(!strncmp(s,"Down",4)){ i|=SNES_DOWN_MASK; s+=4; if(*s=='+') s++; } + if(!strncmp(s,"Left",4)){ i|=SNES_LEFT_MASK; s+=4; if(*s=='+') s++; } + if(!strncmp(s,"Right",5)){ i|=SNES_RIGHT_MASK; s+=5; if(*s=='+') s++; } + if(*s=='A'){ i|=SNES_A_MASK; s++; if(*s=='+') s++; } + if(*s=='B'){ i|=SNES_B_MASK; s++; if(*s=='+') s++; } + if(*s=='X'){ i|=SNES_X_MASK; s++; if(*s=='+') s++; } + if(*s=='Y'){ i|=SNES_Y_MASK; s++; if(*s=='+') s++; } + if(*s=='L'){ i|=SNES_TL_MASK; s++; if(*s=='+') s++; } + if(*s=='R'){ i|=SNES_TR_MASK; s++; if(*s=='+') s++; } + if(!strncmp(s,"Start",5)){ i|=SNES_START_MASK; s+=5; if(*s=='+') s++; } + if(!strncmp(s,"Select",6)){ i|=SNES_SELECT_MASK; s+=6; } + if(i==0 || *s!=0 || *(s-1)=='+') return cmd; + cmd.button.joypad.buttons=i; + cmd.type=S9xButtonJoypad; + } + } else if(!strncmp(name,"Mouse",5)){ + if(name[5]<'1' || name[5]>'2' || name[6]!=' ') return cmd; + cmd.button.mouse.idx = name[5]-'1'; + s=name+7; + i=0; + if((cmd.button.mouse.left=(*s=='L'))) s+=i=1; + if((cmd.button.mouse.right=(*s=='R'))) s+=i=1; + if(i==0 || *s!=0) return cmd; + cmd.type=S9xButtonMouse; + } else if(!strncmp(name,"Superscope ",11)){ + s=name+11; + i=0; + if((cmd.button.scope.aim_offscreen=strncmp(s,"AimOffscreen",12)?0:1)){ s+=i=12; if(*s==' '){ s++; } else if(*s!=0){ return cmd; }} + if((cmd.button.scope.fire=strncmp(s,"Fire",4)?0:1)){ s+=i=4; if(*s=='+') s++; } + if((cmd.button.scope.cursor=strncmp(s,"Cursor",6)?0:1)){ s+=i=6; if(*s=='+') s++; } + if((cmd.button.scope.turbo=strncmp(s,"ToggleTurbo",11)?0:1)){ s+=i=11; if(*s=='+') s++; } + if((cmd.button.scope.pause=strncmp(s,"Pause",5)?0:1)){ s+=i=5; } + if(i==0 || *s!=0 || *(s-1)=='+') return cmd; + cmd.type=S9xButtonSuperscope; + } else if(!strncmp(name,"Justifier",9)){ + if(name[9]<'1' || name[9]>'2' || name[10]!=' ') return cmd; + cmd.button.justifier.idx = name[9]-'1'; + s=name+11; + i=0; + if((cmd.button.justifier.aim_offscreen=strncmp(s,"AimOffscreen",12)?0:1)){ s+=i=12; if(*s==' '){ s++; } else if(*s!=0){ return cmd; }} + if((cmd.button.justifier.trigger=strncmp(s,"Trigger",7)?0:1)){ s+=i=7; if(*s=='+') s++; } + if((cmd.button.justifier.start=strncmp(s,"Start",5)?0:1)){ s+=i=5; } + if(i==0 || *s!=0 || *(s-1)=='+') return cmd; + cmd.type=S9xButtonJustifier; + } else if(!strncmp(name,"Pointer ",8)){ + s=name+8; + i=0; + if((cmd.pointer.aim_mouse0=strncmp(s,"Mouse1",6)?0:1)){ s+=i=6; if(*s=='+') s++; } + if((cmd.pointer.aim_mouse1=strncmp(s,"Mouse2",6)?0:1)){ s+=i=6; if(*s=='+') s++; } + if((cmd.pointer.aim_scope=strncmp(s,"Superscope",10)?0:1)){ s+=i=10; if(*s=='+') s++; } + if((cmd.pointer.aim_justifier0=strncmp(s,"Justifier1",10)?0:1)){ s+=i=10; if(*s=='+') s++; } + if((cmd.pointer.aim_justifier1=strncmp(s,"Justifier2",10)?0:1)){ s+=i=10; } + if(i==0 || *s!=0 || *(s-1)=='+') return cmd; + cmd.type=S9xPointer; + } else if(!strncmp(name,"ButtonToPointer ",16)){ + if(name[16]<'1' || name[16]>'8') return cmd; + cmd.button.pointer.idx = name[16]-'1'; + s=name+17; + i=0; + if((cmd.button.pointer.UD=(*s=='u'?-1:(*s=='d'?1:0)))) s+=i=1; + if((cmd.button.pointer.LR=(*s=='l'?-1:(*s=='r'?1:0)))) s+=i=1; + if(i==0 || *(s++)!=' ') return cmd; + for(i=0; i<4; i++){ + if(!strcmp(s,speed_names[i])) break; + } + if(i>3) return cmd; + cmd.button.pointer.speed_type=i; + cmd.type=S9xButtonPseudopointer; + } else if(!strncmp(name,"AxisToPointer ",14)){ + if(name[14]<'1' || name[14]>'8') return cmd; + cmd.axis.pointer.idx = name[14]-'1'; + s=name+15; + i=0; + if(*s=='h') cmd.axis.pointer.HV=0; + else if(*s=='v') cmd.axis.pointer.HV=1; + else return cmd; + if(s[1]!=' ') return cmd; + s+=2; + if((cmd.axis.pointer.invert=*s=='-')) s++; + for(i=0; i<4; i++){ + if(!strcmp(s,speed_names[i])) break; + } + if(i>3) return cmd; + cmd.axis.pointer.speed_type=i; + cmd.type=S9xAxisPseudopointer; + } else if(!strncmp(name,"AxisToButtons ",14)){ + s=name+14; + if(s[0]=='0'){ + if(s[1]!='/') return cmd; + cmd.axis.button.negbutton=0; + s+=2; + } else { + i=0; + do { + if(*s<'0' || *s>'9') return cmd; + i=i*10+*s-'0'; + if(i>255) return cmd; + } while(*++s!='/'); + cmd.axis.button.negbutton=i; + s++; + } + if(s[0]=='0'){ + if(s[1]!=' ') return cmd; + cmd.axis.button.posbutton=0; + s+=2; + } else { + i=0; + do { + if(*s<'0' || *s>'9') return cmd; + i=i*10+*s-'0'; + if(i>255) return cmd; + } while(*++s!=' '); + cmd.axis.button.posbutton=i; + s++; + } + i=get_threshold(&s); + if(i<0) return cmd; + cmd.axis.button.threshold=(i-1)*256/1000; + cmd.type=S9xAxisPseudobuttons; + } else if(!strncmp(name, "MULTI#",6)){ + i=strtol(name+6,(char **)&s,10); + if(s!=NULL && *s!='\0') return cmd; + if(i>=(int)multis.size()) return cmd; + cmd.button.multi_idx=i; + cmd.type=S9xButtonMulti; + } else if(((name[0]=='+' && name[1]=='{') || name[0]=='{') && + name[strlen(name)-1]=='}'){ + if(multis.size()>2147483640){ + fprintf(stderr, "Too many multis!"); + return cmd; + } + string x; + int n; + j=2; + for(i=(name[0]=='+')?2:1; name[i]!='\0'; i++){ + if(name[i]==',' || name[i]==';'){ + if(name[i]==';') j++; + if(++j>2147483640){ + fprintf(stderr, "Multi too long!"); + return cmd; + } + } + if(name[i]=='{') return cmd; + } + s9xcommand_t *c=(s9xcommand_t *)calloc(j,sizeof(s9xcommand_t)); + if(c==NULL){ + perror("malloc error while parsing multi"); + return cmd; + } + n=0; i=(name[0]=='+')?2:1; + do { + if(name[i]==';'){ + c[n].type=S9xNoMapping; + c[n].multi_press=0; + c[n].button_norpt=0; + j=i; + } else if(name[i]==','){ + free(c); + return cmd; + } else { + uint8 press=0; + if(name[0]=='+'){ + if(name[i]=='+'){ + press=1; + } else if(name[i]=='-'){ + press=2; + } else { + free(c); + return cmd; + } + i++; + } + for(j=i; name[j]!=';' && name[j]!=',' && name[j]!='}'; j++); + x.assign(name+i,j-i); + c[n]=S9xGetCommandT(x.c_str()); + c[n].multi_press=press; + if(maptype(c[n].type)!=MAP_BUTTON){ + free(c); + return cmd; + } + if(name[j]==';') j--; + } + i=j+1; n++; + } while(name[i]!='\0'); + c[n].type=S9xNoMapping; c[n].multi_press=3; + + multis.push_back(c); + cmd.button.multi_idx=multis.size()-1; + cmd.type=S9xButtonMulti; + } else { + i=findstr(name, command_names, LAST_COMMAND); + if(i<0) return cmd; + cmd.type = S9xButtonCommand; + cmd.button.command = i; + } + + return cmd; +} + +const char **S9xGetAllSnes9xCommands(void){ + return command_names; +} + +s9xcommand_t S9xGetMapping(uint32 id){ + if(keymap.count(id)==0){ + s9xcommand_t cmd; + cmd.type=S9xNoMapping; + return cmd; + } else { + return keymap[id]; + } +} + +static const char *maptypename(int t){ + switch(t){ + case MAP_NONE: return "unmapped"; + case MAP_BUTTON: return "button"; + case MAP_AXIS: return "axis"; + case MAP_POINTER: return "pointer"; + default: return "unknown"; + } +} + +void S9xUnmapID(uint32 id){ + int i; + for(i=0; i=PseudoPointerBase) pseudopointer[id-PseudoPointerBase].mapped=false; + keymap.erase(id); +} + +bool S9xMapButton(uint32 id, s9xcommand_t mapping, bool poll){ + int t; + + if(id==InvalidControlID){ + fprintf(stderr, "Cannot map InvalidControlID\n"); + return false; + } + t=maptype(mapping.type); + if(t==MAP_NONE){ S9xUnmapID(id); return true; } + if(t!=MAP_BUTTON) return false; + t=maptype(S9xGetMapping(id).type); + if(t!=MAP_NONE && t!=MAP_BUTTON) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to button\n", id, maptypename(t)); + if(id>=PseudoPointerBase){ + fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as a button\n", id-PseudoPointerBase); + return false; + } + + t=-1; + if(poll){ + if(id>=PseudoButtonBase){ + fprintf(stderr, "INFO: Ignoring attempt to set pseudo-button #%d to polling\n", id-PseudoButtonBase); + } else switch(mapping.type){ + case S9xButtonJoypad: + t=JOYPAD0+mapping.button.joypad.idx; + break; + case S9xButtonMouse: + t=MOUSE0+mapping.button.mouse.idx; + break; + case S9xButtonSuperscope: + t=SUPERSCOPE; + break; + case S9xButtonJustifier: + t=ONE_JUSTIFIER+mapping.button.justifier.idx; + break; + case S9xButtonCommand: + case S9xButtonPseudopointer: + case S9xButtonPort: + case S9xButtonMulti: + t=POLL_ALL; + break; + } + } + + S9xUnmapID(id); + keymap[id]=mapping; + if(t>=0) pollmap[t].insert(id); + return true; +} + +void S9xReportButton(uint32 id, bool pressed){ + if(keymap.count(id)==0) return; + if(keymap[id].type==S9xNoMapping) return; + if(maptype(keymap[id].type)!=MAP_BUTTON){ + fprintf(stderr, "ERROR: S9xReportButton called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); + return; + } + + if(keymap[id].button_norpt==pressed) return; + keymap[id].button_norpt=pressed; + S9xApplyCommand(keymap[id], pressed, 0); +} + + +bool S9xMapPointer(uint32 id, s9xcommand_t mapping, bool poll){ + int t; + + if(id==InvalidControlID){ + fprintf(stderr, "Cannot map InvalidControlID\n"); + return false; + } + t=maptype(mapping.type); + if(t==MAP_NONE){ S9xUnmapID(id); return true; } + if(t!=MAP_POINTER) return false; + t=maptype(S9xGetMapping(id).type); + if(t!=MAP_NONE && t!=MAP_POINTER) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to pointer\n", id, maptypename(t)); + if(id=PseudoButtonBase){ + fprintf(stderr, "ERROR: Refusing to map pseudo-button #%d as a pointer\n", id-PseudoButtonBase); + return false; + } + + if(mapping.type==S9xPointer){ + if(mapping.pointer.aim_mouse0 && mouse[0].ID!=InvalidControlID && mouse[0].ID!=id){ fprintf(stderr, "ERROR: Rejecting attempt to control Mouse1 with two pointers\n"); return false; } + if(mapping.pointer.aim_mouse1 && mouse[1].ID!=InvalidControlID && mouse[1].ID!=id){ fprintf(stderr, "ERROR: Rejecting attempt to control Mouse2 with two pointers\n"); return false; } + if(mapping.pointer.aim_scope && superscope.ID!=InvalidControlID && superscope.ID!=id){ fprintf(stderr, "ERROR: Rejecting attempt to control SuperScope with two pointers\n"); return false; } + if(mapping.pointer.aim_justifier0 && justifier.ID[0]!=InvalidControlID && justifier.ID[0]!=id){ fprintf(stderr, "ERROR: Rejecting attempt to control Justifier1 with two pointers\n"); return false; } + if(mapping.pointer.aim_justifier1 && justifier.ID[1]!=InvalidControlID && justifier.ID[1]!=id){ fprintf(stderr, "ERROR: Rejecting attempt to control Justifier2 with two pointers\n"); return false; } + } + + S9xUnmapID(id); + if(poll){ + if(id>=PseudoPointerBase){ + fprintf(stderr, "INFO: Ignoring attempt to set pseudo-pointer #%d to polling\n", id-PseudoPointerBase); + } else switch(mapping.type){ + case S9xPointer: + if(mapping.pointer.aim_mouse0) pollmap[MOUSE0].insert(id); + if(mapping.pointer.aim_mouse1) pollmap[MOUSE1].insert(id); + if(mapping.pointer.aim_scope) pollmap[SUPERSCOPE].insert(id); + if(mapping.pointer.aim_justifier0) pollmap[ONE_JUSTIFIER].insert(id); + if(mapping.pointer.aim_justifier1) pollmap[TWO_JUSTIFIERS].insert(id); + break; + case S9xPointerPort: + pollmap[POLL_ALL].insert(id); + break; + } + } + + if(id>=PseudoPointerBase) pseudopointer[id-PseudoPointerBase].mapped=true; + keymap[id]=mapping; + if(mapping.pointer.aim_mouse0) mouse[0].ID=id; + if(mapping.pointer.aim_mouse1) mouse[1].ID=id; + if(mapping.pointer.aim_scope) superscope.ID=id; + if(mapping.pointer.aim_justifier0) justifier.ID[0]=id; + if(mapping.pointer.aim_justifier1) justifier.ID[1]=id; + return true; +} + +void S9xReportPointer(uint32 id, int16 x, int16 y){ + if(keymap.count(id)==0) return; + if(keymap[id].type==S9xNoMapping) return; + if(maptype(keymap[id].type)!=MAP_POINTER){ + fprintf(stderr, "ERROR: S9xReportPointer called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); + return; + } + + S9xApplyCommand(keymap[id], x, y); +} + + +bool S9xMapAxis(uint32 id, s9xcommand_t mapping, bool poll){ + int t; + + if(id==InvalidControlID){ + fprintf(stderr, "Cannot map InvalidControlID\n"); + return false; + } + t=maptype(mapping.type); + if(t==MAP_NONE){ S9xUnmapID(id); return true; } + if(t!=MAP_AXIS) return false; + t=maptype(S9xGetMapping(id).type); + if(t!=MAP_NONE && t!=MAP_AXIS) fprintf(stderr, "WARNING: Remapping ID 0x%08x from %s to axis\n", id, maptypename(t)); + if(id>=PseudoPointerBase){ + fprintf(stderr, "ERROR: Refusing to map pseudo-pointer #%d as an axis\n", id-PseudoPointerBase); + return false; + } + if(id>=PseudoButtonBase){ + fprintf(stderr, "ERROR: Refusing to map pseudo-button #%d as an axis\n", id-PseudoButtonBase); + return false; + } + + t=-1; + if(poll){ + switch(mapping.type){ + case S9xAxisJoypad: + t=JOYPAD0+mapping.axis.joypad.idx; + break; + case S9xAxisPseudopointer: + case S9xAxisPseudobuttons: + case S9xAxisPort: + t=POLL_ALL; + break; + } + } + + S9xUnmapID(id); + keymap[id]=mapping; + if(t>=0) pollmap[t].insert(id); + return true; +} + +void S9xReportAxis(uint32 id, int16 value){ + if(keymap.count(id)==0) return; + if(keymap[id].type==S9xNoMapping) return; + if(maptype(keymap[id].type)!=MAP_AXIS){ + fprintf(stderr, "ERROR: S9xReportAxis called on %s ID 0x%08x\n", maptypename(maptype(keymap[id].type)), id); + return; + } + + S9xApplyCommand(keymap[id], value, 0); +} + + +static int32 ApplyMulti(s9xcommand_t *multi, int32 pos, int16 data1){ + while(1){ + if(multi[pos].multi_press==3) return -1; + if(multi[pos].type==S9xNoMapping) break; + if(multi[pos].multi_press){ + S9xApplyCommand(multi[pos], multi[pos].multi_press==1, 0); + } else { + S9xApplyCommand(multi[pos], data1, 0); + } + pos++; + } + return pos+1; +} + +void S9xApplyCommand(s9xcommand_t cmd, int16 data1, int16 data2){ + int i; + + switch(cmd.type){ + case S9xNoMapping: + return; + + case S9xButtonJoypad: + if(cmd.button.joypad.toggle){ + if(!data1) return; + uint16 r=cmd.button.joypad.buttons; + if(cmd.button.joypad.turbo) joypad[cmd.button.joypad.idx].toggleturbo^=r; + if(cmd.button.joypad.sticky) joypad[cmd.button.joypad.idx].togglestick^=r; + } else { + uint16 r,s,t,st; + s=t=st=0; + r=cmd.button.joypad.buttons; + st=r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo; + r ^= st; + t=r & joypad[cmd.button.joypad.idx].toggleturbo; + r ^= t; + s=r & joypad[cmd.button.joypad.idx].togglestick; + r ^= s; + if(cmd.button.joypad.turbo && cmd.button.joypad.sticky){ + uint16 x=r; r=st; st=x; + x=s; s=t; t=x; + } else if(cmd.button.joypad.turbo){ + uint16 x=r; r=t; t=x; + x=s; s=st; st=x; + } else if(cmd.button.joypad.sticky){ + uint16 x=r; r=s; s=x; + x=t; t=st; st=x; + } + if(data1){ + if(cmd.button.joypad.buttons&(SNES_LEFT_MASK|SNES_RIGHT_MASK)){ + // if we're pressing left or right, then unpress and unturbo + // them both first so we don't end up hittnig left AND right + // accidentally. Note though that the user can still do it on + // purpose, bu specifying a single button that presses both. + // This is a feature, look up glitches in tLoZ:aLttP to find + // out why. + joypad[cmd.button.joypad.idx].buttons &= ~(SNES_LEFT_MASK|SNES_RIGHT_MASK); + joypad[cmd.button.joypad.idx].turbos &= ~(SNES_LEFT_MASK|SNES_RIGHT_MASK); + } + if(cmd.button.joypad.buttons&(SNES_UP_MASK|SNES_DOWN_MASK)){ + // and ditto for up/down + joypad[cmd.button.joypad.idx].buttons &= ~(SNES_UP_MASK|SNES_DOWN_MASK); + joypad[cmd.button.joypad.idx].turbos &= ~(SNES_UP_MASK|SNES_DOWN_MASK); + } + joypad[cmd.button.joypad.idx].buttons |= r; + joypad[cmd.button.joypad.idx].turbos |= t; + joypad[cmd.button.joypad.idx].buttons ^= s; + joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & st); + joypad[cmd.button.joypad.idx].turbos ^= st; + } else { + joypad[cmd.button.joypad.idx].buttons &= ~r; + joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & t); + joypad[cmd.button.joypad.idx].turbos &= ~t; + } + } + return; + + case S9xButtonMouse: + i=0; + if(cmd.button.mouse.left) i|=0x40; + if(cmd.button.mouse.right) i|=0x80; + if(data1){ + mouse[cmd.button.mouse.idx].buttons |= i; + } else { + mouse[cmd.button.mouse.idx].buttons &= ~i; + } + return; + + case S9xButtonSuperscope: + i=0; + if(cmd.button.scope.fire) i|=SUPERSCOPE_FIRE; + if(cmd.button.scope.cursor) i|=SUPERSCOPE_CURSOR; + if(cmd.button.scope.pause) i|=SUPERSCOPE_PAUSE; + if(cmd.button.scope.aim_offscreen) i|=SUPERSCOPE_OFFSCREEN; + if(data1){ + superscope.phys_buttons |= i; + if(cmd.button.scope.turbo){ + superscope.phys_buttons^=SUPERSCOPE_TURBO; + if(superscope.phys_buttons&SUPERSCOPE_TURBO){ + superscope.next_buttons |= superscope.phys_buttons&(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR); + } else { + superscope.next_buttons &= ~(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR); + } + } + superscope.next_buttons |= i&(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR|SUPERSCOPE_PAUSE); + if((superscope.next_buttons&(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR)) && + curcontrollers[1]==SUPERSCOPE && + !(superscope.phys_buttons&SUPERSCOPE_OFFSCREEN)){ + DoGunLatch(superscope.x, superscope.y); + } + } else { + superscope.phys_buttons &= ~i; + superscope.next_buttons &= SUPERSCOPE_OFFSCREEN|~i; + } + return; + + case S9xButtonJustifier: + i=0; + if(cmd.button.justifier.trigger) i|=JUSTIFIER_TRIGGER; + if(cmd.button.justifier.start) i|=JUSTIFIER_START; + if(cmd.button.justifier.aim_offscreen) justifier.offscreen[cmd.button.justifier.idx]=data1?1:0; + i>>=cmd.button.justifier.idx; + if(data1){ + justifier.buttons |= i; + } else { + justifier.buttons &= ~i; + } + return; + + case S9xButtonCommand: + if(((enum command_numbers)cmd.button.command)>=LAST_COMMAND){ + fprintf(stderr, "Unknown command %04x\n", cmd.button.command); + return; + } + if(!data1){ + switch(i=cmd.button.command){ + case EmuTurbo: + Settings.TurboMode = FALSE; + break; + } + } else { + switch((enum command_numbers)(i=cmd.button.command)){ + case ExitEmu: + S9xExit(); + break; + case Reset: + S9xReset(); + break; + case SoftReset: + S9xSoftReset(); + break; + case EmuTurbo: + Settings.TurboMode = TRUE; + break; + case ToggleEmuTurbo: + Settings.TurboMode = !Settings.TurboMode; + S9xDisplayStateChange("Turbo Mode", Settings.TurboMode); + break; + case BGLayeringHack: + Settings.BGLayering = !Settings.BGLayering; + S9xDisplayStateChange("Background layering hack", Settings.BGLayering); + break; + case ClipWindows: + Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows; + S9xDisplayStateChange("Graphic clip windows", + !Settings.DisableGraphicWindows); + break; + case Debugger: +#ifdef DEBUGGER + CPU.Flags |= DEBUG_MODE_FLAG; +#endif + break; + case IncFrameRate: + if (Settings.SkipFrames == AUTO_FRAMERATE) + Settings.SkipFrames = 1; + else + if (Settings.SkipFrames < 10) + Settings.SkipFrames++; + + if (Settings.SkipFrames == AUTO_FRAMERATE) + S9xSetInfoString ("Auto frame skip"); + else { + sprintf (buf, "Frame skip: %d", + Settings.SkipFrames - 1); + S9xSetInfoString (buf); + } + break; + case DecFrameRate: + if (Settings.SkipFrames <= 1) + Settings.SkipFrames = AUTO_FRAMERATE; + else + if (Settings.SkipFrames != AUTO_FRAMERATE) + Settings.SkipFrames--; + + if (Settings.SkipFrames == AUTO_FRAMERATE) + S9xSetInfoString ("Auto frame skip"); + else { + sprintf (buf, "Frame skip: %d", + Settings.SkipFrames - 1); + S9xSetInfoString (buf); + } + break; + case IncEmuTurbo: + if(Settings.TurboSkipFrames<20) Settings.TurboSkipFrames += 1; + else if(Settings.TurboSkipFrames<200) Settings.TurboSkipFrames += 5; + sprintf (buf, "Turbo Frame Skip: %d", + Settings.TurboSkipFrames); + S9xSetInfoString (buf); + break; + case DecEmuTurbo: + if(Settings.TurboSkipFrames>20) Settings.TurboSkipFrames -= 5; + else if(Settings.TurboSkipFrames>0) Settings.TurboSkipFrames -= 1; + sprintf (buf, "Turbo Frame Skip: %d", + Settings.TurboSkipFrames); + S9xSetInfoString (buf); + break; + case IncFrameTime: + // Increase emulated frame time by 1ms + Settings.FrameTime += 1000; + sprintf (buf, "Emulated frame time: %dms", + Settings.FrameTime / 1000); + S9xSetInfoString (buf); + break; + case DecFrameTime: + // Decrease emulated frame time by 1ms + if (Settings.FrameTime >= 1000) + Settings.FrameTime -= 1000; + sprintf (buf, "Emulated frame time: %dms", + Settings.FrameTime / 1000); + S9xSetInfoString (buf); + break; + case IncTurboSpeed: + if(turbo_time>=120) break; + turbo_time++; + sprintf (buf, "Turbo speed: %d", + turbo_time); + S9xSetInfoString (buf); + break; + case DecTurboSpeed: + if(turbo_time<=1) break; + turbo_time--; + sprintf (buf, "Turbo speed: %d", + turbo_time); + S9xSetInfoString (buf); + break; + case InterpolateSound: + Settings.InterpolatedSound ^= 1; + S9xDisplayStateChange("Interpolated sound", Settings.InterpolatedSound); + break; + case LoadFreezeFile: +#ifndef NGC + S9xUnfreezeGame(S9xChooseFilename(TRUE)); +#endif + break; + case SaveFreezeFile: +#ifndef NGC + S9xFreezeGame(S9xChooseFilename(FALSE)); +#endif + break; + case LoadOopsFile: + { + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + sprintf (filename, "%s%s%s.%.*s", + S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, + _MAX_EXT-1, "oops"); + +#ifndef NGC + if (S9xLoadSnapshot (filename)) + { + sprintf (buf, "%s.%.*s loaded", def, _MAX_EXT-1, "oops"); + S9xSetInfoString (buf); + } + else + { + S9xMessage (S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, + "Oops file not found"); + } +#endif + } + break; + case Mode7Interpolate: + Settings.Mode7Interpolate ^= TRUE; + S9xDisplayStateChange ("Mode 7 Interpolation", + Settings.Mode7Interpolate); + break; + case Pause: + Settings.Paused ^= 1; + S9xDisplayStateChange ("Pause", Settings.Paused); + break; + case QuickLoad000: case QuickLoad001: case QuickLoad002: case QuickLoad003: case QuickLoad004: case QuickLoad005: case QuickLoad006: case QuickLoad007: case QuickLoad008: case QuickLoad009: case QuickLoad010: + { + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + + sprintf (filename, "%s%s%s.%03d", + S9xGetDirectory (SNAPSHOT_DIR), SLASH_STR, def, + i - QuickLoad000); + +#ifndef NGC + if (S9xLoadSnapshot (filename)) + { + sprintf (buf, "%s.%03d loaded", def, i - QuickLoad000); + S9xSetInfoString (buf); + } + else + { + static char *digits = "t123456789"; + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + + sprintf (filename, "%s%s%s.zs%c", + S9xGetDirectory (SNAPSHOT_DIR), SLASH_STR, + def, digits [i - QuickLoad000]); + if (S9xLoadSnapshot (filename)) + { + sprintf (buf, + "Loaded ZSNES freeze file %s.zs%c", + def, digits [i - QuickLoad000]); + S9xSetInfoString (buf); + } + else + S9xMessage (S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, + "Freeze file not found"); + } +#endif + } + break; + case QuickSave000: case QuickSave001: case QuickSave002: case QuickSave003: case QuickSave004: case QuickSave005: case QuickSave006: case QuickSave007: case QuickSave008: case QuickSave009: case QuickSave010: + { + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + sprintf (filename, "%s%s%s.%03d", + S9xGetDirectory (SNAPSHOT_DIR), SLASH_STR, def, + i - QuickSave000); + sprintf (buf, "%s.%03d saved", def, i - QuickSave000); + S9xSetInfoString (buf); +#ifndef NGC + Snapshot(filename); +#endif + + } + break; + case SaveSPC: + { + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + strcpy (ext, "spc"); + _makepath (filename, drive, S9xGetDirectory (SPC_DIR), + def, ext); + +#ifndef NGC + if (S9xSPCDump (filename)) + sprintf (buf, "%s.%s saved", def, ext); + else + sprintf (buf, "%s.%s not saved (%s)", + def, ext, strerror (errno)); +#endif + S9xSetInfoString (buf); + } + break; + case Screenshot: + Settings.TakeScreenshot=TRUE; + break; + case SoundChannel0: case SoundChannel1: case SoundChannel2: case SoundChannel3: case SoundChannel4: case SoundChannel5: case SoundChannel6: case SoundChannel7: + S9xToggleSoundChannel(i-SoundChannel0); + sprintf (buf, "Sound channel %d toggled", i-SoundChannel0); + S9xSetInfoString (buf); + break; + case SoundChannelsOn: + S9xToggleSoundChannel(8); + S9xSetInfoString ("All sound channels on"); + break; + case SynchronizeSound: + Settings.SoundSync ^= 1; + S9xDisplayStateChange ("Synchronised sound", + Settings.SoundSync); + break; + case ToggleBG0: + PPU.BG_Forced ^= 1; + S9xDisplayStateChange ("BG#0", !(PPU.BG_Forced & 1)); + break; + case ToggleBG1: + PPU.BG_Forced ^= 2; + S9xDisplayStateChange ("BG#1", !(PPU.BG_Forced & 2)); + break; + case ToggleBG2: + PPU.BG_Forced ^= 4; + S9xDisplayStateChange ("BG#2", !(PPU.BG_Forced & 4)); + break; + case ToggleBG3: + PPU.BG_Forced ^= 8; + S9xDisplayStateChange ("BG#3", !(PPU.BG_Forced & 8)); + break; + case ToggleSprites: + PPU.BG_Forced ^= 16; + S9xDisplayStateChange ("Sprites", !(PPU.BG_Forced & 16)); + break; + case ToggleHDMA: + Settings.DisableHDMA = !Settings.DisableHDMA; + S9xDisplayStateChange ("HDMA emulation", !Settings.DisableHDMA); + break; + case ToggleTransparency: + Settings.Transparency = !Settings.Transparency; + S9xDisplayStateChange ("Transparency effects", + Settings.Transparency); + break; + + case DumpSPC7110Log: + if(Settings.SPC7110) Do7110Logging(); + break; + + case BeginRecordingMovie: +#ifndef NGC + if(S9xMovieActive()) S9xMovieStop(FALSE); + S9xMovieCreate(S9xChooseMovieFilename(FALSE), + 0xFF, + //MOVIE_OPT_FROM_SNAPSHOT + MOVIE_OPT_FROM_RESET, + NULL, 0); +#endif + break; + + case LoadMovie: +#ifndef NGC + if(S9xMovieActive()) S9xMovieStop(FALSE); + S9xMovieOpen(S9xChooseMovieFilename(TRUE), FALSE); +#endif + break; + + case EndRecordingMovie: +#ifndef NGC + if(S9xMovieActive()) S9xMovieStop(FALSE); +#endif + break; + + case SwapJoypads: + if((curcontrollers[0]!=NONE && !(curcontrollers[0]>=JOYPAD0 && curcontrollers[0]<=JOYPAD7))){ + S9xSetInfoString("Cannot swap pads: port 1 is not a joypad"); + break; + } + if((curcontrollers[1]!=NONE && !(curcontrollers[1]>=JOYPAD0 && curcontrollers[1]<=JOYPAD7))){ + S9xSetInfoString("Cannot swap pads: port 2 is not a joypad"); + break; + } + newcontrollers[1]=curcontrollers[0]; + newcontrollers[0]=curcontrollers[1]; + strcpy(buf, "Swap pads: P1="); + i=14; + if(newcontrollers[0]==NONE){ + strcpy(buf+i, ""); + i+=6; + } else { + sprintf(buf+i, "Joypad%d", newcontrollers[0]-JOYPAD0+1); + i+=7; + } + strcpy(buf+i, " P2="); + i+=4; + if(newcontrollers[1]==NONE){ + strcpy(buf+i, ""); + i+=6; + } else { + sprintf(buf+i, "Joypad%d", newcontrollers[1]-JOYPAD0+1); + i+=7; + } + S9xSetInfoString(buf); + break; + + case LAST_COMMAND: break; + /* no default, so we get compiler warnings */ + } + } + return; + + case S9xPointer: + if(cmd.pointer.aim_mouse0){ + mouse[0].cur_x=data1; + mouse[0].cur_y=data2; + } + if(cmd.pointer.aim_mouse1){ + mouse[1].cur_x=data1; + mouse[1].cur_y=data2; + } + if(cmd.pointer.aim_scope){ + superscope.x=data1; + superscope.y=data2; + } + if(cmd.pointer.aim_justifier0){ + justifier.x[0]=data1; + justifier.y[0]=data2; + } + if(cmd.pointer.aim_justifier1){ + justifier.x[1]=data1; + justifier.y[1]=data2; + } + return; + + case S9xButtonPseudopointer: + if(data1){ + if(cmd.button.pointer.UD){ + if(!pseudopointer[cmd.button.pointer.idx].V_adj) pseudopointer[cmd.button.pointer.idx].V_adj=cmd.button.pointer.UD*ptrspeeds[cmd.button.pointer.speed_type]; + pseudopointer[cmd.button.pointer.idx].V_var=(cmd.button.pointer.speed_type==0); + } + if(cmd.button.pointer.LR){ + if(!pseudopointer[cmd.button.pointer.idx].H_adj) pseudopointer[cmd.button.pointer.idx].H_adj=cmd.button.pointer.LR*ptrspeeds[cmd.button.pointer.speed_type]; + pseudopointer[cmd.button.pointer.idx].H_var=(cmd.button.pointer.speed_type==0); + } + } else { + if(cmd.button.pointer.UD){ + pseudopointer[cmd.button.pointer.idx].V_adj=0; + pseudopointer[cmd.button.pointer.idx].V_var=false; + } + if(cmd.button.pointer.LR){ + pseudopointer[cmd.button.pointer.idx].H_adj=0; + pseudopointer[cmd.button.pointer.idx].H_var=false; + } + } + return; + + case S9xAxisJoypad: + { + uint16 pos, neg; + switch(cmd.axis.joypad.axis){ + case 0: neg=SNES_LEFT_MASK; pos=SNES_RIGHT_MASK; break; + case 1: neg=SNES_UP_MASK; pos=SNES_DOWN_MASK; break; + case 2: neg=SNES_Y_MASK; pos=SNES_A_MASK; break; + case 3: neg=SNES_X_MASK; pos=SNES_B_MASK; break; + case 4: neg=SNES_TL_MASK; pos=SNES_TR_MASK; break; + default: return; + } + if(cmd.axis.joypad.invert) data1=-data1; + uint16 p, r; + p=r=0; + if(data1>((cmd.axis.joypad.threshold+1)*127)){ + p|=pos; + } else { + r|=pos; + } + if(data1<=((cmd.axis.joypad.threshold+1)*-127)){ + p|=neg; + } else { + r|=neg; + } + joypad[cmd.axis.joypad.idx].buttons |= p; + joypad[cmd.axis.joypad.idx].buttons &= ~r; + joypad[cmd.axis.joypad.idx].turbos &= ~(p|r); + } + return; + + case S9xAxisPseudopointer: + if(data1==0){ + if(cmd.axis.pointer.HV){ + pseudopointer[cmd.axis.pointer.idx].V_adj=0; + pseudopointer[cmd.axis.pointer.idx].V_var=false; + } else { + pseudopointer[cmd.axis.pointer.idx].H_adj=0; + pseudopointer[cmd.axis.pointer.idx].H_var=false; + } + } else { + if(cmd.axis.pointer.invert) data1=-data1; + if(cmd.axis.pointer.HV){ + if(!pseudopointer[cmd.axis.pointer.idx].V_adj) pseudopointer[cmd.axis.pointer.idx].V_adj=(int32)data1*ptrspeeds[cmd.axis.pointer.speed_type]/32767; + pseudopointer[cmd.axis.pointer.idx].V_var=(cmd.axis.pointer.speed_type==0); + } else { + if(!pseudopointer[cmd.axis.pointer.idx].H_adj) pseudopointer[cmd.axis.pointer.idx].H_adj=(int32)data1*ptrspeeds[cmd.axis.pointer.speed_type]/32767; + pseudopointer[cmd.axis.pointer.idx].H_var=(cmd.axis.pointer.speed_type==0); + } + } + return; + + case S9xAxisPseudobuttons: + if(data1>((cmd.axis.button.threshold+1)*127)){ + if(!pseudobuttons[cmd.axis.button.posbutton]){ + pseudobuttons[cmd.axis.button.posbutton]=1; + S9xReportButton(PseudoButtonBase+cmd.axis.button.posbutton, true); + } + } else { + if(pseudobuttons[cmd.axis.button.posbutton]){ + pseudobuttons[cmd.axis.button.posbutton]=0; + S9xReportButton(PseudoButtonBase+cmd.axis.button.posbutton, false); + } + } + if(data1<=((cmd.axis.button.threshold+1)*-127)){ + if(!pseudobuttons[cmd.axis.button.negbutton]){ + pseudobuttons[cmd.axis.button.negbutton]=1; + S9xReportButton(PseudoButtonBase+cmd.axis.button.negbutton, true); + } + } else { + if(pseudobuttons[cmd.axis.button.negbutton]){ + pseudobuttons[cmd.axis.button.negbutton]=0; + S9xReportButton(PseudoButtonBase+cmd.axis.button.negbutton, false); + } + } + return; + + case S9xButtonPort: + case S9xAxisPort: + case S9xPointerPort: + S9xHandlePortCommand(cmd, data1, data2); + return; + + case S9xButtonMulti: + if(cmd.button.multi_idx>=(int)multis.size()) return; + if(multis[cmd.button.multi_idx]->multi_press && !data1) return; + i=ApplyMulti(multis[cmd.button.multi_idx], 0, data1); + if(i>=0){ + struct exemulti *e=new struct exemulti; + e->pos=i; + e->data1=data1; + e->script=multis[cmd.button.multi_idx]; + exemultis.insert(e); + } + return; + + default: + fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type); + return; + } +} + + +static void do_polling(int mp){ + set::iterator itr; + + if(pollmap[mp].empty()) return; + for(itr=pollmap[mp].begin(); itr!=pollmap[mp].end(); itr++){ + switch(maptype(keymap[*itr].type)){ + case MAP_BUTTON: + bool pressed; + if(S9xPollButton(*itr, &pressed)) S9xReportButton(*itr, pressed); + break; + + case MAP_AXIS: + int16 value; + if(S9xPollAxis(*itr, &value)) S9xReportAxis(*itr, value); + break; + + case MAP_POINTER: + int16 x, y; + if(S9xPollPointer(*itr, &x, &y)) S9xReportPointer(*itr, x, y); + break; + + default: + break; + } + } +} + +void S9xSetJoypadLatch(bool latch){ + if(!latch && FLAG_LATCH){ + // 1 written, 'plug in' new controllers now + curcontrollers[0]=newcontrollers[0]; + curcontrollers[1]=newcontrollers[1]; + } + if(latch && !FLAG_LATCH){ + int i, j, n; + + for(n=0; n<2; n++){ + for(j=0; j<2; j++){ + read_idx[n][j]=0; + } + switch(i=curcontrollers[n]){ + case MP5: + for(j=0, i=mp5[n].pads[j]; j<4; i=mp5[n].pads[++j]){ + if(i==NONE) continue; + do_polling(i); + } + break; + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + do_polling(i); + break; + + case MOUSE0: case MOUSE1: + do_polling(i); + j=mouse[i-MOUSE0].cur_x-mouse[i-MOUSE0].old_x; + if(j<-127){ + mouse[i-MOUSE0].delta_x=0xff; + mouse[i-MOUSE0].old_x-=127; + } else if(j<0){ + mouse[i-MOUSE0].delta_x=0x80 | -j; + mouse[i-MOUSE0].old_x=mouse[i-MOUSE0].cur_x; + } else if(j>127){ + mouse[i-MOUSE0].delta_x=0x7f; + mouse[i-MOUSE0].old_x+=127; + } else { + mouse[i-MOUSE0].delta_x=j; + mouse[i-MOUSE0].old_x=mouse[i-MOUSE0].cur_x; + } + j=mouse[i-MOUSE0].cur_y-mouse[i-MOUSE0].old_y; + if(j<-127){ + mouse[i-MOUSE0].delta_y=0xff; + mouse[i-MOUSE0].old_y-=127; + } else if(j<0){ + mouse[i-MOUSE0].delta_y=0x80 | -j; + mouse[i-MOUSE0].old_y=mouse[i-MOUSE0].cur_y; + } else if(j>127){ + mouse[i-MOUSE0].delta_y=0x7f; + mouse[i-MOUSE0].old_y+=127; + } else { + mouse[i-MOUSE0].delta_y=j; + mouse[i-MOUSE0].old_y=mouse[i-MOUSE0].cur_y; + } + break; + case SUPERSCOPE: + if(superscope.next_buttons&SUPERSCOPE_FIRE){ + superscope.next_buttons&=~SUPERSCOPE_TURBO; + superscope.next_buttons|=superscope.phys_buttons&SUPERSCOPE_TURBO; + } + if(superscope.next_buttons&(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR)){ + superscope.next_buttons&=~SUPERSCOPE_OFFSCREEN; + superscope.next_buttons|=superscope.phys_buttons&SUPERSCOPE_OFFSCREEN; + } + superscope.read_buttons=superscope.next_buttons; + superscope.next_buttons&=~SUPERSCOPE_PAUSE; + if(!(superscope.phys_buttons&SUPERSCOPE_TURBO)) superscope.next_buttons&=~(SUPERSCOPE_CURSOR|SUPERSCOPE_FIRE); + do_polling(i); + break; + case TWO_JUSTIFIERS: + do_polling(TWO_JUSTIFIERS); + /* fall through */ + case ONE_JUSTIFIER: + justifier.buttons^=JUSTIFIER_SELECT; + do_polling(ONE_JUSTIFIER); + break; + default: + break; + } + } + } + FLAG_LATCH=latch; +} + +uint8 S9xReadJOYSERn(int n){ + int i, j, r; + + if(n>1) n-=0x4016; + assert(n==0 || n==1); + + uint8 bits=(OpenBus&~3)|((n==1)?0x1c:0); + + if(FLAG_LATCH){ + switch(i=curcontrollers[n]){ + case MP5: + return bits|2; + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + return bits|((joypad[i-JOYPAD0].buttons&0x8000)?1:0); + case MOUSE0: case MOUSE1: + mouse[i-MOUSE0].buttons+=0x10; + if((mouse[i-MOUSE0].buttons&0x30)==0x30) + mouse[i-MOUSE0].buttons&=0xcf; + return bits; + case SUPERSCOPE: + return bits|((superscope.read_buttons&0x80)?1:0); + case ONE_JUSTIFIER: case TWO_JUSTIFIERS: + return bits; + default: + return bits; + } + } else { + switch(i=curcontrollers[n]){ + case MP5: + r=read_idx[n][FLAG_IOBIT(n)?0:1]++; + j=FLAG_IOBIT(n)?0:2; + for(i=0; i<2; i++, j++){ + if(mp5[n].pads[j]==NONE) continue; + if(r>=16){ + bits|=1<>r))?1:0)<=16){ + read_idx[n][0]++; + return bits|1; + } else { + return bits|((joypad[i-JOYPAD0].buttons&(0x8000>>read_idx[n][0]++))?1:0); + } + case MOUSE0: case MOUSE1: + if(read_idx[n][0]<8){ + read_idx[n][0]++; + return bits; + } else if(read_idx[n][0]<16){ + return bits|((mouse[i-MOUSE0].buttons&(0x8000>>read_idx[n][0]++))?1:0); + } else if(read_idx[n][0]<24){ + return bits|((mouse[i-MOUSE0].delta_y&(0x800000>>read_idx[n][0]++))?1:0); + } else if(read_idx[n][0]<32){ + return bits|((mouse[i-MOUSE0].delta_x&(0x80000000>>read_idx[n][0]++))?1:0); + } else { + read_idx[n][0]++; + return bits|1; + } + case SUPERSCOPE: + if(read_idx[n][0]<8){ + return bits|((superscope.read_buttons&(0x80>>read_idx[n][0]++))?1:0); + } else { + read_idx[n][0]++; + return bits|1; + } + case ONE_JUSTIFIER: + if(read_idx[n][0]<24){ + return bits|((0xaa7000>>read_idx[n][0]++)&1); + } else if(read_idx[n][0]<32){ + bits|=((justifier.buttons & + (JUSTIFIER_TRIGGER|JUSTIFIER_START|JUSTIFIER_SELECT) & + (0x80000000>>read_idx[n][0]++))?1:0); + return bits; + } else { + read_idx[n][0]++; + return bits|1; + } + case TWO_JUSTIFIERS: + if(read_idx[n][0]<24){ + return bits|((0xaa7000>>read_idx[n][0]++)&1); + } else if(read_idx[n][0]<32){ + return bits|((justifier.buttons&(0x80000000>>read_idx[n][0]++))?1:0); + } else { + read_idx[n][0]++; + return bits|1; + } + default: + read_idx[n][0]++; + return bits; + } + } +} + +void S9xDoAutoJoypad(void){ + int n, i, j; + + S9xSetJoypadLatch(1); + S9xSetJoypadLatch(0); + + for(n=0; n<2; n++){ + switch(i=curcontrollers[n]){ + case MP5: + j=FLAG_IOBIT(n)?0:2; + for(i=0; i<2; i++, j++){ + if(mp5[n].pads[j]==NONE){ + WRITE_WORD(Memory.FillRAM+0x4218+n*2+i*4, 0); + } else { + WRITE_WORD(Memory.FillRAM+0x4218+n*2+i*4, joypad[mp5[n].pads[j]-JOYPAD0].buttons); + } + } + read_idx[n][FLAG_IOBIT(n)?0:1]=16; + break; + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + read_idx[n][0]=16; + WRITE_WORD(Memory.FillRAM+0x4218+n*2, joypad[i-JOYPAD0].buttons); + WRITE_WORD(Memory.FillRAM+0x421c+n*2, 0); + break; + case MOUSE0: case MOUSE1: + read_idx[n][0]=16; + WRITE_WORD(Memory.FillRAM+0x4218+n*2, mouse[i-MOUSE0].buttons); + WRITE_WORD(Memory.FillRAM+0x421c+n*2, 0); + break; + case SUPERSCOPE: + read_idx[n][0]=16; + Memory.FillRAM[0x4218+n*2]=0xff; + Memory.FillRAM[0x4219+n*2]=superscope.read_buttons; + WRITE_WORD(Memory.FillRAM+0x421c+n*2, 0); + break; + case ONE_JUSTIFIER: case TWO_JUSTIFIERS: + read_idx[n][0]=16; + WRITE_WORD(Memory.FillRAM+0x4218+n*2, 0x000e); + WRITE_WORD(Memory.FillRAM+0x421c+n*2, 0); + break; + default: + WRITE_WORD(Memory.FillRAM+0x4218+n*2, 0); + WRITE_WORD(Memory.FillRAM+0x421c+n*2, 0); + break; + } + } +} + +void S9xControlEOF(void){ + int i, j, n; + struct crosshair *c; + + PPU.GunVLatch=1000; /* i.e., never latch */ + PPU.GunHLatch=0; + + for(n=0; n<2; n++){ + switch(i=curcontrollers[n]){ + case MP5: + for(j=0, i=mp5[n].pads[j]; j<4; i=mp5[n].pads[++j]){ + if(i==NONE) continue; + if(++joypad[i-JOYPAD0].turbo_ct>=turbo_time){ + joypad[i-JOYPAD0].turbo_ct=0; + joypad[i-JOYPAD0].buttons ^= joypad[i-JOYPAD0].turbos; + } + } + break; + case JOYPAD0: case JOYPAD1: case JOYPAD2: case JOYPAD3: + case JOYPAD4: case JOYPAD5: case JOYPAD6: case JOYPAD7: + if(++joypad[i-JOYPAD0].turbo_ct>=turbo_time){ + joypad[i-JOYPAD0].turbo_ct=0; + joypad[i-JOYPAD0].buttons ^= joypad[i-JOYPAD0].turbos; + } + break; + case MOUSE0: case MOUSE1: + c=&mouse[i-MOUSE0].crosshair; + if(IPPU.RenderThisFrame) + S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, + mouse[i-MOUSE0].cur_x, mouse[i-MOUSE0].cur_y); + break; + case SUPERSCOPE: + if(n==1 && !(superscope.phys_buttons&SUPERSCOPE_OFFSCREEN)){ + if(superscope.next_buttons&(SUPERSCOPE_FIRE|SUPERSCOPE_CURSOR)) + DoGunLatch(superscope.x, superscope.y); + + c=&superscope.crosshair; + if(IPPU.RenderThisFrame) + S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, + superscope.x, superscope.y); + } + break; + case TWO_JUSTIFIERS: + if(n==1 && !justifier.offscreen[1]){ + c=&justifier.crosshair[1]; + if(IPPU.RenderThisFrame) + S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, + justifier.x[1], justifier.y[1]); + } + i=(justifier.buttons&JUSTIFIER_SELECT)?1:0; + goto do_justifier; + case ONE_JUSTIFIER: + i=(justifier.buttons&JUSTIFIER_SELECT)?-1:0; +do_justifier: + if(n==1){ + if(i>=0 && !justifier.offscreen[i]) + DoGunLatch(justifier.x[i], justifier.y[i]); + + if(!justifier.offscreen[0]){ + c=&justifier.crosshair[0]; + if(IPPU.RenderThisFrame) + S9xDrawCrosshair(S9xGetCrosshair(c->img), c->fg, c->bg, + justifier.x[0], justifier.y[0]); + } + } + break; + default: + break; + } + } + + for(n=0; n<8; n++){ + if(!pseudopointer[n].mapped) continue; + if(pseudopointer[n].H_adj){ + pseudopointer[n].x+=pseudopointer[n].H_adj; + if(pseudopointer[n].x<0) pseudopointer[n].x=0; + if(pseudopointer[n].x>255) pseudopointer[n].x=255; + if(pseudopointer[n].H_var){ + if(pseudopointer[n].H_adj<0){ + if(pseudopointer[n].H_adj>-ptrspeeds[3]) pseudopointer[n].H_adj--; + } else { + if(pseudopointer[n].H_adjPPU.ScreenHeight-1) pseudopointer[n].y=PPU.ScreenHeight-1; + if(pseudopointer[n].V_var){ + if(pseudopointer[n].V_adj<0){ + if(pseudopointer[n].V_adj>-ptrspeeds[3]) pseudopointer[n].V_adj--; + } else { + if(pseudopointer[n].V_adj::iterator it, jt; + for(it=exemultis.begin(); it!=exemultis.end(); it++){ + i=ApplyMulti((*it)->script, (*it)->pos, (*it)->data1); + if(i>=0){ + (*it)->pos=i; + } else { + jt=it; + it--; + delete *jt; + exemultis.erase(jt); + } + } + do_polling(POLL_ALL); + +#ifndef NGC + S9xMovieUpdate(); +#endif + +} + +void S9xSetControllerCrosshair(enum crosscontrols ctl, int8 idx, const char *fg, const char *bg){ + struct crosshair *c; + int8 fgcolor=-1, bgcolor=-1; + int i, j; + + if(idx<-1 || idx>31){ + fprintf(stderr, "S9xSetControllerCrosshair() called with invalid index\n"); + return; + } + + switch(ctl){ + case X_MOUSE1: c=&mouse[0].crosshair; break; + case X_MOUSE2: c=&mouse[1].crosshair; break; + case X_SUPERSCOPE: c=&superscope.crosshair; break; + case X_JUSTIFIER1: c=&justifier.crosshair[0]; break; + case X_JUSTIFIER2: c=&justifier.crosshair[1]; break; + default: + fprintf(stderr, "S9xSetControllerCrosshair() called with an invalid controller ID %d\n", ctl); + return; + } + + if(fg!=NULL){ + fgcolor=0; + if(*fg=='t'){ fg++; fgcolor=16; } + for(i=0; i<16; i++){ + for(j=0; color_names[i][j] && fg[j]==color_names[i][j]; j++); + if(isalnum(fg[j])) continue; + if(!color_names[i][j]) break; + } + fgcolor|=i; + if(i>15 || fgcolor==16){ + fprintf(stderr, "S9xSetControllerCrosshair() called with invalid fgcolor\n"); + return; + } + } + + if(bg!=NULL){ + bgcolor=0; + if(*bg=='t'){ bg++; bgcolor=16; } + for(i=0; i<16; i++){ + for(j=0; color_names[i][j] && bg[j]==color_names[i][j]; j++); + if(isalnum(bg[j])) continue; + if(!color_names[i][j]) break; + } + bgcolor|=i; + if(i>15 || bgcolor==16){ + fprintf(stderr, "S9xSetControllerCrosshair() called with invalid bgcolor\n"); + return; + } + } + + if(idx!=-1){ c->set|=1; c->img=idx; } + if(fgcolor!=-1){ c->set|=2; c->fg=fgcolor; } + if(bgcolor!=-1){c->set|=4; c->bg=bgcolor; } +} + +void S9xGetControllerCrosshair(enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg){ + struct crosshair *c; + + switch(ctl){ + case X_MOUSE1: c=&mouse[0].crosshair; break; + case X_MOUSE2: c=&mouse[1].crosshair; break; + case X_SUPERSCOPE: c=&superscope.crosshair; break; + case X_JUSTIFIER1: c=&justifier.crosshair[0]; break; + case X_JUSTIFIER2: c=&justifier.crosshair[1]; break; + default: + fprintf(stderr, "S9xGetControllerCrosshair() called with an invalid controller ID %d\n", ctl); + return; + } + + if(idx!=NULL) *idx=c->img; + if(fg!=NULL) *fg=color_names[c->fg]; + if(bg!=NULL) *bg=color_names[c->bg]; +} + +uint16 MovieGetJoypad(int i){ + if(i<0 || i>7) return 0; + return joypad[i].buttons; +} + +void MovieSetJoypad(int i, uint16 buttons){ + if(i<0 || i>7) return; + joypad[i].buttons=buttons; +} + +void S9xControlPreSave(struct SControlSnapshot *s){ + int i; + + ZeroMemory(s, sizeof(*s)); + s->ver=1; + for(i=0; i<2; i++){ + s->port1_read_idx[i]=read_idx[0][i]; + s->port2_read_idx[i]=read_idx[1][i]; + } + for(i=0; i<2; i++){ + s->mouse_speed[i]=(mouse[i].buttons&0x30)>>4; + } + s->justifier_select=((justifier.buttons&JUSTIFIER_SELECT)?1:0); +} + +void S9xControlPostLoad(struct SControlSnapshot *s){ + int i; + + if(curcontrollers[0]==MP5 && s->ver<1){ + // Crap. Old snes9x didn't support this. + S9xMessage(S9X_WARNING, S9X_FREEZE_FILE_INFO, "Old savestate has no support for MP5 in port 1."); + newcontrollers[0]=curcontrollers[0]; + curcontrollers[0]=mp5[0].pads[0]; + } + for(i=0; i<2; i++){ + read_idx[0][i]=s->port1_read_idx[i]; + read_idx[1][i]=s->port2_read_idx[i]; + } + + mouse[0].buttons|=(s->mouse_speed[0]&3)<<4; + mouse[1].buttons|=(s->mouse_speed[1]&3)<<4; + if(s->justifier_select&1){ + justifier.buttons|=JUSTIFIER_SELECT; + } else { + justifier.buttons&=~JUSTIFIER_SELECT; + } + FLAG_LATCH=(Memory.FillRAM[0x4016]&1)==1; +} diff --git a/source/snes9x/controls.h b/source/snes9x/controls.h new file mode 100644 index 0000000..e281c74 --- /dev/null +++ b/source/snes9x/controls.h @@ -0,0 +1,421 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef FOO_H +#define FOO_H + +#include "port.h" + +#define S9xNoMapping 0 +#define S9xButtonJoypad 1 +#define S9xButtonMouse 2 +#define S9xButtonSuperscope 3 +#define S9xButtonJustifier 4 +#define S9xButtonCommand 5 +#define S9xButtonMulti 6 +#define S9xAxisJoypad 7 +#define S9xPointer 8 + +#define S9xButtonPseudopointer 254 +#define S9xAxisPseudopointer 253 +#define S9xAxisPseudobuttons 252 + +// These are automatically kicked out to the S9xHandlePortCommand function. If +// your port wants to define port-specific commands or whatever, use these +// values for the s9xcommand_t type field. +#define S9xButtonPort 251 +#define S9xAxisPort 250 +#define S9xPointerPort 249 + +#define S9xBadMapping 255 +#define InvalidControlID ((uint32)-1) + +// S9xButtonPseudopointer and S9xAxisPseudopointer will report pointer motion +// using IDs PseudoPointerBase through PseudoPointerBase+7. +// S9xAxisPseudopointer command types. S9xAxisPseudobuttons will report buttons +// with IDs PseudoButtonBase to PseudoButtonBase+255. +#define PseudoPointerBase (InvalidControlID-8) +#define PseudoButtonBase (PseudoPointerBase-256) + +// Yes, this struct looks huge. But gcc makes it 6 bytes (the minimum), so it's +// not that bad. +typedef struct { + uint8 type; + uint8 multi_press:2; + uint8 button_norpt:1; + + union { + union { + struct { + uint8 idx:3; // Pad number 0-7 + uint8 toggle:1; // If set, toggle turbo/sticky for the button + uint8 turbo:1; // If set, be a 'turbo' button + uint8 sticky:1; // If set, toggle button state (on/turbo or off) + // when pressed and do nothing on release + uint16 buttons; // Which buttons to actuate. + // Use SNES_*_MASK constants from snes9x.h + } joypad; + + struct { + uint8 idx:1; // Mouse number 0-1 + uint8 left:1; // buttons + uint8 right:1; + } mouse; + + struct { + uint8 fire:1; + uint8 cursor:1; + uint8 turbo:1; + uint8 pause:1; + uint8 aim_offscreen:1; // Pretend we're pointing the gun + // offscreen (ignore the pointer) + } scope; + + struct { + uint8 idx:3; // Pseudo-pointer number 0-7 + uint8 speed_type:2; // 0=variable, 1=slow, 2=med, 3=fast + int8 UD:2; // -1=up, 1=down, 0=no vertical motion + int8 LR:2; // -1=left, 1=right, 0=no horizontal motion + } pointer; + + struct { + uint8 idx:1; // Justifier number 0-1 + uint8 trigger:1; // buttons + uint8 start:1; + uint8 aim_offscreen:1; // Pretend we're pointing the gun + // offscreen (ignore the pointer) + } justifier; + + int32 multi_idx; + uint16 command; + } button; + + union { + struct { + uint8 idx:3; // Pad number 0-7 + uint8 invert:1; // 1 = positive is Left/Up/Y/X/L + uint8 axis:3; // 0=Left/Right, 1=Up/Down, + // 2=Y/A, 3=X/B, 4=L/R + uint8 threshold; // (threshold+1)/256% deflection is a + // button press + } joypad; + + struct { + uint8 idx:3; // Pseudo-pointer number 0-7 + uint8 speed_type:2; // 0=variable, 1=slow, 2=med, 3=fast + uint8 invert:1; // 1 = invert axis, so positive is up/left + uint8 HV:1; // 0=horizontal, 1=vertical + } pointer; + + struct { + uint8 threshold; // (threshold+1)/256% deflection is a + // button press + uint8 negbutton; // Button ID for negative deflection + uint8 posbutton; // Button ID for positive deflection + } button; + } axis; + + struct { + // Which SNES-pointers to control with this pointer + uint16 aim_mouse0:1; + uint16 aim_mouse1:1; + uint16 aim_scope:1; + uint16 aim_justifier0:1; + uint16 aim_justifier1:1; + } pointer; + + uint8 port[4]; + }; +} s9xcommand_t; + + +/* Starting out... */ +void S9xUnmapAllControls(void); + +/* Setting which controllers are plugged in */ +enum controllers { + CTL_NONE, /* all ids ignored */ + CTL_JOYPAD, /* use id1 to specify 0-7 */ + CTL_MOUSE, /* use id1 to specify 0-1 */ + CTL_SUPERSCOPE, + CTL_JUSTIFIER, /* use id1: 0=one justifier, 1=two justifiers */ + CTL_MP5 /* use id1-id4 to specify pad 0-7 (or -1) */ +}; +void S9xSetController(int port, enum controllers controller, int8 id1, int8 id2, int8 id3, int8 id4); /* port=0-1 */ +void S9xGetController(int port, enum controllers *controller, int8 *id1, int8 *id2, int8 *id3, int8 *id4); +void S9xReportControllers(void); + +/* Call this when you're done with S9xSetController, or if you change any of + * the controller Settings.*Master flags. Returns true if something was + * disabled */ +bool S9xVerifyControllers(void); + +/* + * Functions for translation s9xcommand_t's into strings, and vice versa. + * free() the returned string after you're done with it. + */ +char *S9xGetCommandName(s9xcommand_t command); +s9xcommand_t S9xGetCommandT(const char *name); + +/* + * Returns an array of strings naming all the snes9x commands. Note that this + * is only the strings for S9xButtonCommand! The idea is that this would be + * used for a pull-down list in a config GUI. DO NOT free() the returned value. + */ +const char **S9xGetAllSnes9xCommands(void); + +/* + * Generic mapping functions + */ +s9xcommand_t S9xGetMapping(uint32 id); +void S9xUnmapID(uint32 id); + +/* + * Button mapping functions. If a button is mapped with poll=TRUE, then + * S9xPollButton will be called whenever snes9x feels a need for that mapping. + * Otherwise, snes9x will assume you will call S9xReportButton() whenever the + * button state changes. S9xMapButton() will fail and return FALSE if + * mapping.type isn't a S9xButton* type. + */ +bool S9xMapButton(uint32 id, s9xcommand_t mapping, bool poll); +void S9xReportButton(uint32 id, bool pressed); + +/* + * Pointer mapping functions. If a button is mapped with poll=TRUE, then + * S9xPollPointer will be called whenever snes9x feels a need for that mapping. + * Otherwise, snes9x will assume you will call S9xReportPointer() whenever the + * pointer position changes. S9xMapPointer() will fail and return FALSE if + * mapping.type isn't S9xPointer. + * + * Note that position [0,0] is considered the upper-left corner of the + * 'screen', and either [255,223] or [255,239] is the lower-right. Note that + * the SNES mouse doesn't aim at a particular point, so the SNES's idea of + * where the mouse pointer is will probably differ from your OS's idea. + */ +bool S9xMapPointer(uint32 id, s9xcommand_t mapping, bool poll); +void S9xReportPointer(uint32 id, int16 x, int16 y); + +/* + * Axis mapping functions. If a button is mapped with poll=TRUE, then + * S9xPollAxis will be called whenever snes9x feels a need for that mapping. + * Otherwise, snes9x will assume you will call S9xReportAxis() whenever the + * axis deflection changes. S9xMapAxis() will fail and return FALSE if + * mapping.type isn't a S9xAxis* type. + * + * Note that value is linear -32767 through 32767 with 0 being no + * deflection. If your axis reports differently you should transform the + * value before passing it to S9xReportAxis(). + */ +bool S9xMapAxis(uint32 id, s9xcommand_t mapping, bool poll); +void S9xReportAxis(uint32 id, int16 value); + +/* + * Do whatever the s9xcommand_t says to do. If cmd.type is a button type, data1 + * should be TRUE (non-0) or FALSE (0) to indicate whether the 'button' is + * pressed or released. If cmd.type is an axis, data1 holds the deflection + * value. If cmd.type is a pointer, data1 and data2 are the positions of the + * pointer. + */ +void S9xApplyCommand(s9xcommand_t cmd, int16 data1, int16 data2); + +/******* + * These functions are called by snes9x into your port, so each port should + * implement them. + */ + +/* + * If something was mapped with poll=TRUE, these functions will be called when + * snes9x needs the button/axis/pointer state. Fill in the reference options as + * appropriate. + */ +bool S9xPollButton(uint32 id, bool *pressed); +bool S9xPollPointer(uint32 id, int16 *x, int16 *y); +bool S9xPollAxis(uint32 id, int16 *value); + +/* + * These are called when snes9x tries to apply a command with a S9x*Port type. + * data1 and data2 are filled in like S9xApplyCommand. + */ +void S9xHandlePortCommand(s9xcommand_t cmd, int16 data1, int16 data2); + +/* These are for your use */ +s9xcommand_t S9xGetPortCommandT(const char *name); +char *S9xGetPortCommandName(s9xcommand_t command); +void S9xSetupDefaultKeymap(void); +bool8 S9xMapInput(const char *name, s9xcommand_t *cmd); + + +/******* + * These functions are called from snes9x into this subsystem. No need to use + * them from a port. + */ + +/* Use when resetting snes9x */ +void S9xControlsReset(void); +void S9xControlsSoftReset(void); + +/* Use when writing to $4016 */ +void S9xSetJoypadLatch(bool latch); + +/* Use when reading $4016/7 (JOYSER0 and JOYSER1) */ +uint8 S9xReadJOYSERn(int n); + +/* End-Of-Frame processing. Sets gun latch variables and tries to draw + * crosshairs */ +void S9xControlEOF(void); + +struct SControlSnapshot { + uint8 ver; + uint8 port1_read_idx[2]; + uint8 dummy1[4]; // for future expansion + uint8 port2_read_idx[2]; + uint8 dummy2[4]; + uint8 mouse_speed[2]; + uint8 justifier_select; + uint8 dummy3[10]; +}; + +void S9xControlPreSave(struct SControlSnapshot *s); +void S9xControlPostLoad(struct SControlSnapshot *s); + +#endif diff --git a/source/snes9x/copyright.h b/source/snes9x/copyright.h new file mode 100644 index 0000000..1079a25 --- /dev/null +++ b/source/snes9x/copyright.h @@ -0,0 +1,214 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code + * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. + * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. + * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com). + * + * DOS port code contains the works of other authors. See headers in + * individual files. + * + * Snes9x homepage: http://www.snes9x.com + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996, 1997, 1998, 1999 Gary Henderson (gary@daniver.demon.co.uk) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code (c) Copyright 1997, 1998 Ivar and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ + diff --git a/source/snes9x/cpu.cpp b/source/snes9x/cpu.cpp new file mode 100644 index 0000000..8f67a21 --- /dev/null +++ b/source/snes9x/cpu.cpp @@ -0,0 +1,417 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" +#include "dsp1.h" +#include "cpuexec.h" +#include "debug.h" +#include "apu.h" +#include "dma.h" +#include "sa1.h" + +#ifndef NGC +#include "cheats.h" +#endif + +#include "srtc.h" +#include "sdd1.h" +#include "spc7110.h" +#include "obc1.h" +#include "bsx.h" +#include "snapshot.h" + + +#ifndef ZSNES_FX +#include "fxemu.h" + +extern struct FxInit_s SuperFX; + +void S9xResetSuperFX () +{ + SuperFX.vFlags = 0; //FX_FLAG_ROM_BUFFER;// | FX_FLAG_ADDRESS_CHECKING; + // FIXME: Snes9x can't execute CPU and SuperFX at a time. Don't ask me what is 0.417 :P + SuperFX.speedPerLine = (uint32) (0.417 * 10.5e6 * ((1.0 / (float) Memory.ROMFramesPerSecond) / ((float) (Timings.V_Max)))); + //printf("SFX:%d\n", SuperFX.speedPerLine); + SuperFX.oneLineDone = FALSE; + FxReset (&SuperFX); +} +#endif + +void S9xSoftResetCPU () +{ + Registers.PBPC = 0; + Registers.PB = 0; + Registers.PCw = S9xGetWord (0xFFFC); + OpenBus = Registers.PCh; + Registers.D.W = 0; + Registers.DB = 0; + Registers.SH = 1; + Registers.SL -= 3; + Registers.XH = 0; + Registers.YH = 0; + + ICPU.ShiftedPB = 0; + ICPU.ShiftedDB = 0; + SetFlags (MemoryFlag | IndexFlag | IRQ | Emulation); + ClearFlags (Decimal); + + CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG); + CPU.BranchSkip = FALSE; + CPU.NMIActive = FALSE; + CPU.IRQActive = FALSE; + CPU.WaitingForInterrupt = FALSE; + CPU.InDMA = CPU.InWRAM_DMA = FALSE; + CPU.PCBase = NULL; + CPU.PBPCAtOpcodeStart = 0xffffffff; + CPU.WaitAddress = 0xffffffff; + CPU.WaitCounter = 0; + CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector. + CPU.V_Counter = 0; + CPU.MemSpeed = SLOW_ONE_CYCLE; + CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2; + CPU.FastROMSpeed = SLOW_ONE_CYCLE; + CPU.AutoSaveTimer = 0; + CPU.SRAMModified = FALSE; + CPU.BRKTriggered = FALSE; + //CPU.TriedInterleavedMode2 = FALSE; // Reset when ROM image loaded + + Timings.InterlaceField = FALSE; + Timings.H_Max = Timings.H_Max_Master; + Timings.V_Max = Timings.V_Max_Master; + Timings.NMITriggerPos = 0xffff; + if (Model->_5A22 == 2) + Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; + else + Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; + + CPU.WhichEvent = HC_RENDER_EVENT; + CPU.NextEvent = Timings.RenderPos; + + S9xSetPCBase (Registers.PBPC); + + ICPU.S9xOpcodes = S9xOpcodesE1; + ICPU.S9xOpLengths = S9xOpLengthsM1X1; + ICPU.CPUExecuting = TRUE; + + S9xUnpackStatus(); +} + +void S9xResetCPU () +{ + S9xSoftResetCPU (); + Registers.SL = 0xFF; + Registers.P.W = 0; + SetFlags (MemoryFlag | IndexFlag | IRQ | Emulation); + ClearFlags (Decimal); +} + +#ifdef ZSNES_FX +START_EXTERN_C +void S9xResetSuperFX (); +bool8 WinterGold = 0; +extern uint8 *C4Ram; +END_EXTERN_C +#endif + +void S9xReset (void) +{ +#ifndef NGC + S9xResetSaveTimer (FALSE); +#endif + + ZeroMemory (Memory.FillRAM, 0x8000); + memset (Memory.VRAM, 0x00, 0x10000); + memset (Memory.RAM, 0x55, 0x20000); + + if (Settings.BS) + S9xResetBSX(); + if(Settings.SPC7110) + S9xSpc7110Reset(); + S9xResetCPU (); + S9xResetPPU (); + S9xResetSRTC (); + if (Settings.SDD1) + S9xResetSDD1 (); + + S9xResetDMA (); + S9xResetAPU (); + S9xResetDSP1 (); + S9xSA1Init (); + if (Settings.C4) + S9xInitC4 (); + +#ifndef NGC + S9xInitCheatData (); +#endif + if (Settings.OBC1) + ResetOBC1(); + if (Settings.SuperFX) + S9xResetSuperFX (); +#ifdef ZSNES_FX + WinterGold = Settings.WinterGold; +#endif +// Settings.Paused = FALSE; +} + +void S9xSoftReset (void) +{ +#ifndef NGC + S9xResetSaveTimer (FALSE); +#endif + if (Settings.BS) + S9xResetBSX(); + if (Settings.SuperFX) + S9xResetSuperFX (); +#ifdef ZSNES_FX + WinterGold = Settings.WinterGold; +#endif + ZeroMemory (Memory.FillRAM, 0x8000); + memset (Memory.VRAM, 0x00, 0x10000); + // memset (Memory.RAM, 0x55, 0x20000); + + if(Settings.SPC7110) + S9xSpc7110Reset(); + S9xSoftResetCPU (); + S9xSoftResetPPU (); + S9xResetSRTC (); + if (Settings.SDD1) + S9xResetSDD1 (); + + S9xResetDMA (); + S9xResetAPU (); + S9xResetDSP1 (); + if(Settings.OBC1) + ResetOBC1(); + S9xSA1Init (); + if (Settings.C4) + S9xInitC4 (); + +#ifndef NGC + S9xInitCheatData (); +#endif + +// Settings.Paused = FALSE; +} + +uint8 S9xOpLengthsM0X0[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 + 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 + 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4 + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 + 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 + 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 + 3, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B + 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D + 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F +}; + +uint8 S9xOpLengthsM0X1[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 + 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 + 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4 + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 + 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 + 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F +}; + +uint8 S9xOpLengthsM1X0[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 + 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 + 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4 + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 + 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 + 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 + 3, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B + 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D + 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F +}; + +uint8 S9xOpLengthsM1X1[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1 + 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3 + 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4 + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5 + 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7 + 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9 + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C + 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E + 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F +}; diff --git a/source/snes9x/cpuaddr.h b/source/snes9x/cpuaddr.h new file mode 100644 index 0000000..06a8c1e --- /dev/null +++ b/source/snes9x/cpuaddr.h @@ -0,0 +1,534 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _CPUADDR_H_ +#define _CPUADDR_H_ + +typedef enum { + NONE = 0, + READ = 1, + WRITE = 2, + MODIFY = 3, + JUMP = 5, + JSR = 8 +} AccessMode; + +STATIC inline uint8 Immediate8 (AccessMode a) { + uint8 val = CPU.PCBase[Registers.PCw]; + if(a&READ) OpenBus = val; + AddCycles(CPU.MemSpeed); + Registers.PCw++; + return val; +} + +STATIC inline uint8 Immediate8Slow (AccessMode a) { + uint8 val = S9xGetByte(Registers.PBPC); + if(a&READ) OpenBus = val; + Registers.PCw++; + return val; +} + +STATIC inline uint16 Immediate16 (AccessMode a) { + uint16 val = READ_WORD(CPU.PCBase+Registers.PCw); + if(a&READ) OpenBus = (uint8)(val>>8); + AddCycles(CPU.MemSpeedx2); + Registers.PCw+=2; + return val; +} + +STATIC inline uint16 Immediate16Slow (AccessMode a) { + uint16 val = S9xGetWord(Registers.PBPC, WRAP_BANK); + if(a&READ) OpenBus = (uint8)(val>>8); + Registers.PCw+=2; + return val; +} + + +STATIC inline uint32 RelativeSlow (AccessMode a) { // branch $xx + int8 offset = Immediate8Slow(a); + return ((int16)Registers.PCw + offset) & 0xffff; +} + +STATIC inline uint32 Relative (AccessMode a) { // branch $xx + int8 offset = Immediate8(a); + return ((int16)Registers.PCw + offset) & 0xffff; +} + +STATIC inline uint32 RelativeLongSlow (AccessMode a) { // BRL $xxxx + int16 offset = Immediate16Slow(a); + return ((int32)Registers.PCw + offset) & 0xffff; +} + +STATIC inline uint32 RelativeLong (AccessMode a) { // BRL $xxxx + int16 offset = Immediate16(a); + return ((int32)Registers.PCw + offset) & 0xffff; +} + +STATIC inline uint32 AbsoluteIndexedIndirectSlow (AccessMode a) { // (a,X) + uint16 addr; + if(a&JSR){ + // JSR (a,X) pushes the old address in the middle of loading the new. + // OpenBus needs to be set to account for this. + addr = Immediate8Slow(READ); + if(a==JSR) OpenBus = Registers.PCl; + addr |= Immediate8Slow(READ)<<8; + } else { + addr = Immediate16Slow(READ); + } + AddCycles(ONE_CYCLE); + addr+=Registers.X.W; + + // Address load wraps within the bank + uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); + OpenBus = addr2>>8; + return addr2; +} + +STATIC inline uint32 AbsoluteIndexedIndirect (AccessMode a) { // (a,X) + uint16 addr = Immediate16Slow(READ); + addr+=Registers.X.W; + + // Address load wraps within the bank + uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); + OpenBus = addr2>>8; + return addr2; +} + +STATIC inline uint32 AbsoluteIndirectLongSlow (AccessMode a) { // [a] + uint16 addr = Immediate16Slow(READ); + + // No info on wrapping, but it doesn't matter anyway due to mirroring + uint32 addr2 = S9xGetWord(addr); + OpenBus=addr2>>8; + addr2 |= (OpenBus = S9xGetByte(addr+2))<<16; + return addr2; +} + +STATIC inline uint32 AbsoluteIndirectLong (AccessMode a) { // [a] + uint16 addr = Immediate16(READ); + + // No info on wrapping, but it doesn't matter anyway due to mirroring + uint32 addr2 = S9xGetWord(addr); + OpenBus=addr2>>8; + addr2 |= (OpenBus = S9xGetByte(addr+2))<<16; + return addr2; +} + +STATIC inline uint32 AbsoluteIndirectSlow (AccessMode a) { // (a) + // No info on wrapping, but it doesn't matter anyway due to mirroring + uint16 addr2 = S9xGetWord(Immediate16Slow(READ)); + OpenBus=addr2>>8; + return addr2; +} + +STATIC inline uint32 AbsoluteIndirect (AccessMode a) { // (a) + // No info on wrapping, but it doesn't matter anyway due to mirroring + uint16 addr2 = S9xGetWord(Immediate16(READ)); + OpenBus=addr2>>8; + return addr2; +} + +STATIC inline uint32 AbsoluteSlow (AccessMode a) { // a + return ICPU.ShiftedDB|Immediate16Slow(a); +} + +STATIC inline uint32 Absolute (AccessMode a) { // a + return ICPU.ShiftedDB|Immediate16(a); +} + +STATIC inline uint32 AbsoluteLongSlow (AccessMode a) { // l + uint32 addr = Immediate16Slow(READ); + + // JSR l pushes the old bank in the middle of loading the new. + // OpenBus needs to be set to account for this. + if(a==JSR) OpenBus = Registers.PB; + + addr |= Immediate8Slow(a)<<16; + return addr; +} + +STATIC inline uint32 AbsoluteLong (AccessMode a) { // l + uint32 addr = READ_3WORD(CPU.PCBase+Registers.PCw); + AddCycles(CPU.MemSpeedx2+CPU.MemSpeed); + if(a&READ) OpenBus = addr>>16; + Registers.PCw+=3; + return addr; +} + +STATIC inline uint32 DirectSlow (AccessMode a) { // d + uint16 addr = Immediate8Slow(a) + Registers.D.W; + if(Registers.DL!=0) AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 Direct (AccessMode a) { // d + uint16 addr = Immediate8(a) + Registers.D.W; + if(Registers.DL!=0) AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 DirectIndirectSlow (AccessMode a) { // (d) + uint32 addr = S9xGetWord(DirectSlow(READ), + (!CheckEmulation() || Registers.DL)?WRAP_BANK:WRAP_PAGE); + if(a&READ) OpenBus=(uint8)(addr>>8); + addr |= ICPU.ShiftedDB; + return addr; +} + +STATIC inline uint32 DirectIndirectE0 (AccessMode a) { // (d) + uint32 addr = S9xGetWord(Direct(READ)); + if(a&READ) OpenBus = (uint8)(addr>>8); + addr |= ICPU.ShiftedDB; + return addr; +} + +STATIC inline uint32 DirectIndirectE1 (AccessMode a) { // (d) + uint32 addr = S9xGetWord(DirectSlow(READ), + Registers.DL?WRAP_BANK:WRAP_PAGE); + if(a&READ) OpenBus=(uint8)(addr>>8); + addr |= ICPU.ShiftedDB; + return addr; +} + +STATIC inline uint32 DirectIndirectIndexedSlow (AccessMode a) { // (d),Y + uint32 addr = DirectIndirectSlow(a); + if(a&WRITE || !CheckIndex() || (addr&0xff)+Registers.YL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 DirectIndirectIndexedE0X0 (AccessMode a) { // (d),Y + uint32 addr = DirectIndirectE0(a); + AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 DirectIndirectIndexedE0X1 (AccessMode a) { // (d),Y + uint32 addr = DirectIndirectE0(a); + if(a&WRITE || (addr&0xff)+Registers.YL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 DirectIndirectIndexedE1 (AccessMode a) { // (d),Y + uint32 addr = DirectIndirectE1(a); + if(a&WRITE || (addr&0xff)+Registers.YL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 DirectIndirectLongSlow (AccessMode a) { // [d] + uint16 addr = DirectSlow(READ); + uint32 addr2 = S9xGetWord(addr); + OpenBus=addr2>>8; + addr2 |= (OpenBus = S9xGetByte(addr+2))<<16; + return addr2; +} + +STATIC inline uint32 DirectIndirectLong (AccessMode a) { // [d] + uint16 addr = Direct(READ); + uint32 addr2 = S9xGetWord(addr); + OpenBus=addr2>>8; + addr2 |= (OpenBus = S9xGetByte(addr+2))<<16; + return addr2; +} + +STATIC inline uint32 DirectIndirectIndexedLongSlow (AccessMode a) { // [d],Y + return DirectIndirectLongSlow(a) + Registers.Y.W; +} + +STATIC inline uint32 DirectIndirectIndexedLong (AccessMode a) { // [d],Y + return DirectIndirectLong(a) + Registers.Y.W; +} + +STATIC inline uint32 DirectIndexedXSlow (AccessMode a) { // d,X + pair addr; + addr.W = DirectSlow(a); + if(!CheckEmulation() || Registers.DL){ + addr.W+=Registers.X.W; + } else { + addr.B.l+=Registers.XL; + } + AddCycles(ONE_CYCLE); + return addr.W; +} + +STATIC inline uint32 DirectIndexedXE0 (AccessMode a) { // d,X + uint16 addr = Direct(a) + Registers.X.W; + AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 DirectIndexedXE1 (AccessMode a) { // d,X + if(Registers.DL){ + return DirectIndexedXE0(a); + } else { + pair addr; + addr.W = Direct(a); + addr.B.l+=Registers.XL; + AddCycles(ONE_CYCLE); + return addr.W; + } +} + +STATIC inline uint32 DirectIndexedYSlow (AccessMode a) { // d,Y + pair addr; + addr.W = DirectSlow(a); + if(!CheckEmulation() || Registers.DL){ + addr.W+=Registers.Y.W; + } else { + addr.B.l+=Registers.YL; + } + AddCycles(ONE_CYCLE); + return addr.W; +} + +STATIC inline uint32 DirectIndexedYE0 (AccessMode a) { // d,Y + uint16 addr = Direct(a) + Registers.Y.W; + AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 DirectIndexedYE1 (AccessMode a) { // d,Y + if(Registers.DL){ + return DirectIndexedYE0(a); + } else { + pair addr; + addr.W = Direct(a); + addr.B.l+=Registers.YL; + AddCycles(ONE_CYCLE); + return addr.W; + } +} + +STATIC inline uint32 DirectIndexedIndirectSlow (AccessMode a) { // (d,X) + uint32 addr = S9xGetWord(DirectIndexedXSlow(READ), + (!CheckEmulation() || Registers.DL)?WRAP_BANK:WRAP_PAGE); + if(a&READ) OpenBus=(uint8)(addr>>8); + return ICPU.ShiftedDB|addr; +} + +STATIC inline uint32 DirectIndexedIndirectE0 (AccessMode a) { // (d,X) + uint32 addr = S9xGetWord(DirectIndexedXE0(READ)); + if(a&READ) OpenBus = (uint8)(addr>>8); + return ICPU.ShiftedDB|addr; +} + +STATIC inline uint32 DirectIndexedIndirectE1 (AccessMode a) { // (d,X) + uint32 addr = S9xGetWord(DirectIndexedXE1(READ), + Registers.DL?WRAP_BANK:WRAP_PAGE); + if(a&READ) OpenBus=(uint8)(addr>>8); + return ICPU.ShiftedDB|addr; +} + +STATIC inline uint32 AbsoluteIndexedXSlow (AccessMode a) { // a,X + uint32 addr = AbsoluteSlow(a); + if(a&WRITE || !CheckIndex() || (addr&0xff)+Registers.XL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.X.W); +} + +STATIC inline uint32 AbsoluteIndexedXX0 (AccessMode a) { // a,X + uint32 addr = Absolute(a); + AddCycles(ONE_CYCLE); + return (addr + Registers.X.W); +} + +STATIC inline uint32 AbsoluteIndexedXX1 (AccessMode a) { // a,X + uint32 addr = Absolute(a); + if(a&WRITE || (addr&0xff)+Registers.XL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.X.W); +} + +STATIC inline uint32 AbsoluteIndexedYSlow (AccessMode a) { // a,Y + uint32 addr = AbsoluteSlow(a); + if(a&WRITE || !CheckIndex() || (addr&0xff)+Registers.YL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 AbsoluteIndexedYX0 (AccessMode a) { // a,Y + uint32 addr = Absolute(a); + AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 AbsoluteIndexedYX1 (AccessMode a) { // a,Y + uint32 addr = Absolute(a); + if(a&WRITE || (addr&0xff)+Registers.YL>=0x100) AddCycles(ONE_CYCLE); + return (addr + Registers.Y.W); +} + +STATIC inline uint32 AbsoluteLongIndexedXSlow (AccessMode a) { // l,X + return (AbsoluteLongSlow(a) + Registers.X.W); +} + +STATIC inline uint32 AbsoluteLongIndexedX (AccessMode a) { // l,X + return (AbsoluteLong(a) + Registers.X.W); +} + +STATIC inline uint32 StackRelativeSlow (AccessMode a) { // d,S + uint16 addr = Immediate8Slow(a) + Registers.S.W; + AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 StackRelative (AccessMode a) { // d,S + uint16 addr = Immediate8(a) + Registers.S.W; + AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 StackRelativeIndirectIndexedSlow (AccessMode a) { // (d,S),Y + uint32 addr=S9xGetWord(StackRelativeSlow(READ)); + if(a&READ) OpenBus = (uint8)(addr>>8); + addr = (addr+Registers.Y.W+ICPU.ShiftedDB)&0xffffff; + AddCycles(ONE_CYCLE); + return addr; +} + +STATIC inline uint32 StackRelativeIndirectIndexed (AccessMode a) { // (d,S),Y + uint32 addr=S9xGetWord(StackRelative(READ)); + if(a&READ) OpenBus = (uint8)(addr>>8); + addr = (addr+Registers.Y.W+ICPU.ShiftedDB)&0xffffff; + AddCycles(ONE_CYCLE); + return addr; +} +#endif + diff --git a/source/snes9x/cpuexec.cpp b/source/snes9x/cpuexec.cpp new file mode 100644 index 0000000..6b7887c --- /dev/null +++ b/source/snes9x/cpuexec.cpp @@ -0,0 +1,517 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "cpuops.h" +#include "ppu.h" +#include "cpuexec.h" +#include "debug.h" +#include "snapshot.h" +#include "gfx.h" +#include "missing.h" +#include "apu.h" +#include "dma.h" +#include "sa1.h" +#include "spc7110.h" + +#ifndef ZSNES_FX +#include "fxemu.h" +extern struct FxInit_s SuperFX; +#endif + +void S9xMainLoop (void) +{ + for (;;) + { + APU_EXECUTE(); + + if (CPU.Flags) + { + if (CPU.Flags & NMI_FLAG) + { + if (Timings.NMITriggerPos <= CPU.Cycles) + { + CPU.Flags &= ~NMI_FLAG; + Timings.NMITriggerPos = 0xffff; + if (CPU.WaitingForInterrupt) + { + CPU.WaitingForInterrupt = FALSE; + Registers.PCw++; + } + + S9xOpcode_NMI(); + } + } + +#ifdef DEBUGGER + if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) + { + for (int Break = 0; Break != 6; Break++) + { + if (S9xBreakpoint[Break].Enabled && + S9xBreakpoint[Break].Bank == Registers.PB && + S9xBreakpoint[Break].Address == Registers.PCw) + { + if (S9xBreakpoint[Break].Enabled == 2) + S9xBreakpoint[Break].Enabled = TRUE; + else + CPU.Flags |= DEBUG_MODE_FLAG; + } + } + } +#endif + + CHECK_SOUND(); + + if (CPU.Flags & IRQ_PENDING_FLAG) + { + if (CPU.WaitingForInterrupt) + { + CPU.WaitingForInterrupt = FALSE; + Registers.PCw++; + } + + if (CPU.IRQActive && !Settings.DisableIRQ) + { + if (!CheckFlag(IRQ)) + S9xOpcode_IRQ(); + } + else + CPU.Flags &= ~IRQ_PENDING_FLAG; + } + + if (CPU.Flags & SCAN_KEYS_FLAG) + break; + +#ifdef DEBUGGER + if (CPU.Flags & DEBUG_MODE_FLAG) + break; + + if (CPU.Flags & TRACE_FLAG) + S9xTrace(); + + if (CPU.Flags & SINGLE_STEP_FLAG) + { + CPU.Flags &= ~SINGLE_STEP_FLAG; + CPU.Flags |= DEBUG_MODE_FLAG; + } +#endif + } + +#ifdef CPU_SHUTDOWN + CPU.PBPCAtOpcodeStart = Registers.PBPC; +#endif + + register uint8 Op; + register struct SOpcodes *Opcodes; + + if (CPU.PCBase) + { + Op = CPU.PCBase[Registers.PCw]; + CPU.Cycles += CPU.MemSpeed; + Opcodes = ICPU.S9xOpcodes; + } + else + { + Op = S9xGetByte(Registers.PBPC); + OpenBus = Op; + Opcodes = S9xOpcodesSlow; + } + + if ((Registers.PCw&MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) + { + uint8 *oldPCBase = CPU.PCBase; + + CPU.PCBase = GetBasePointer(ICPU.ShiftedPB + ((uint16) (Registers.PCw + 4))); + if (oldPCBase!=CPU.PCBase || (Registers.PCw&~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) + Opcodes = S9xOpcodesSlow; + } + + Registers.PCw++; + (*Opcodes[Op].S9xOpcode)(); + + S9xUpdateAPUTimer(); + + if (SA1.Executing) + S9xSA1MainLoop(); + + if (CPU.Cycles >= CPU.NextEvent) + S9xDoHEventProcessing(); + } + + S9xPackStatus(); + APURegisters.PC = IAPU.PC - IAPU.RAM; + S9xAPUPackStatus(); + + if (CPU.Flags & SCAN_KEYS_FLAG) + { +#ifdef DEBUGGER + if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) +#endif + S9xSyncSpeed(); + CPU.Flags &= ~SCAN_KEYS_FLAG; + } +} + +void S9xSetIRQ (uint32 source) +{ + CPU.IRQActive |= source; + CPU.Flags |= IRQ_PENDING_FLAG; + + if (CPU.WaitingForInterrupt) + { + // Force IRQ to trigger immediately after WAI - + // Final Fantasy Mystic Quest crashes without this. + CPU.WaitingForInterrupt = FALSE; + Registers.PCw++; + } +} + +void S9xClearIRQ (uint32 source) +{ + CLEAR_IRQ_SOURCE(source); +} + +void S9xDoHEventProcessing (void) +{ +#ifdef CPU_SHUTDOWN + CPU.WaitCounter++; +#endif + switch (CPU.WhichEvent) + { + case HC_HBLANK_START_EVENT: + S9xCheckMissingHTimerPosition(Timings.HBlankStart); + + break; + + case HC_HDMA_START_EVENT: + if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) + IPPU.HDMA = S9xDoHDMA(IPPU.HDMA); + + S9xCheckMissingHTimerPosition(Timings.HDMAStart); + + break; + + case HC_HCOUNTER_MAX_EVENT: + #ifndef ZSNES_FX + if (Settings.SuperFX) + { + if (!SuperFX.oneLineDone) + S9xSuperFXExec(); + SuperFX.oneLineDone = FALSE; + } + #else + S9xSuperFXExec(); + #endif + + #ifndef STORM + if (Settings.SoundSync) + S9xGenerateSound(); + #endif + + CPU.Cycles -= Timings.H_Max; + IAPU.NextAPUTimerPos -= (Timings.H_Max << SNES_APUTIMER_ACCURACY); + if (IAPU.APUExecuting) + APU.Cycles -= Timings.H_Max; + else + APU.Cycles = 0; + if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max)) + Timings.NMITriggerPos -= Timings.H_Max; + + ICPU.Scanline++; + + CPU.V_Counter++; + if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1 + { + CPU.V_Counter = 0; + Timings.InterlaceField ^= 1; + + // From byuu: + // [NTSC] + // interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd. + // non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames. + // [PAL] + // interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd. + // non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames. + if (IPPU.Interlace && !Timings.InterlaceField) + Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL) + else + Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL) + + Memory.FillRAM[0x213F] ^= 0x80; + PPU.RangeTimeOver = 0; + + // FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles. + Memory.FillRAM[0x4210] = Model->_5A22; + CPU.Flags &= ~NMI_FLAG; + Timings.NMITriggerPos = 0xffff; + + ICPU.Frame++; + PPU.HVBeamCounterLatched = 0; + CPU.Flags |= SCAN_KEYS_FLAG; + } + + // From byuu: + // In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame. + // On odd frames, scanline 240 is one dot short. + // In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines, + // and odd frames have 262 scanlines. + // Interlace mode scanline 240 on odd frames is not missing a dot. + if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240 + Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360 + else + Timings.H_Max = Timings.H_Max_Master; // HC=1364 + + if (Model->_5A22 == 2) + { + if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240 + { + if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534 + Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538 + else + Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534 + } + } + else + Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1; + + S9xCheckMissingHTimerPosition(0); + + if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240). + { + S9xEndScreenRefresh(); + IPPU.HDMA = 0; + // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. + #ifdef DEBUGGER + missing.dma_this_frame = 0; + #endif + IPPU.MaxBrightness = PPU.Brightness; + PPU.ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1; + + if (!PPU.ForcedBlanking) + { + PPU.OAMAddr = PPU.SavedOAMAddr; + + uint8 tmp = 0; + + if (PPU.OAMPriorityRotation) + tmp = (PPU.OAMAddr & 0xFE) >> 1; + if ((PPU.OAMFlip & 1) || PPU.FirstSprite!=tmp) + { + PPU.FirstSprite = tmp; + IPPU.OBJChanged = TRUE; + } + + PPU.OAMFlip = 0; + } + + // FIXME: writing to $4210 will wait 6 cycles. + Memory.FillRAM[0x4210] = 0x80 | Model->_5A22; + if (Memory.FillRAM[0x4200] & 0x80) + { + // FIXME: triggered at HC=6, checked just before the final CPU cycle, + // then, when to call S9xOpcode_NMI()? + CPU.Flags |= NMI_FLAG; + Timings.NMITriggerPos = 6 + 6; + } + + } + + if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true + S9xDoAutoJoypad(); + + if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1 + S9xStartScreenRefresh(); + + CPU.NextEvent = -1; + + break; + + case HC_HDMA_INIT_EVENT: + if (CPU.V_Counter == 0) + S9xStartHDMA(); + + S9xCheckMissingHTimerPosition(Timings.HDMAInit); + + break; + + case HC_RENDER_EVENT: + if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight) + RenderLine(CPU.V_Counter - FIRST_VISIBLE_LINE); + + S9xCheckMissingHTimerPosition(Timings.RenderPos); + + break; + + case HC_WRAM_REFRESH_EVENT: + if (!CPU.InDMA) + { + S9xCheckMissingHTimerPositionRange(Timings.WRAMRefreshPos, SNES_WRAM_REFRESH_CYCLES); + CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; + S9xUpdateAPUTimer(); + APU_EXECUTE(); + } + else + S9xCheckMissingHTimerPosition(Timings.WRAMRefreshPos); + + break; + + case HC_IRQ_1_3_EVENT: + case HC_IRQ_3_5_EVENT: + case HC_IRQ_5_7_EVENT: + case HC_IRQ_7_9_EVENT: + case HC_IRQ_9_A_EVENT: + case HC_IRQ_A_1_EVENT: + if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition))) + S9xSetIRQ(PPU_H_BEAM_IRQ_SOURCE); + else + if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition)) + S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE); + + break; + } + + S9xReschedule(); +} diff --git a/source/snes9x/cpuexec.h b/source/snes9x/cpuexec.h new file mode 100644 index 0000000..11d47a8 --- /dev/null +++ b/source/snes9x/cpuexec.h @@ -0,0 +1,341 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _CPUEXEC_H_ +#define _CPUEXEC_H_ + +#include "snes9x.h" + +struct SOpcodes { +#ifdef __WIN32__ + void (__cdecl *S9xOpcode)( void); +#else + void (*S9xOpcode)( void); +#endif +}; + +struct SICPU +{ + uint8 *Speed; + struct SOpcodes *S9xOpcodes; + uint8 *S9xOpLengths; + uint8 _Carry; + uint8 _Zero; + uint8 _Negative; + uint8 _Overflow; + bool8 CPUExecuting; + uint32 ShiftedPB; + uint32 ShiftedDB; + uint32 Frame; + uint32 Scanline; + uint32 FrameAdvanceCount; +}; + +START_EXTERN_C +extern struct SICPU ICPU; +END_EXTERN_C + +#include "ppu.h" +#include "memmap.h" +#include "65c816.h" + +START_EXTERN_C +void S9xMainLoop (void); +void S9xReset (void); +void S9xSoftReset (void); +void S9xDoHEventProcessing (); +void S9xClearIRQ (uint32); +void S9xSetIRQ (uint32); + +extern struct SOpcodes S9xOpcodesE1 [256]; +extern struct SOpcodes S9xOpcodesM1X1 [256]; +extern struct SOpcodes S9xOpcodesM1X0 [256]; +extern struct SOpcodes S9xOpcodesM0X1 [256]; +extern struct SOpcodes S9xOpcodesM0X0 [256]; +extern struct SOpcodes S9xOpcodesSlow [256]; +extern uint8 S9xOpLengthsM1X1 [256]; +extern uint8 S9xOpLengthsM1X0 [256]; +extern uint8 S9xOpLengthsM0X1 [256]; +extern uint8 S9xOpLengthsM0X0 [256]; +END_EXTERN_C + +STATIC inline void S9xUnpackStatus() +{ + ICPU._Zero = (Registers.PL & Zero) == 0; + ICPU._Negative = (Registers.PL & Negative); + ICPU._Carry = (Registers.PL & Carry); + ICPU._Overflow = (Registers.PL & Overflow) >> 6; +} + +STATIC inline void S9xPackStatus() +{ + Registers.PL &= ~(Zero | Negative | Carry | Overflow); + Registers.PL |= ICPU._Carry | ((ICPU._Zero == 0) << 1) | + (ICPU._Negative & 0x80) | (ICPU._Overflow << 6); +} + +STATIC inline void CLEAR_IRQ_SOURCE (uint32 M) +{ + CPU.IRQActive &= ~M; + if (!CPU.IRQActive) + CPU.Flags &= ~IRQ_PENDING_FLAG; +} + +STATIC inline void S9xFixCycles () +{ + if (CheckEmulation ()) + { + ICPU.S9xOpcodes = S9xOpcodesE1; + ICPU.S9xOpLengths = S9xOpLengthsM1X1; + } + else + if (CheckMemory ()) + { + if (CheckIndex ()) + { + ICPU.S9xOpcodes = S9xOpcodesM1X1; + ICPU.S9xOpLengths = S9xOpLengthsM1X1; + } + else + { + ICPU.S9xOpcodes = S9xOpcodesM1X0; + ICPU.S9xOpLengths = S9xOpLengthsM1X0; + } + } + else + { + if (CheckIndex ()) + { + ICPU.S9xOpcodes = S9xOpcodesM0X1; + ICPU.S9xOpLengths = S9xOpLengthsM0X1; + } + else + { + ICPU.S9xOpcodes = S9xOpcodesM0X0; + ICPU.S9xOpLengths = S9xOpLengthsM0X0; + } + } +} + +STATIC inline void S9xReschedule (void) +{ + uint8 next = 0; + int32 hpos = 0; + + switch (CPU.WhichEvent) + { + case HC_HBLANK_START_EVENT: + case HC_IRQ_1_3_EVENT: + next = HC_HDMA_START_EVENT; + hpos = Timings.HDMAStart; + break; + + case HC_HDMA_START_EVENT: + case HC_IRQ_3_5_EVENT: + next = HC_HCOUNTER_MAX_EVENT; + hpos = Timings.H_Max; + break; + + case HC_HCOUNTER_MAX_EVENT: + case HC_IRQ_5_7_EVENT: + next = HC_HDMA_INIT_EVENT; + hpos = Timings.HDMAInit; + break; + + case HC_HDMA_INIT_EVENT: + case HC_IRQ_7_9_EVENT: + next = HC_RENDER_EVENT; + hpos = Timings.RenderPos; + break; + + case HC_RENDER_EVENT: + case HC_IRQ_9_A_EVENT: + next = HC_WRAM_REFRESH_EVENT; + hpos = Timings.WRAMRefreshPos; + break; + + case HC_WRAM_REFRESH_EVENT: + case HC_IRQ_A_1_EVENT: + next = HC_HBLANK_START_EVENT; + hpos = Timings.HBlankStart; + break; + } + + if (((int32) PPU.HTimerPosition > CPU.NextEvent) && ((int32) PPU.HTimerPosition < hpos)) + { + hpos = (int32) PPU.HTimerPosition; + + switch (next) + { + case HC_HDMA_START_EVENT: + next = HC_IRQ_1_3_EVENT; + break; + + case HC_HCOUNTER_MAX_EVENT: + next = HC_IRQ_3_5_EVENT; + break; + + case HC_HDMA_INIT_EVENT: + next = HC_IRQ_5_7_EVENT; + break; + + case HC_RENDER_EVENT: + next = HC_IRQ_7_9_EVENT; + break; + + case HC_WRAM_REFRESH_EVENT: + next = HC_IRQ_9_A_EVENT; + break; + + case HC_HBLANK_START_EVENT: + next = HC_IRQ_A_1_EVENT; + break; + } + } + + CPU.NextEvent = hpos; + CPU.WhichEvent = next; +} + +#endif diff --git a/source/snes9x/cpumacro.h b/source/snes9x/cpumacro.h new file mode 100644 index 0000000..ebd8b90 --- /dev/null +++ b/source/snes9x/cpumacro.h @@ -0,0 +1,781 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _CPUMACRO_H_ +#define _CPUMACRO_H_ + +#define rOP8(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \ + FUNC(val); \ + } + +#define rOP16(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + uint16 val = S9xGetWord(ADDR(READ), WRAP); \ + OpenBus = (uint8)(val>>8); \ + FUNC(val); \ + } + +#define rOPC(OP, COND, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + if(Check##COND()){ \ + uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \ + FUNC(val); \ + } else { \ + uint16 val = S9xGetWord(ADDR(READ), WRAP); \ + OpenBus = (uint8)(val>>8); \ + FUNC(val); \ + } \ + } + +#define rOPM(OP, ADDR, WRAP, FUNC) \ + rOPC(OP, Memory, ADDR, WRAP, FUNC) + +#define rOPX(OP, ADDR, WRAP, FUNC) \ + rOPC(OP, Index, ADDR, WRAP, FUNC) + + +#define wOP8(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + FUNC##8 (ADDR(WRITE)); \ + } + +#define wOP16(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + FUNC##16 (ADDR(WRITE), WRAP); \ + } + +#define wOPC(OP, COND, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + if(Check##COND()){ \ + FUNC##8 (ADDR(WRITE)); \ + } else { \ + FUNC##16 (ADDR(WRITE), WRAP); \ + } \ + } + +#define wOPM(OP, ADDR, WRAP, FUNC) \ + wOPC(OP, Memory, ADDR, WRAP, FUNC) + +#define wOPX(OP, ADDR, WRAP, FUNC) \ + wOPC(OP, Index, ADDR, WRAP, FUNC) + + +#define mOP8(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + FUNC##8 (ADDR(MODIFY)); \ + } + +#define mOP16(OP, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + FUNC##16 (ADDR(MODIFY), WRAP); \ + } + +#define mOPC(OP, COND, ADDR, WRAP, FUNC) \ + static void Op##OP (void) { \ + if(Check##COND()){ \ + FUNC##8 (ADDR(MODIFY)); \ + } else { \ + FUNC##16 (ADDR(MODIFY), WRAP); \ + } \ + } + +#define mOPM(OP, ADDR, WRAP, FUNC) \ + mOPC(OP, Memory, ADDR, WRAP, FUNC) + + +#define bOP(OP, COND, CHK, E) \ + static void Op##OP (void) { \ + pair newPC; \ + newPC.W = Relative(JUMP); \ + BranchCheck##CHK (); \ + if(COND){ \ + AddCycles(ONE_CYCLE); \ + if(E && Registers.PCh!=newPC.B.h){AddCycles(ONE_CYCLE);} \ + if((Registers.PCw&~MEMMAP_MASK)!=(newPC.W&~MEMMAP_MASK)){ \ + S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \ + } else { \ + Registers.PCw = newPC.W; \ + } \ + CPUShutdown (); \ + } \ + } + + +STATIC inline void SetZN (uint16 Work) { + ICPU._Zero = Work != 0; + ICPU._Negative = (uint8) (Work >> 8); +} + +STATIC inline void SetZN (uint8 Work) { + ICPU._Zero = Work; + ICPU._Negative = Work; +} + +STATIC inline void ADC (uint8 Work8) { + if(CheckDecimal()) { + uint8 A1 = Registers.A.W & 0x0F; + uint16 A2 = Registers.A.W & 0xF0; + uint8 W1 = Work8 & 0x0F; + uint8 W2 = Work8 & 0xF0; + + A1 += W1+CheckCarry(); + if(A1>0x09){ + A1-=0x0A; + A1&=0x0F; + A2+=0x10; + } + + A2 += W2; + if(A2>0x90){ + A2-=0xA0; + A2&=0xF0; + SetCarry(); + } else { + ClearCarry(); + } + + uint8 Ans8 = A2|A1; + if (~(Registers.AL ^ Work8) & + (Work8 ^ Ans8) & 0x80) + SetOverflow(); + else + ClearOverflow(); + Registers.AL = Ans8; + SetZN (Registers.AL); + } else { + uint16 Ans16 = Registers.AL + Work8 + CheckCarry(); + + ICPU._Carry = Ans16 >= 0x100; + + if (~(Registers.AL ^ Work8) & + (Work8 ^ (uint8) Ans16) & 0x80) + SetOverflow(); + else + ClearOverflow(); + Registers.AL = (uint8) Ans16; + SetZN (Registers.AL); + } +} + +STATIC inline void ADC (uint16 Work16) { + if (CheckDecimal ()) { + uint16 A1 = Registers.A.W & 0x000F; + uint16 A2 = Registers.A.W & 0x00F0; + uint16 A3 = Registers.A.W & 0x0F00; + uint32 A4 = Registers.A.W & 0xF000; + uint16 W1 = Work16 & 0x000F; + uint16 W2 = Work16 & 0x00F0; + uint16 W3 = Work16 & 0x0F00; + uint16 W4 = Work16 & 0xF000; + + A1 += W1 + CheckCarry (); + if(A1>0x0009) { + A1 -= 0x000A; + A1 &= 0x000F; + A2 += 0x0010; + } + + A2 += W2; + if(A2>0x0090){ + A2 -= 0x00A0; + A2 &= 0x00F0; + A3 += 0x0100; + } + + A3 += W3; + if(A3>0x0900){ + A3 -= 0x0A00; + A3 &= 0x0F00; + A4 += 0x1000; + } + + A4 += W4; + if(A4>0x9000){ + A4 -= 0xA000; + A4 &= 0xF000; + SetCarry (); + } else { + ClearCarry (); + } + + uint16 Ans16 = A4|A3|A2|A1; + if (~(Registers.A.W ^ Work16) & + (Work16 ^ Ans16) & 0x8000) + SetOverflow(); + else + ClearOverflow(); + Registers.A.W = Ans16; + SetZN (Registers.A.W); + } else { + uint32 Ans32 = Registers.A.W + Work16 + CheckCarry(); + + ICPU._Carry = Ans32 >= 0x10000; + + if (~(Registers.A.W ^ Work16) & + (Work16 ^ (uint16) Ans32) & 0x8000) + SetOverflow(); + else + ClearOverflow(); + Registers.A.W = (uint16) Ans32; + SetZN (Registers.A.W); + } +} + +STATIC inline void AND (uint16 Work16) { + Registers.A.W &= Work16; + SetZN (Registers.A.W); +} + +STATIC inline void AND (uint8 Work8) { + Registers.AL &= Work8; + SetZN (Registers.AL); +} + +STATIC inline void ASL16 (uint32 OpAddress, s9xwrap_t w) { + uint16 Work16 = S9xGetWord (OpAddress, w); + ICPU._Carry = (Work16 & 0x8000) != 0; + Work16 <<= 1; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = (Work16&0xff); + SetZN (Work16); +} + +STATIC inline void ASL8 (uint32 OpAddress) { + uint8 Work8 = S9xGetByte (OpAddress); + ICPU._Carry = (Work8 & 0x80) != 0; + Work8 <<= 1; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; + SetZN (Work8); +} + +STATIC inline void BIT (uint16 Work16) { + ICPU._Overflow = (Work16 & 0x4000) != 0; + ICPU._Negative = (uint8) (Work16 >> 8); + ICPU._Zero = (Work16 & Registers.A.W) != 0; +} + +STATIC inline void BIT (uint8 Work8) { + ICPU._Overflow = (Work8 & 0x40) != 0; + ICPU._Negative = Work8; + ICPU._Zero = Work8 & Registers.AL; +} + +STATIC inline void CMP (uint16 val) { + int32 Int32 = (int32) Registers.A.W - (int32) val; + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +STATIC inline void CMP (uint8 val) { + int16 Int16 = (int16) Registers.AL - (int16) val; + ICPU._Carry = Int16 >= 0; + SetZN ((uint8) Int16); +} + +STATIC inline void CPX (uint16 val) { + int32 Int32 = (int32) Registers.X.W - (int32) val; + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +STATIC inline void CPX (uint8 val) { + int16 Int16 = (int16) Registers.XL - (int16) val; + ICPU._Carry = Int16 >= 0; + SetZN ((uint8) Int16); +} + +STATIC inline void CPY (uint16 val) { + int32 Int32 = (int32) Registers.Y.W - (int32) val; + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +STATIC inline void CPY (uint8 val) { + int16 Int16 = (int16) Registers.YL - (int16) val; + ICPU._Carry = Int16 >= 0; + SetZN ((uint8) Int16); +} + +STATIC inline void DEC16 (uint32 OpAddress, s9xwrap_t w) { +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + + uint16 Work16 = S9xGetWord(OpAddress, w) - 1; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = Work16&0xff; + SetZN (Work16); +} + +STATIC inline void DEC8 (uint32 OpAddress) { +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + + uint8 Work8 = S9xGetByte (OpAddress) - 1; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; + SetZN (Work8); +} + +STATIC inline void EOR (uint16 val) { + Registers.A.W ^= val; + SetZN (Registers.A.W); +} + +STATIC inline void EOR (uint8 val) { + Registers.AL ^= val; + SetZN (Registers.AL); +} + +STATIC inline void INC16 (uint32 OpAddress, s9xwrap_t w) { +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + + uint16 Work16 = S9xGetWord(OpAddress, w) + 1; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = Work16&0xff; + SetZN (Work16); +} + +STATIC inline void INC8 (uint32 OpAddress) { +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + + uint8 Work8 = S9xGetByte (OpAddress) + 1; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; + SetZN (Work8); +} + +STATIC inline void LDA (uint16 val) { + Registers.A.W = val; + SetZN (Registers.A.W); +} + +STATIC inline void LDA (uint8 val) { + Registers.AL = val; + SetZN (Registers.AL); +} + +STATIC inline void LDX (uint16 val) { + Registers.X.W = val; + SetZN (Registers.X.W); +} + +STATIC inline void LDX (uint8 val) { + Registers.XL = val; + SetZN (Registers.XL); +} + +STATIC inline void LDY (uint16 val) { + Registers.Y.W = val; + SetZN (Registers.Y.W); +} + +STATIC inline void LDY (uint8 val) { + Registers.YL = val; + SetZN (Registers.YL); +} + +STATIC inline void LSR16 (uint32 OpAddress, s9xwrap_t w) { + uint16 Work16 = S9xGetWord (OpAddress, w); + ICPU._Carry = Work16 & 1; + Work16 >>= 1; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = (Work16&0xff); + SetZN (Work16); +} + +STATIC inline void LSR8 (uint32 OpAddress) { + uint8 Work8 = S9xGetByte (OpAddress); + ICPU._Carry = Work8 & 1; + Work8 >>= 1; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; + SetZN (Work8); +} + +STATIC inline void ORA (uint16 val) { + Registers.A.W |= val; + SetZN (Registers.A.W); +} + +STATIC inline void ORA (uint8 val) { + Registers.AL |= val; + SetZN (Registers.AL); +} + +STATIC inline void ROL16 (uint32 OpAddress, s9xwrap_t w) { + uint32 Work32 = (((uint32)S9xGetWord(OpAddress, w))<<1) | CheckCarry(); + ICPU._Carry = Work32>=0x10000; + AddCycles(ONE_CYCLE); + S9xSetWord ((uint16)Work32, OpAddress, w, WRITE_10); + OpenBus = (Work32&0xff); + SetZN ((uint16)Work32); +} + +STATIC inline void ROL8 (uint32 OpAddress) { + uint16 Work16 = (((uint16)S9xGetByte(OpAddress))<<1) | CheckCarry(); + ICPU._Carry = Work16>=0x100; + AddCycles(ONE_CYCLE); + S9xSetByte ((uint8)Work16, OpAddress); + OpenBus = Work16&0xff; + SetZN ((uint8)Work16); +} + +STATIC inline void ROR16 (uint32 OpAddress, s9xwrap_t w) { + uint32 Work32 = ((uint32)S9xGetWord(OpAddress, w)) | (((uint32)CheckCarry())<<16); + ICPU._Carry = Work32&1; + Work32 >>= 1; + AddCycles(ONE_CYCLE); + S9xSetWord ((uint16)Work32, OpAddress, w, WRITE_10); + OpenBus = (Work32&0xff); + SetZN ((uint16)Work32); +} + +STATIC inline void ROR8 (uint32 OpAddress) { + uint16 Work16 = ((uint16)S9xGetByte(OpAddress)) | (((uint16)CheckCarry())<<8); + ICPU._Carry = Work16&1; + Work16 >>= 1; + AddCycles(ONE_CYCLE); + S9xSetByte ((uint8)Work16, OpAddress); + OpenBus = Work16&0xff; + SetZN ((uint8)Work16); +} + +STATIC inline void SBC (uint16 Work16) { + if (CheckDecimal ()) { + uint16 A1 = Registers.A.W & 0x000F; + uint16 A2 = Registers.A.W & 0x00F0; + uint16 A3 = Registers.A.W & 0x0F00; + uint32 A4 = Registers.A.W & 0xF000; + uint16 W1 = Work16 & 0x000F; + uint16 W2 = Work16 & 0x00F0; + uint16 W3 = Work16 & 0x0F00; + uint16 W4 = Work16 & 0xF000; + + A1 -= W1 + !CheckCarry (); + A2 -= W2; + A3 -= W3; + A4 -= W4; + if (A1 > 0x000F) { + A1 += 0x000A; + A1 &= 0x000F; + A2 -= 0x0010; + } + if (A2 > 0x00F0) { + A2 += 0x00A0; + A2 &= 0x00F0; + A3 -= 0x0100; + } + if (A3 > 0x0F00) { + A3 += 0x0A00; + A3 &= 0x0F00; + A4 -= 0x1000; + } + if (A4 > 0xF000) { + A4 += 0xA000; + A4 &= 0xF000; + ClearCarry (); + } else { + SetCarry (); + } + + uint16 Ans16 = A4|A3|A2|A1; + if ((Registers.A.W ^ Work16) & + (Registers.A.W ^ Ans16) & 0x8000) + SetOverflow(); + else + ClearOverflow(); + Registers.A.W = Ans16; + SetZN (Registers.A.W); + } else { + int32 Int32 = (int32) Registers.A.W - (int32) Work16 + (int32) CheckCarry() - 1; + + ICPU._Carry = Int32 >= 0; + + if ((Registers.A.W ^ Work16) & + (Registers.A.W ^ (uint16) Int32) & 0x8000) + SetOverflow(); + else + ClearOverflow (); + Registers.A.W = (uint16) Int32; + SetZN (Registers.A.W); + } +} + +STATIC inline void SBC (uint8 Work8) { + if (CheckDecimal ()) { + uint8 A1 = Registers.A.W & 0x0F; + uint16 A2 = Registers.A.W & 0xF0; + uint8 W1 = Work8 & 0x0F; + uint8 W2 = Work8 & 0xF0; + + A1 -= W1 + !CheckCarry (); + A2 -= W2; + if (A1 > 0x0F) { + A1 += 0x0A; + A1 &= 0x0F; + A2 -= 0x10; + } + if (A2 > 0xF0) { + A2 += 0xA0; + A2 &= 0xF0; + ClearCarry (); + } else { + SetCarry (); + } + + uint8 Ans8 = A2|A1; + if ((Registers.AL ^ Work8) & + (Registers.AL ^ Ans8) & 0x80) + SetOverflow (); + else + ClearOverflow (); + Registers.AL = Ans8; + SetZN (Registers.AL); + } else { + int16 Int16 = (int16) Registers.AL - (int16) Work8 + (int16) CheckCarry() - 1; + + ICPU._Carry = Int16 >= 0; + if ((Registers.AL ^ Work8) & + (Registers.AL ^ (uint8) Int16) & 0x80) + SetOverflow (); + else + ClearOverflow (); + Registers.AL = (uint8) Int16; + SetZN (Registers.AL); + } +} + +STATIC inline void STA16 (uint32 OpAddress, enum s9xwrap_t w) { + S9xSetWord (Registers.A.W, OpAddress, w); + OpenBus = Registers.AH; +} + +STATIC inline void STA8 (uint32 OpAddress) { + S9xSetByte (Registers.AL, OpAddress); + OpenBus = Registers.AL; +} + +STATIC inline void STX16 (uint32 OpAddress, enum s9xwrap_t w) { + S9xSetWord (Registers.X.W, OpAddress, w); + OpenBus = Registers.XH; +} + +STATIC inline void STX8 (uint32 OpAddress) { + S9xSetByte (Registers.XL, OpAddress); + OpenBus = Registers.XL; +} + +STATIC inline void STY16 (uint32 OpAddress, enum s9xwrap_t w) { + S9xSetWord (Registers.Y.W, OpAddress, w); + OpenBus = Registers.YH; +} + +STATIC inline void STY8 (uint32 OpAddress) { + S9xSetByte (Registers.YL, OpAddress); + OpenBus = Registers.YL; +} + +STATIC inline void STZ16 (uint32 OpAddress, enum s9xwrap_t w) { + S9xSetWord (0, OpAddress, w); + OpenBus = 0; +} + +STATIC inline void STZ8 (uint32 OpAddress) { + S9xSetByte (0, OpAddress); + OpenBus = 0; +} + +STATIC inline void TSB16 (uint32 OpAddress, enum s9xwrap_t w) { + uint16 Work16 = S9xGetWord (OpAddress, w); + ICPU._Zero = (Work16 & Registers.A.W) != 0; + Work16 |= Registers.A.W; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = Work16&0xff; +} + +STATIC inline void TSB8 (uint32 OpAddress) { + uint8 Work8 = S9xGetByte (OpAddress); + ICPU._Zero = Work8 & Registers.AL; + Work8 |= Registers.AL; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; +} + +STATIC inline void TRB16 (uint32 OpAddress, enum s9xwrap_t w) { + uint16 Work16 = S9xGetWord (OpAddress, w); + ICPU._Zero = (Work16 & Registers.A.W) != 0; + Work16 &= ~Registers.A.W; + AddCycles(ONE_CYCLE); + S9xSetWord (Work16, OpAddress, w, WRITE_10); + OpenBus = Work16&0xff; +} + +STATIC inline void TRB8 (uint32 OpAddress) { + uint8 Work8 = S9xGetByte (OpAddress); + ICPU._Zero = Work8 & Registers.AL; + Work8 &= ~Registers.AL; + AddCycles(ONE_CYCLE); + S9xSetByte (Work8, OpAddress); + OpenBus = Work8; +} +#endif diff --git a/source/snes9x/cpuops.cpp b/source/snes9x/cpuops.cpp new file mode 100644 index 0000000..706a9b8 --- /dev/null +++ b/source/snes9x/cpuops.cpp @@ -0,0 +1,3639 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +/*****************************************************************************/ +/* CPU-S9xOpcodes.CPP */ +/* This file contains all the opcodes */ +/*****************************************************************************/ + +#include "snes9x.h" +#include "memmap.h" +#include "debug.h" +#include "missing.h" +#ifdef DEBUGGER +// for "Magic WDM" features +#include "display.h" +#include "snapshot.h" +#endif +#include "apu.h" +#include "sa1.h" +#include "spc7110.h" +#include "dsp1.h" + +#ifdef SA1_OPCODES +#define AddCycles(n) +#else +#define AddCycles(n) CPU.Cycles+=n +#endif + +#include "cpuexec.h" +#include "cpuaddr.h" +#include "cpuops.h" +#include "cpumacro.h" + +/* ADC ********************************************************************* */ +static void Op69M1 (void) { + ADC(Immediate8(READ)); +} + +static void Op69M0 (void) { + ADC(Immediate16(READ)); +} + +static void Op69Slow (void) { + if(CheckMemory()) { + ADC(Immediate8Slow(READ)); + } else { + ADC(Immediate16Slow(READ)); + } +} + +rOP8 (65M1, Direct, WRAP_BANK, ADC) +rOP16(65M0, Direct, WRAP_BANK, ADC) +rOPM (65Slow, DirectSlow, WRAP_BANK, ADC) + +rOP8 (75E1, DirectIndexedXE1, WRAP_BANK, ADC) +rOP8 (75E0M1, DirectIndexedXE0, WRAP_BANK, ADC) +rOP16(75E0M0, DirectIndexedXE0, WRAP_BANK, ADC) +rOPM (75Slow, DirectIndexedXSlow, WRAP_BANK, ADC) + +rOP8 (72E1, DirectIndirectE1, WRAP_NONE, ADC) +rOP8 (72E0M1, DirectIndirectE0, WRAP_NONE, ADC) +rOP16(72E0M0, DirectIndirectE0, WRAP_NONE, ADC) +rOPM (72Slow, DirectIndirectSlow, WRAP_NONE, ADC) + +rOP8 (61E1, DirectIndexedIndirectE1, WRAP_NONE, ADC) +rOP8 (61E0M1, DirectIndexedIndirectE0, WRAP_NONE, ADC) +rOP16(61E0M0, DirectIndexedIndirectE0, WRAP_NONE, ADC) +rOPM (61Slow, DirectIndexedIndirectSlow, WRAP_NONE, ADC) + +rOP8 (71E1, DirectIndirectIndexedE1, WRAP_NONE, ADC) +rOP8 (71E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC) +rOP16(71E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC) +rOP8 (71E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC) +rOP16(71E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC) +rOPM (71Slow, DirectIndirectIndexedSlow, WRAP_NONE, ADC) + +rOP8 (67M1, DirectIndirectLong, WRAP_NONE, ADC) +rOP16(67M0, DirectIndirectLong, WRAP_NONE, ADC) +rOPM (67Slow, DirectIndirectLongSlow, WRAP_NONE, ADC) + +rOP8 (77M1, DirectIndirectIndexedLong, WRAP_NONE, ADC) +rOP16(77M0, DirectIndirectIndexedLong, WRAP_NONE, ADC) +rOPM (77Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ADC) + +rOP8 (6DM1, Absolute, WRAP_NONE, ADC) +rOP16(6DM0, Absolute, WRAP_NONE, ADC) +rOPM (6DSlow, AbsoluteSlow, WRAP_NONE, ADC) + +rOP8 (7DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ADC) +rOP16(7DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ADC) +rOP8 (7DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ADC) +rOP16(7DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ADC) +rOPM (7DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ADC) + +rOP8 (79M1X1, AbsoluteIndexedYX1, WRAP_NONE, ADC) +rOP16(79M0X1, AbsoluteIndexedYX1, WRAP_NONE, ADC) +rOP8 (79M1X0, AbsoluteIndexedYX0, WRAP_NONE, ADC) +rOP16(79M0X0, AbsoluteIndexedYX0, WRAP_NONE, ADC) +rOPM (79Slow, AbsoluteIndexedYSlow, WRAP_NONE, ADC) + +rOP8 (6FM1, AbsoluteLong, WRAP_NONE, ADC) +rOP16(6FM0, AbsoluteLong, WRAP_NONE, ADC) +rOPM (6FSlow, AbsoluteLongSlow, WRAP_NONE, ADC) + +rOP8 (7FM1, AbsoluteLongIndexedX, WRAP_NONE, ADC) +rOP16(7FM0, AbsoluteLongIndexedX, WRAP_NONE, ADC) +rOPM (7FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ADC) + +rOP8 (63M1, StackRelative, WRAP_NONE, ADC) +rOP16(63M0, StackRelative, WRAP_NONE, ADC) +rOPM (63Slow, StackRelativeSlow, WRAP_NONE, ADC) + +rOP8 (73M1, StackRelativeIndirectIndexed, WRAP_NONE, ADC) +rOP16(73M0, StackRelativeIndirectIndexed, WRAP_NONE, ADC) +rOPM (73Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ADC) + +/*****************************************************************************/ + +/* AND ********************************************************************* */ +static void Op29M1 (void) { + Registers.AL &= Immediate8(READ); + SetZN (Registers.AL); +} + +static void Op29M0 (void) { + Registers.A.W &= Immediate16(READ); + SetZN (Registers.A.W); +} + +static void Op29Slow (void) { + if(CheckMemory()){ + Registers.AL &= Immediate8Slow(READ); + SetZN (Registers.AL); + } else { + Registers.A.W &= Immediate16Slow(READ); + SetZN (Registers.A.W); + } +} + +rOP8 (25M1, Direct, WRAP_BANK, AND) +rOP16(25M0, Direct, WRAP_BANK, AND) +rOPM (25Slow, DirectSlow, WRAP_BANK, AND) + +rOP8 (35E1, DirectIndexedXE1, WRAP_BANK, AND) +rOP8 (35E0M1, DirectIndexedXE0, WRAP_BANK, AND) +rOP16(35E0M0, DirectIndexedXE0, WRAP_BANK, AND) +rOPM (35Slow, DirectIndexedXSlow, WRAP_BANK, AND) + +rOP8 (32E1, DirectIndirectE1, WRAP_NONE, AND) +rOP8 (32E0M1, DirectIndirectE0, WRAP_NONE, AND) +rOP16(32E0M0, DirectIndirectE0, WRAP_NONE, AND) +rOPM (32Slow, DirectIndirectSlow, WRAP_NONE, AND) + +rOP8 (21E1, DirectIndexedIndirectE1, WRAP_NONE, AND) +rOP8 (21E0M1, DirectIndexedIndirectE0, WRAP_NONE, AND) +rOP16(21E0M0, DirectIndexedIndirectE0, WRAP_NONE, AND) +rOPM (21Slow, DirectIndexedIndirectSlow, WRAP_NONE, AND) + +rOP8 (31E1, DirectIndirectIndexedE1, WRAP_NONE, AND) +rOP8 (31E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND) +rOP16(31E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND) +rOP8 (31E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND) +rOP16(31E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND) +rOPM (31Slow, DirectIndirectIndexedSlow, WRAP_NONE, AND) + +rOP8 (27M1, DirectIndirectLong, WRAP_NONE, AND) +rOP16(27M0, DirectIndirectLong, WRAP_NONE, AND) +rOPM (27Slow, DirectIndirectLongSlow, WRAP_NONE, AND) + +rOP8 (37M1, DirectIndirectIndexedLong, WRAP_NONE, AND) +rOP16(37M0, DirectIndirectIndexedLong, WRAP_NONE, AND) +rOPM (37Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, AND) + +rOP8 (2DM1, Absolute, WRAP_NONE, AND) +rOP16(2DM0, Absolute, WRAP_NONE, AND) +rOPM (2DSlow, AbsoluteSlow, WRAP_NONE, AND) + +rOP8 (3DM1X1, AbsoluteIndexedXX1, WRAP_NONE, AND) +rOP16(3DM0X1, AbsoluteIndexedXX1, WRAP_NONE, AND) +rOP8 (3DM1X0, AbsoluteIndexedXX0, WRAP_NONE, AND) +rOP16(3DM0X0, AbsoluteIndexedXX0, WRAP_NONE, AND) +rOPM (3DSlow, AbsoluteIndexedXSlow, WRAP_NONE, AND) + +rOP8 (39M1X1, AbsoluteIndexedYX1, WRAP_NONE, AND) +rOP16(39M0X1, AbsoluteIndexedYX1, WRAP_NONE, AND) +rOP8 (39M1X0, AbsoluteIndexedYX0, WRAP_NONE, AND) +rOP16(39M0X0, AbsoluteIndexedYX0, WRAP_NONE, AND) +rOPM (39Slow, AbsoluteIndexedYSlow, WRAP_NONE, AND) + +rOP8 (2FM1, AbsoluteLong, WRAP_NONE, AND) +rOP16(2FM0, AbsoluteLong, WRAP_NONE, AND) +rOPM (2FSlow, AbsoluteLongSlow, WRAP_NONE, AND) + +rOP8 (3FM1, AbsoluteLongIndexedX, WRAP_NONE, AND) +rOP16(3FM0, AbsoluteLongIndexedX, WRAP_NONE, AND) +rOPM (3FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, AND) + +rOP8 (23M1, StackRelative, WRAP_NONE, AND) +rOP16(23M0, StackRelative, WRAP_NONE, AND) +rOPM (23Slow, StackRelativeSlow, WRAP_NONE, AND) + +rOP8 (33M1, StackRelativeIndirectIndexed, WRAP_NONE, AND) +rOP16(33M0, StackRelativeIndirectIndexed, WRAP_NONE, AND) +rOPM (33Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, AND) + +/*****************************************************************************/ + +/* ASL ********************************************************************* */ +static void Op0AM1 (void) { + AddCycles(ONE_CYCLE); + ICPU._Carry = (Registers.AL & 0x80) != 0; + Registers.AL <<= 1; + SetZN (Registers.AL); +} + +static void Op0AM0 (void) { + AddCycles(ONE_CYCLE); + ICPU._Carry = (Registers.AH & 0x80) != 0; + Registers.A.W <<= 1; + SetZN (Registers.A.W); +} + +static void Op0ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + ICPU._Carry = (Registers.AL & 0x80) != 0; + Registers.AL <<= 1; + SetZN (Registers.AL); + } else { + ICPU._Carry = (Registers.AH & 0x80) != 0; + Registers.A.W <<= 1; + SetZN (Registers.A.W); + } +} + +mOP8 (06M1, Direct, WRAP_BANK, ASL) +mOP16(06M0, Direct, WRAP_BANK, ASL) +mOPM (06Slow, DirectSlow, WRAP_BANK, ASL) + +mOP8 (16E1, DirectIndexedXE1, WRAP_BANK, ASL) +mOP8 (16E0M1, DirectIndexedXE0, WRAP_BANK, ASL) +mOP16(16E0M0, DirectIndexedXE0, WRAP_BANK, ASL) +mOPM (16Slow, DirectIndexedXSlow, WRAP_BANK, ASL) + +mOP8 (0EM1, Absolute, WRAP_NONE, ASL) +mOP16(0EM0, Absolute, WRAP_NONE, ASL) +mOPM (0ESlow, AbsoluteSlow, WRAP_NONE, ASL) + +mOP8 (1EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ASL) +mOP16(1EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ASL) +mOP8 (1EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ASL) +mOP16(1EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ASL) +mOPM (1ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ASL) + +/*****************************************************************************/ + +/* BIT ********************************************************************* */ + +static void Op89M1 (void) { + ICPU._Zero = Registers.AL & Immediate8(READ); +} + +static void Op89M0 (void) { + ICPU._Zero = (Registers.A.W & Immediate16(READ)) != 0; +} + +static void Op89Slow (void) { + if(CheckMemory()){ + ICPU._Zero = Registers.AL & Immediate8Slow(READ); + } else { + ICPU._Zero = (Registers.A.W & Immediate16Slow(READ)) != 0; + } +} + +rOP8 (24M1, Direct, WRAP_BANK, BIT) +rOP16(24M0, Direct, WRAP_BANK, BIT) +rOPM (24Slow, DirectSlow, WRAP_BANK, BIT) + +rOP8 (34E1, DirectIndexedXE1, WRAP_BANK, BIT) +rOP8 (34E0M1, DirectIndexedXE0, WRAP_BANK, BIT) +rOP16(34E0M0, DirectIndexedXE0, WRAP_BANK, BIT) +rOPM (34Slow, DirectIndexedXSlow, WRAP_BANK, BIT) + +rOP8 (2CM1, Absolute, WRAP_NONE, BIT) +rOP16(2CM0, Absolute, WRAP_NONE, BIT) +rOPM (2CSlow, AbsoluteSlow, WRAP_NONE, BIT) + +rOP8 (3CM1X1, AbsoluteIndexedXX1, WRAP_NONE, BIT) +rOP16(3CM0X1, AbsoluteIndexedXX1, WRAP_NONE, BIT) +rOP8 (3CM1X0, AbsoluteIndexedXX0, WRAP_NONE, BIT) +rOP16(3CM0X0, AbsoluteIndexedXX0, WRAP_NONE, BIT) +rOPM (3CSlow, AbsoluteIndexedXSlow, WRAP_NONE, BIT) + +/*****************************************************************************/ + +/* CMP ********************************************************************* */ + +static void OpC9M1 (void) { + int16 Int16 = (int16)Registers.AL - (int16)Immediate8(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); +} + +static void OpC9M0 (void) { + int32 Int32 = (int32)Registers.A.W - (int32)Immediate16(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +static void OpC9Slow (void) { + if(CheckMemory()){ + int16 Int16 = (int16)Registers.AL - (int16)Immediate8Slow(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); + } else { + int32 Int32 = (int32)Registers.A.W - (int32)Immediate16Slow(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16)Int32); + } +} + +rOP8 (C5M1, Direct, WRAP_BANK, CMP) +rOP16(C5M0, Direct, WRAP_BANK, CMP) +rOPM (C5Slow, DirectSlow, WRAP_BANK, CMP) + +rOP8 (D5E1, DirectIndexedXE1, WRAP_BANK, CMP) +rOP8 (D5E0M1, DirectIndexedXE0, WRAP_BANK, CMP) +rOP16(D5E0M0, DirectIndexedXE0, WRAP_BANK, CMP) +rOPM (D5Slow, DirectIndexedXSlow, WRAP_BANK, CMP) + +rOP8 (D2E1, DirectIndirectE1, WRAP_NONE, CMP) +rOP8 (D2E0M1, DirectIndirectE0, WRAP_NONE, CMP) +rOP16(D2E0M0, DirectIndirectE0, WRAP_NONE, CMP) +rOPM (D2Slow, DirectIndirectSlow, WRAP_NONE, CMP) + +rOP8 (C1E1, DirectIndexedIndirectE1, WRAP_NONE, CMP) +rOP8 (C1E0M1, DirectIndexedIndirectE0, WRAP_NONE, CMP) +rOP16(C1E0M0, DirectIndexedIndirectE0, WRAP_NONE, CMP) +rOPM (C1Slow, DirectIndexedIndirectSlow, WRAP_NONE, CMP) + +rOP8 (D1E1, DirectIndirectIndexedE1, WRAP_NONE, CMP) +rOP8 (D1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP) +rOP16(D1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP) +rOP8 (D1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP) +rOP16(D1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP) +rOPM (D1Slow, DirectIndirectIndexedSlow, WRAP_NONE, CMP) + +rOP8 (C7M1, DirectIndirectLong, WRAP_NONE, CMP) +rOP16(C7M0, DirectIndirectLong, WRAP_NONE, CMP) +rOPM (C7Slow, DirectIndirectLongSlow, WRAP_NONE, CMP) + +rOP8 (D7M1, DirectIndirectIndexedLong, WRAP_NONE, CMP) +rOP16(D7M0, DirectIndirectIndexedLong, WRAP_NONE, CMP) +rOPM (D7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, CMP) + +rOP8 (CDM1, Absolute, WRAP_NONE, CMP) +rOP16(CDM0, Absolute, WRAP_NONE, CMP) +rOPM (CDSlow, AbsoluteSlow, WRAP_NONE, CMP) + +rOP8 (DDM1X1, AbsoluteIndexedXX1, WRAP_NONE, CMP) +rOP16(DDM0X1, AbsoluteIndexedXX1, WRAP_NONE, CMP) +rOP8 (DDM1X0, AbsoluteIndexedXX0, WRAP_NONE, CMP) +rOP16(DDM0X0, AbsoluteIndexedXX0, WRAP_NONE, CMP) +rOPM (DDSlow, AbsoluteIndexedXSlow, WRAP_NONE, CMP) + +rOP8 (D9M1X1, AbsoluteIndexedYX1, WRAP_NONE, CMP) +rOP16(D9M0X1, AbsoluteIndexedYX1, WRAP_NONE, CMP) +rOP8 (D9M1X0, AbsoluteIndexedYX0, WRAP_NONE, CMP) +rOP16(D9M0X0, AbsoluteIndexedYX0, WRAP_NONE, CMP) +rOPM (D9Slow, AbsoluteIndexedYSlow, WRAP_NONE, CMP) + +rOP8 (CFM1, AbsoluteLong, WRAP_NONE, CMP) +rOP16(CFM0, AbsoluteLong, WRAP_NONE, CMP) +rOPM (CFSlow, AbsoluteLongSlow, WRAP_NONE, CMP) + +rOP8 (DFM1, AbsoluteLongIndexedX, WRAP_NONE, CMP) +rOP16(DFM0, AbsoluteLongIndexedX, WRAP_NONE, CMP) +rOPM (DFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, CMP) + +rOP8 (C3M1, StackRelative, WRAP_NONE, CMP) +rOP16(C3M0, StackRelative, WRAP_NONE, CMP) +rOPM (C3Slow, StackRelativeSlow, WRAP_NONE, CMP) + +rOP8 (D3M1, StackRelativeIndirectIndexed, WRAP_NONE, CMP) +rOP16(D3M0, StackRelativeIndirectIndexed, WRAP_NONE, CMP) +rOPM (D3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, CMP) + +/*****************************************************************************/ + +/* CPX ********************************************************************* */ + +static void OpE0X1 (void) { + int16 Int16 = (int16)Registers.XL - (int16)Immediate8(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); +} + +static void OpE0X0 (void) { + int32 Int32 = (int32)Registers.X.W - (int32)Immediate16(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +static void OpE0Slow (void) { + if(CheckIndex()){ + int16 Int16 = (int16)Registers.XL - (int16)Immediate8Slow(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); + } else { + int32 Int32 = (int32)Registers.X.W - (int32)Immediate16Slow(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); + } +} + +rOP8 (E4X1, Direct, WRAP_BANK, CPX) +rOP16(E4X0, Direct, WRAP_BANK, CPX) +rOPX (E4Slow, DirectSlow, WRAP_BANK, CPX) + +rOP8 (ECX1, Absolute, WRAP_NONE, CPX) +rOP16(ECX0, Absolute, WRAP_NONE, CPX) +rOPX (ECSlow, AbsoluteSlow, WRAP_NONE, CPX) + +/*****************************************************************************/ + +/* CPY ********************************************************************* */ + +static void OpC0X1 (void) { + int16 Int16 = (int16)Registers.YL - (int16)Immediate8(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); +} + +static void OpC0X0 (void) { + int32 Int32 = (int32)Registers.Y.W - (int32)Immediate16(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); +} + +static void OpC0Slow (void) { + if(CheckIndex()){ + int16 Int16 = (int16)Registers.YL - (int16)Immediate8Slow(READ); + ICPU._Carry = Int16 >= 0; + SetZN ((uint8)Int16); + } else { + int32 Int32 = (int32)Registers.Y.W - (int32)Immediate16Slow(READ); + ICPU._Carry = Int32 >= 0; + SetZN ((uint16) Int32); + } +} + +rOP8 (C4X1, Direct, WRAP_BANK, CPY) +rOP16(C4X0, Direct, WRAP_BANK, CPY) +rOPX (C4Slow, DirectSlow, WRAP_BANK, CPY) + +rOP8 (CCX1, Absolute, WRAP_NONE, CPY) +rOP16(CCX0, Absolute, WRAP_NONE, CPY) +rOPX (CCSlow, AbsoluteSlow, WRAP_NONE, CPY) + +/*****************************************************************************/ + +/* DEC ********************************************************************* */ + +static void Op3AM1 (void){ + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.AL--; + SetZN (Registers.AL); +} + +static void Op3AM0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.A.W--; + SetZN (Registers.A.W); +} + +static void Op3ASlow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckMemory()){ + Registers.AL--; + SetZN (Registers.AL); + } else { + Registers.A.W--; + SetZN (Registers.A.W); + } +} + +mOP8 (C6M1, Direct, WRAP_BANK, DEC) +mOP16(C6M0, Direct, WRAP_BANK, DEC) +mOPM (C6Slow, DirectSlow, WRAP_BANK, DEC) + +mOP8 (D6E1, DirectIndexedXE1, WRAP_BANK, DEC) +mOP8 (D6E0M1, DirectIndexedXE0, WRAP_BANK, DEC) +mOP16(D6E0M0, DirectIndexedXE0, WRAP_BANK, DEC) +mOPM (D6Slow, DirectIndexedXSlow, WRAP_BANK, DEC) + +mOP8 (CEM1, Absolute, WRAP_NONE, DEC) +mOP16(CEM0, Absolute, WRAP_NONE, DEC) +mOPM (CESlow, AbsoluteSlow, WRAP_NONE, DEC) + +mOP8 (DEM1X1, AbsoluteIndexedXX1, WRAP_NONE, DEC) +mOP16(DEM0X1, AbsoluteIndexedXX1, WRAP_NONE, DEC) +mOP8 (DEM1X0, AbsoluteIndexedXX0, WRAP_NONE, DEC) +mOP16(DEM0X0, AbsoluteIndexedXX0, WRAP_NONE, DEC) +mOPM (DESlow, AbsoluteIndexedXSlow, WRAP_NONE, DEC) + +/*****************************************************************************/ + +/* EOR ********************************************************************* */ +static void Op49M1 (void) { + Registers.AL ^= Immediate8(READ); + SetZN (Registers.AL); +} + +static void Op49M0 (void) { + Registers.A.W ^= Immediate16(READ); + SetZN (Registers.A.W); +} + +static void Op49Slow (void) { + if(CheckMemory()) { + Registers.AL ^= Immediate8Slow(READ); + SetZN (Registers.AL); + } else { + Registers.A.W ^= Immediate16Slow(READ); + SetZN (Registers.A.W); + } +} + +rOP8 (45M1, Direct, WRAP_BANK, EOR) +rOP16(45M0, Direct, WRAP_BANK, EOR) +rOPM (45Slow, DirectSlow, WRAP_BANK, EOR) + +rOP8 (55E1, DirectIndexedXE1, WRAP_BANK, EOR) +rOP8 (55E0M1, DirectIndexedXE0, WRAP_BANK, EOR) +rOP16(55E0M0, DirectIndexedXE0, WRAP_BANK, EOR) +rOPM (55Slow, DirectIndexedXSlow, WRAP_BANK, EOR) + +rOP8 (52E1, DirectIndirectE1, WRAP_NONE, EOR) +rOP8 (52E0M1, DirectIndirectE0, WRAP_NONE, EOR) +rOP16(52E0M0, DirectIndirectE0, WRAP_NONE, EOR) +rOPM (52Slow, DirectIndirectSlow, WRAP_NONE, EOR) + +rOP8 (41E1, DirectIndexedIndirectE1, WRAP_NONE, EOR) +rOP8 (41E0M1, DirectIndexedIndirectE0, WRAP_NONE, EOR) +rOP16(41E0M0, DirectIndexedIndirectE0, WRAP_NONE, EOR) +rOPM (41Slow, DirectIndexedIndirectSlow, WRAP_NONE, EOR) + +rOP8 (51E1, DirectIndirectIndexedE1, WRAP_NONE, EOR) +rOP8 (51E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR) +rOP16(51E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR) +rOP8 (51E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR) +rOP16(51E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR) +rOPM (51Slow, DirectIndirectIndexedSlow, WRAP_NONE, EOR) + +rOP8 (47M1, DirectIndirectLong, WRAP_NONE, EOR) +rOP16(47M0, DirectIndirectLong, WRAP_NONE, EOR) +rOPM (47Slow, DirectIndirectLongSlow, WRAP_NONE, EOR) + +rOP8 (57M1, DirectIndirectIndexedLong, WRAP_NONE, EOR) +rOP16(57M0, DirectIndirectIndexedLong, WRAP_NONE, EOR) +rOPM (57Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, EOR) + +rOP8 (4DM1, Absolute, WRAP_NONE, EOR) +rOP16(4DM0, Absolute, WRAP_NONE, EOR) +rOPM (4DSlow, AbsoluteSlow, WRAP_NONE, EOR) + +rOP8 (5DM1X1, AbsoluteIndexedXX1, WRAP_NONE, EOR) +rOP16(5DM0X1, AbsoluteIndexedXX1, WRAP_NONE, EOR) +rOP8 (5DM1X0, AbsoluteIndexedXX0, WRAP_NONE, EOR) +rOP16(5DM0X0, AbsoluteIndexedXX0, WRAP_NONE, EOR) +rOPM (5DSlow, AbsoluteIndexedXSlow, WRAP_NONE, EOR) + +rOP8 (59M1X1, AbsoluteIndexedYX1, WRAP_NONE, EOR) +rOP16(59M0X1, AbsoluteIndexedYX1, WRAP_NONE, EOR) +rOP8 (59M1X0, AbsoluteIndexedYX0, WRAP_NONE, EOR) +rOP16(59M0X0, AbsoluteIndexedYX0, WRAP_NONE, EOR) +rOPM (59Slow, AbsoluteIndexedYSlow, WRAP_NONE, EOR) + +rOP8 (4FM1, AbsoluteLong, WRAP_NONE, EOR) +rOP16(4FM0, AbsoluteLong, WRAP_NONE, EOR) +rOPM (4FSlow, AbsoluteLongSlow, WRAP_NONE, EOR) + +rOP8 (5FM1, AbsoluteLongIndexedX, WRAP_NONE, EOR) +rOP16(5FM0, AbsoluteLongIndexedX, WRAP_NONE, EOR) +rOPM (5FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, EOR) + +rOP8 (43M1, StackRelative, WRAP_NONE, EOR) +rOP16(43M0, StackRelative, WRAP_NONE, EOR) +rOPM (43Slow, StackRelativeSlow, WRAP_NONE, EOR) + +rOP8 (53M1, StackRelativeIndirectIndexed, WRAP_NONE, EOR) +rOP16(53M0, StackRelativeIndirectIndexed, WRAP_NONE, EOR) +rOPM (53Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, EOR) + +/*****************************************************************************/ + +/* INC ********************************************************************* */ + +static void Op1AM1 (void){ + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.AL++; + SetZN (Registers.AL); +} + +static void Op1AM0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.A.W++; + SetZN (Registers.A.W); +} + +static void Op1ASlow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckMemory()){ + Registers.AL++; + SetZN (Registers.AL); + } else { + Registers.A.W++; + SetZN (Registers.A.W); + } +} + +mOP8 (E6M1, Direct, WRAP_BANK, INC) +mOP16(E6M0, Direct, WRAP_BANK, INC) +mOPM (E6Slow, DirectSlow, WRAP_BANK, INC) + +mOP8 (F6E1, DirectIndexedXE1, WRAP_BANK, INC) +mOP8 (F6E0M1, DirectIndexedXE0, WRAP_BANK, INC) +mOP16(F6E0M0, DirectIndexedXE0, WRAP_BANK, INC) +mOPM (F6Slow, DirectIndexedXSlow, WRAP_BANK, INC) + +mOP8 (EEM1, Absolute, WRAP_NONE, INC) +mOP16(EEM0, Absolute, WRAP_NONE, INC) +mOPM (EESlow, AbsoluteSlow, WRAP_NONE, INC) + +mOP8 (FEM1X1, AbsoluteIndexedXX1, WRAP_NONE, INC) +mOP16(FEM0X1, AbsoluteIndexedXX1, WRAP_NONE, INC) +mOP8 (FEM1X0, AbsoluteIndexedXX0, WRAP_NONE, INC) +mOP16(FEM0X0, AbsoluteIndexedXX0, WRAP_NONE, INC) +mOPM (FESlow, AbsoluteIndexedXSlow, WRAP_NONE, INC) + +/*****************************************************************************/ +/* LDA ********************************************************************* */ +static void OpA9M1 (void) { + Registers.AL = Immediate8(READ); + SetZN(Registers.AL); +} + +static void OpA9M0 (void) { + Registers.A.W = Immediate16(READ); + SetZN(Registers.A.W); +} + +static void OpA9Slow (void) { + if(CheckMemory()) { + Registers.AL = Immediate8(READ); + SetZN(Registers.AL); + } else { + Registers.A.W = Immediate16(READ); + SetZN(Registers.A.W); + } +} + +rOP8 (A5M1, Direct, WRAP_BANK, LDA) +rOP16(A5M0, Direct, WRAP_BANK, LDA) +rOPM (A5Slow, DirectSlow, WRAP_BANK, LDA) + +rOP8 (B5E1, DirectIndexedXE1, WRAP_BANK, LDA) +rOP8 (B5E0M1, DirectIndexedXE0, WRAP_BANK, LDA) +rOP16(B5E0M0, DirectIndexedXE0, WRAP_BANK, LDA) +rOPM (B5Slow, DirectIndexedXSlow, WRAP_BANK, LDA) + +rOP8 (B2E1, DirectIndirectE1, WRAP_NONE, LDA) +rOP8 (B2E0M1, DirectIndirectE0, WRAP_NONE, LDA) +rOP16(B2E0M0, DirectIndirectE0, WRAP_NONE, LDA) +rOPM (B2Slow, DirectIndirectSlow, WRAP_NONE, LDA) + +rOP8 (A1E1, DirectIndexedIndirectE1, WRAP_NONE, LDA) +rOP8 (A1E0M1, DirectIndexedIndirectE0, WRAP_NONE, LDA) +rOP16(A1E0M0, DirectIndexedIndirectE0, WRAP_NONE, LDA) +rOPM (A1Slow, DirectIndexedIndirectSlow, WRAP_NONE, LDA) + +rOP8 (B1E1, DirectIndirectIndexedE1, WRAP_NONE, LDA) +rOP8 (B1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA) +rOP16(B1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA) +rOP8 (B1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA) +rOP16(B1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA) +rOPM (B1Slow, DirectIndirectIndexedSlow, WRAP_NONE, LDA) + +rOP8 (A7M1, DirectIndirectLong, WRAP_NONE, LDA) +rOP16(A7M0, DirectIndirectLong, WRAP_NONE, LDA) +rOPM (A7Slow, DirectIndirectLongSlow, WRAP_NONE, LDA) + +rOP8 (B7M1, DirectIndirectIndexedLong, WRAP_NONE, LDA) +rOP16(B7M0, DirectIndirectIndexedLong, WRAP_NONE, LDA) +rOPM (B7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, LDA) + +rOP8 (ADM1, Absolute, WRAP_NONE, LDA) +rOP16(ADM0, Absolute, WRAP_NONE, LDA) +rOPM (ADSlow, AbsoluteSlow, WRAP_NONE, LDA) + +rOP8 (BDM1X1, AbsoluteIndexedXX1, WRAP_NONE, LDA) +rOP16(BDM0X1, AbsoluteIndexedXX1, WRAP_NONE, LDA) +rOP8 (BDM1X0, AbsoluteIndexedXX0, WRAP_NONE, LDA) +rOP16(BDM0X0, AbsoluteIndexedXX0, WRAP_NONE, LDA) +rOPM (BDSlow, AbsoluteIndexedXSlow, WRAP_NONE, LDA) + +rOP8 (B9M1X1, AbsoluteIndexedYX1, WRAP_NONE, LDA) +rOP16(B9M0X1, AbsoluteIndexedYX1, WRAP_NONE, LDA) +rOP8 (B9M1X0, AbsoluteIndexedYX0, WRAP_NONE, LDA) +rOP16(B9M0X0, AbsoluteIndexedYX0, WRAP_NONE, LDA) +rOPM (B9Slow, AbsoluteIndexedYSlow, WRAP_NONE, LDA) + +rOP8 (AFM1, AbsoluteLong, WRAP_NONE, LDA) +rOP16(AFM0, AbsoluteLong, WRAP_NONE, LDA) +rOPM (AFSlow, AbsoluteLongSlow, WRAP_NONE, LDA) + +rOP8 (BFM1, AbsoluteLongIndexedX, WRAP_NONE, LDA) +rOP16(BFM0, AbsoluteLongIndexedX, WRAP_NONE, LDA) +rOPM (BFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, LDA) + +rOP8 (A3M1, StackRelative, WRAP_NONE, LDA) +rOP16(A3M0, StackRelative, WRAP_NONE, LDA) +rOPM (A3Slow, StackRelativeSlow, WRAP_NONE, LDA) + +rOP8 (B3M1, StackRelativeIndirectIndexed, WRAP_NONE, LDA) +rOP16(B3M0, StackRelativeIndirectIndexed, WRAP_NONE, LDA) +rOPM (B3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, LDA) + +/*****************************************************************************/ + +/* LDX ********************************************************************* */ +static void OpA2X1 (void) { + Registers.XL = Immediate8(READ); + SetZN(Registers.XL); +} + +static void OpA2X0 (void) { + Registers.X.W = Immediate16(READ); + SetZN(Registers.X.W); +} + +static void OpA2Slow (void) { + if(CheckIndex()) { + Registers.XL = Immediate8Slow(READ); + SetZN(Registers.XL); + } else { + Registers.X.W = Immediate16Slow(READ); + SetZN(Registers.X.W); + } +} + +rOP8 (A6X1, Direct, WRAP_BANK, LDX) +rOP16(A6X0, Direct, WRAP_BANK, LDX) +rOPX (A6Slow, DirectSlow, WRAP_BANK, LDX) + +rOP8 (B6E1, DirectIndexedYE1, WRAP_BANK, LDX) +rOP8 (B6E0X1, DirectIndexedYE0, WRAP_BANK, LDX) +rOP16(B6E0X0, DirectIndexedYE0, WRAP_BANK, LDX) +rOPX (B6Slow, DirectIndexedYSlow, WRAP_BANK, LDX) + +rOP8 (AEX1, Absolute, WRAP_BANK, LDX) +rOP16(AEX0, Absolute, WRAP_BANK, LDX) +rOPX (AESlow, AbsoluteSlow, WRAP_BANK, LDX) + +rOP8 (BEX1, AbsoluteIndexedYX1, WRAP_BANK, LDX) +rOP16(BEX0, AbsoluteIndexedYX0, WRAP_BANK, LDX) +rOPX (BESlow, AbsoluteIndexedYSlow, WRAP_BANK, LDX) + +/*****************************************************************************/ + +/* LDY ********************************************************************* */ +static void OpA0X1 (void) { + Registers.YL = Immediate8(READ); + SetZN(Registers.YL); +} + +static void OpA0X0 (void) { + Registers.Y.W = Immediate16(READ); + SetZN(Registers.Y.W); +} + +static void OpA0Slow (void) { + if(CheckIndex()) { + Registers.YL = Immediate8Slow(READ); + SetZN(Registers.YL); + } else { + Registers.Y.W = Immediate16Slow(READ); + SetZN(Registers.Y.W); + } +} + +rOP8 (A4X1, Direct, WRAP_BANK, LDY) +rOP16(A4X0, Direct, WRAP_BANK, LDY) +rOPX (A4Slow, DirectSlow, WRAP_BANK, LDY) + +rOP8 (B4E1, DirectIndexedXE1, WRAP_BANK, LDY) +rOP8 (B4E0X1, DirectIndexedXE0, WRAP_BANK, LDY) +rOP16(B4E0X0, DirectIndexedXE0, WRAP_BANK, LDY) +rOPX (B4Slow, DirectIndexedXSlow, WRAP_BANK, LDY) + +rOP8 (ACX1, Absolute, WRAP_BANK, LDY) +rOP16(ACX0, Absolute, WRAP_BANK, LDY) +rOPX (ACSlow, AbsoluteSlow, WRAP_BANK, LDY) + +rOP8 (BCX1, AbsoluteIndexedXX1, WRAP_BANK, LDY) +rOP16(BCX0, AbsoluteIndexedXX0, WRAP_BANK, LDY) +rOPX (BCSlow, AbsoluteIndexedXSlow, WRAP_BANK, LDY) + +/*****************************************************************************/ + +/* LSR ********************************************************************* */ +static void Op4AM1 (void) { + AddCycles(ONE_CYCLE); + ICPU._Carry = Registers.AL & 1; + Registers.AL >>= 1; + SetZN (Registers.AL); +} + +static void Op4AM0 (void) { + AddCycles(ONE_CYCLE); + ICPU._Carry = Registers.A.W & 1; + Registers.A.W >>= 1; + SetZN (Registers.A.W); +} + +static void Op4ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + ICPU._Carry = Registers.AL & 1; + Registers.AL >>= 1; + SetZN (Registers.AL); + } else { + ICPU._Carry = Registers.A.W & 1; + Registers.A.W >>= 1; + SetZN (Registers.A.W); + } +} + +mOP8 (46M1, Direct, WRAP_BANK, LSR) +mOP16(46M0, Direct, WRAP_BANK, LSR) +mOPM (46Slow, DirectSlow, WRAP_BANK, LSR) + +mOP8 (56E1, DirectIndexedXE1, WRAP_BANK, LSR) +mOP8 (56E0M1, DirectIndexedXE0, WRAP_BANK, LSR) +mOP16(56E0M0, DirectIndexedXE0, WRAP_BANK, LSR) +mOPM (56Slow, DirectIndexedXSlow, WRAP_BANK, LSR) + +mOP8 (4EM1, Absolute, WRAP_NONE, LSR) +mOP16(4EM0, Absolute, WRAP_NONE, LSR) +mOPM (4ESlow, AbsoluteSlow, WRAP_NONE, LSR) + +mOP8 (5EM1X1, AbsoluteIndexedXX1, WRAP_NONE, LSR) +mOP16(5EM0X1, AbsoluteIndexedXX1, WRAP_NONE, LSR) +mOP8 (5EM1X0, AbsoluteIndexedXX0, WRAP_NONE, LSR) +mOP16(5EM0X0, AbsoluteIndexedXX0, WRAP_NONE, LSR) +mOPM (5ESlow, AbsoluteIndexedXSlow, WRAP_NONE, LSR) + +/*****************************************************************************/ + +/* ORA ********************************************************************* */ +static void Op09M1 (void) { + Registers.AL |= Immediate8(READ); + SetZN (Registers.AL); +} + +static void Op09M0 (void) { + Registers.A.W |= Immediate16(READ); + SetZN (Registers.A.W); +} + +static void Op09Slow (void) { + if(CheckMemory()){ + Registers.AL |= Immediate8Slow(READ); + SetZN (Registers.AL); + } else { + Registers.A.W |= Immediate16Slow(READ); + SetZN (Registers.A.W); + } +} + +rOP8 (05M1, Direct, WRAP_BANK, ORA) +rOP16(05M0, Direct, WRAP_BANK, ORA) +rOPM (05Slow, DirectSlow, WRAP_BANK, ORA) + +rOP8 (15E1, DirectIndexedXE1, WRAP_BANK, ORA) +rOP8 (15E0M1, DirectIndexedXE0, WRAP_BANK, ORA) +rOP16(15E0M0, DirectIndexedXE0, WRAP_BANK, ORA) +rOPM (15Slow, DirectIndexedXSlow, WRAP_BANK, ORA) + +rOP8 (12E1, DirectIndirectE1, WRAP_NONE, ORA) +rOP8 (12E0M1, DirectIndirectE0, WRAP_NONE, ORA) +rOP16(12E0M0, DirectIndirectE0, WRAP_NONE, ORA) +rOPM (12Slow, DirectIndirectSlow, WRAP_NONE, ORA) + +rOP8 (01E1, DirectIndexedIndirectE1, WRAP_NONE, ORA) +rOP8 (01E0M1, DirectIndexedIndirectE0, WRAP_NONE, ORA) +rOP16(01E0M0, DirectIndexedIndirectE0, WRAP_NONE, ORA) +rOPM (01Slow, DirectIndexedIndirectSlow, WRAP_NONE, ORA) + +rOP8 (11E1, DirectIndirectIndexedE1, WRAP_NONE, ORA) +rOP8 (11E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA) +rOP16(11E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA) +rOP8 (11E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA) +rOP16(11E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA) +rOPM (11Slow, DirectIndirectIndexedSlow, WRAP_NONE, ORA) + +rOP8 (07M1, DirectIndirectLong, WRAP_NONE, ORA) +rOP16(07M0, DirectIndirectLong, WRAP_NONE, ORA) +rOPM (07Slow, DirectIndirectLongSlow, WRAP_NONE, ORA) + +rOP8 (17M1, DirectIndirectIndexedLong, WRAP_NONE, ORA) +rOP16(17M0, DirectIndirectIndexedLong, WRAP_NONE, ORA) +rOPM (17Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ORA) + +rOP8 (0DM1, Absolute, WRAP_NONE, ORA) +rOP16(0DM0, Absolute, WRAP_NONE, ORA) +rOPM (0DSlow, AbsoluteSlow, WRAP_NONE, ORA) + +rOP8 (1DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ORA) +rOP16(1DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ORA) +rOP8 (1DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ORA) +rOP16(1DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ORA) +rOPM (1DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ORA) + +rOP8 (19M1X1, AbsoluteIndexedYX1, WRAP_NONE, ORA) +rOP16(19M0X1, AbsoluteIndexedYX1, WRAP_NONE, ORA) +rOP8 (19M1X0, AbsoluteIndexedYX0, WRAP_NONE, ORA) +rOP16(19M0X0, AbsoluteIndexedYX0, WRAP_NONE, ORA) +rOPM (19Slow, AbsoluteIndexedYSlow, WRAP_NONE, ORA) + +rOP8 (0FM1, AbsoluteLong, WRAP_NONE, ORA) +rOP16(0FM0, AbsoluteLong, WRAP_NONE, ORA) +rOPM (0FSlow, AbsoluteLongSlow, WRAP_NONE, ORA) + +rOP8 (1FM1, AbsoluteLongIndexedX, WRAP_NONE, ORA) +rOP16(1FM0, AbsoluteLongIndexedX, WRAP_NONE, ORA) +rOPM (1FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ORA) + +rOP8 (03M1, StackRelative, WRAP_NONE, ORA) +rOP16(03M0, StackRelative, WRAP_NONE, ORA) +rOPM (03Slow, StackRelativeSlow, WRAP_NONE, ORA) + +rOP8 (13M1, StackRelativeIndirectIndexed, WRAP_NONE, ORA) +rOP16(13M0, StackRelativeIndirectIndexed, WRAP_NONE, ORA) +rOPM (13Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ORA) + +/*****************************************************************************/ + +/* ROL ********************************************************************* */ +static void Op2AM1 (void) { + AddCycles(ONE_CYCLE); + uint16 w = (((uint16)Registers.AL)<<1) | CheckCarry(); + ICPU._Carry = w>=0x100; + Registers.AL = (uint8)w; + SetZN (Registers.AL); +} + +static void Op2AM0 (void) { + AddCycles(ONE_CYCLE); + uint32 w = (((uint32)Registers.A.W)<<1) | CheckCarry(); + ICPU._Carry = w>=0x10000; + Registers.A.W = (uint16)w; + SetZN (Registers.A.W); +} + +static void Op2ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + uint16 w = (((uint16)Registers.AL)<<1) | CheckCarry(); + ICPU._Carry = w>=0x100; + Registers.AL = (uint8)w; + SetZN (Registers.AL); + } else { + uint32 w = (((uint32)Registers.A.W)<<1) | CheckCarry(); + ICPU._Carry = w>=0x10000; + Registers.A.W = (uint16)w; + SetZN (Registers.A.W); + } +} + +mOP8 (26M1, Direct, WRAP_BANK, ROL) +mOP16(26M0, Direct, WRAP_BANK, ROL) +mOPM (26Slow, DirectSlow, WRAP_BANK, ROL) + +mOP8 (36E1, DirectIndexedXE1, WRAP_BANK, ROL) +mOP8 (36E0M1, DirectIndexedXE0, WRAP_BANK, ROL) +mOP16(36E0M0, DirectIndexedXE0, WRAP_BANK, ROL) +mOPM (36Slow, DirectIndexedXSlow, WRAP_BANK, ROL) + +mOP8 (2EM1, Absolute, WRAP_NONE, ROL) +mOP16(2EM0, Absolute, WRAP_NONE, ROL) +mOPM (2ESlow, AbsoluteSlow, WRAP_NONE, ROL) + +mOP8 (3EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROL) +mOP16(3EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROL) +mOP8 (3EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROL) +mOP16(3EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROL) +mOPM (3ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROL) + +/*****************************************************************************/ + +/* ROR ********************************************************************* */ +static void Op6AM1 (void) { + AddCycles(ONE_CYCLE); + uint16 w = ((uint16)Registers.AL) | (((uint16)CheckCarry())<<8); + ICPU._Carry = w&1; + w>>=1; + Registers.AL = (uint8)w; + SetZN (Registers.AL); +} + +static void Op6AM0 (void) { + AddCycles(ONE_CYCLE); + uint32 w = ((uint32)Registers.A.W) | (((uint32)CheckCarry())<<16); + ICPU._Carry = w&1; + w>>=1; + Registers.A.W = (uint16)w; + SetZN (Registers.A.W); +} + +static void Op6ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + uint16 w = ((uint16)Registers.AL) | (((uint16)CheckCarry())<<8); + ICPU._Carry = w&1; + w>>=1; + Registers.AL = (uint8)w; + SetZN (Registers.AL); + } else { + uint32 w = ((uint32)Registers.A.W) | (((uint32)CheckCarry())<<16); + ICPU._Carry = w&1; + w>>=1; + Registers.A.W = (uint16)w; + SetZN (Registers.A.W); + } +} + +mOP8 (66M1, Direct, WRAP_BANK, ROR) +mOP16(66M0, Direct, WRAP_BANK, ROR) +mOPM (66Slow, DirectSlow, WRAP_BANK, ROR) + +mOP8 (76E1, DirectIndexedXE1, WRAP_BANK, ROR) +mOP8 (76E0M1, DirectIndexedXE0, WRAP_BANK, ROR) +mOP16(76E0M0, DirectIndexedXE0, WRAP_BANK, ROR) +mOPM (76Slow, DirectIndexedXSlow, WRAP_BANK, ROR) + +mOP8 (6EM1, Absolute, WRAP_NONE, ROR) +mOP16(6EM0, Absolute, WRAP_NONE, ROR) +mOPM (6ESlow, AbsoluteSlow, WRAP_NONE, ROR) + +mOP8 (7EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROR) +mOP16(7EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROR) +mOP8 (7EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROR) +mOP16(7EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROR) +mOPM (7ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROR) + +/*****************************************************************************/ + +/* SBC ********************************************************************* */ +static void OpE9M1 (void) { + SBC(Immediate8(READ)); +} + +static void OpE9M0 (void) { + SBC(Immediate16(READ)); +} + +static void OpE9Slow (void) { + if(CheckMemory()) { + SBC(Immediate8Slow(READ)); + } else { + SBC(Immediate16Slow(READ)); + } +} + +rOP8 (E5M1, Direct, WRAP_BANK, SBC) +rOP16(E5M0, Direct, WRAP_BANK, SBC) +rOPM (E5Slow, DirectSlow, WRAP_BANK, SBC) + +rOP8 (F5E1, DirectIndexedXE1, WRAP_BANK, SBC) +rOP8 (F5E0M1, DirectIndexedXE0, WRAP_BANK, SBC) +rOP16(F5E0M0, DirectIndexedXE0, WRAP_BANK, SBC) +rOPM (F5Slow, DirectIndexedXSlow, WRAP_BANK, SBC) + +rOP8 (F2E1, DirectIndirectE1, WRAP_NONE, SBC) +rOP8 (F2E0M1, DirectIndirectE0, WRAP_NONE, SBC) +rOP16(F2E0M0, DirectIndirectE0, WRAP_NONE, SBC) +rOPM (F2Slow, DirectIndirectSlow, WRAP_NONE, SBC) + +rOP8 (E1E1, DirectIndexedIndirectE1, WRAP_NONE, SBC) +rOP8 (E1E0M1, DirectIndexedIndirectE0, WRAP_NONE, SBC) +rOP16(E1E0M0, DirectIndexedIndirectE0, WRAP_NONE, SBC) +rOPM (E1Slow, DirectIndexedIndirectSlow, WRAP_NONE, SBC) + +rOP8 (F1E1, DirectIndirectIndexedE1, WRAP_NONE, SBC) +rOP8 (F1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC) +rOP16(F1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC) +rOP8 (F1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC) +rOP16(F1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC) +rOPM (F1Slow, DirectIndirectIndexedSlow, WRAP_NONE, SBC) + +rOP8 (E7M1, DirectIndirectLong, WRAP_NONE, SBC) +rOP16(E7M0, DirectIndirectLong, WRAP_NONE, SBC) +rOPM (E7Slow, DirectIndirectLongSlow, WRAP_NONE, SBC) + +rOP8 (F7M1, DirectIndirectIndexedLong, WRAP_NONE, SBC) +rOP16(F7M0, DirectIndirectIndexedLong, WRAP_NONE, SBC) +rOPM (F7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, SBC) + +rOP8 (EDM1, Absolute, WRAP_NONE, SBC) +rOP16(EDM0, Absolute, WRAP_NONE, SBC) +rOPM (EDSlow, AbsoluteSlow, WRAP_NONE, SBC) + +rOP8 (FDM1X1, AbsoluteIndexedXX1, WRAP_NONE, SBC) +rOP16(FDM0X1, AbsoluteIndexedXX1, WRAP_NONE, SBC) +rOP8 (FDM1X0, AbsoluteIndexedXX0, WRAP_NONE, SBC) +rOP16(FDM0X0, AbsoluteIndexedXX0, WRAP_NONE, SBC) +rOPM (FDSlow, AbsoluteIndexedXSlow, WRAP_NONE, SBC) + +rOP8 (F9M1X1, AbsoluteIndexedYX1, WRAP_NONE, SBC) +rOP16(F9M0X1, AbsoluteIndexedYX1, WRAP_NONE, SBC) +rOP8 (F9M1X0, AbsoluteIndexedYX0, WRAP_NONE, SBC) +rOP16(F9M0X0, AbsoluteIndexedYX0, WRAP_NONE, SBC) +rOPM (F9Slow, AbsoluteIndexedYSlow, WRAP_NONE, SBC) + +rOP8 (EFM1, AbsoluteLong, WRAP_NONE, SBC) +rOP16(EFM0, AbsoluteLong, WRAP_NONE, SBC) +rOPM (EFSlow, AbsoluteLongSlow, WRAP_NONE, SBC) + +rOP8 (FFM1, AbsoluteLongIndexedX, WRAP_NONE, SBC) +rOP16(FFM0, AbsoluteLongIndexedX, WRAP_NONE, SBC) +rOPM (FFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, SBC) + +rOP8 (E3M1, StackRelative, WRAP_NONE, SBC) +rOP16(E3M0, StackRelative, WRAP_NONE, SBC) +rOPM (E3Slow, StackRelativeSlow, WRAP_NONE, SBC) + +rOP8 (F3M1, StackRelativeIndirectIndexed, WRAP_NONE, SBC) +rOP16(F3M0, StackRelativeIndirectIndexed, WRAP_NONE, SBC) +rOPM (F3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, SBC) + +/*****************************************************************************/ + +/* STA ********************************************************************* */ +wOP8 (85M1, Direct, WRAP_BANK, STA) +wOP16(85M0, Direct, WRAP_BANK, STA) +wOPM (85Slow, DirectSlow, WRAP_BANK, STA) + +wOP8 (95E1, DirectIndexedXE1, WRAP_BANK, STA) +wOP8 (95E0M1, DirectIndexedXE0, WRAP_BANK, STA) +wOP16(95E0M0, DirectIndexedXE0, WRAP_BANK, STA) +wOPM (95Slow, DirectIndexedXSlow, WRAP_BANK, STA) + +wOP8 (92E1, DirectIndirectE1, WRAP_NONE, STA) +wOP8 (92E0M1, DirectIndirectE0, WRAP_NONE, STA) +wOP16(92E0M0, DirectIndirectE0, WRAP_NONE, STA) +wOPM (92Slow, DirectIndirectSlow, WRAP_NONE, STA) + +wOP8 (81E1, DirectIndexedIndirectE1, WRAP_NONE, STA) +wOP8 (81E0M1, DirectIndexedIndirectE0, WRAP_NONE, STA) +wOP16(81E0M0, DirectIndexedIndirectE0, WRAP_NONE, STA) +wOPM (81Slow, DirectIndexedIndirectSlow, WRAP_NONE, STA) + +wOP8 (91E1, DirectIndirectIndexedE1, WRAP_NONE, STA) +wOP8 (91E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA) +wOP16(91E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA) +wOP8 (91E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA) +wOP16(91E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA) +wOPM (91Slow, DirectIndirectIndexedSlow, WRAP_NONE, STA) + +wOP8 (87M1, DirectIndirectLong, WRAP_NONE, STA) +wOP16(87M0, DirectIndirectLong, WRAP_NONE, STA) +wOPM (87Slow, DirectIndirectLongSlow, WRAP_NONE, STA) + +wOP8 (97M1, DirectIndirectIndexedLong, WRAP_NONE, STA) +wOP16(97M0, DirectIndirectIndexedLong, WRAP_NONE, STA) +wOPM (97Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, STA) + +wOP8 (8DM1, Absolute, WRAP_NONE, STA) +wOP16(8DM0, Absolute, WRAP_NONE, STA) +wOPM (8DSlow, AbsoluteSlow, WRAP_NONE, STA) + +wOP8 (9DM1X1, AbsoluteIndexedXX1, WRAP_NONE, STA) +wOP16(9DM0X1, AbsoluteIndexedXX1, WRAP_NONE, STA) +wOP8 (9DM1X0, AbsoluteIndexedXX0, WRAP_NONE, STA) +wOP16(9DM0X0, AbsoluteIndexedXX0, WRAP_NONE, STA) +wOPM (9DSlow, AbsoluteIndexedXSlow, WRAP_NONE, STA) + +wOP8 (99M1X1, AbsoluteIndexedYX1, WRAP_NONE, STA) +wOP16(99M0X1, AbsoluteIndexedYX1, WRAP_NONE, STA) +wOP8 (99M1X0, AbsoluteIndexedYX0, WRAP_NONE, STA) +wOP16(99M0X0, AbsoluteIndexedYX0, WRAP_NONE, STA) +wOPM (99Slow, AbsoluteIndexedYSlow, WRAP_NONE, STA) + +wOP8 (8FM1, AbsoluteLong, WRAP_NONE, STA) +wOP16(8FM0, AbsoluteLong, WRAP_NONE, STA) +wOPM (8FSlow, AbsoluteLongSlow, WRAP_NONE, STA) + +wOP8 (9FM1, AbsoluteLongIndexedX, WRAP_NONE, STA) +wOP16(9FM0, AbsoluteLongIndexedX, WRAP_NONE, STA) +wOPM (9FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, STA) + +wOP8 (83M1, StackRelative, WRAP_NONE, STA) +wOP16(83M0, StackRelative, WRAP_NONE, STA) +wOPM (83Slow, StackRelativeSlow, WRAP_NONE, STA) + +wOP8 (93M1, StackRelativeIndirectIndexed, WRAP_NONE, STA) +wOP16(93M0, StackRelativeIndirectIndexed, WRAP_NONE, STA) +wOPM (93Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, STA) + +/*****************************************************************************/ + +/* STX ********************************************************************* */ + +wOP8 (86X1, Direct, WRAP_BANK, STX) +wOP16(86X0, Direct, WRAP_BANK, STX) +wOPX (86Slow, DirectSlow, WRAP_BANK, STX) + +wOP8 (96E1, DirectIndexedYE1, WRAP_BANK, STX) +wOP8 (96E0X1, DirectIndexedYE0, WRAP_BANK, STX) +wOP16(96E0X0, DirectIndexedYE0, WRAP_BANK, STX) +wOPX (96Slow, DirectIndexedYSlow, WRAP_BANK, STX) + +wOP8 (8EX1, Absolute, WRAP_BANK, STX) +wOP16(8EX0, Absolute, WRAP_BANK, STX) +wOPX (8ESlow, AbsoluteSlow, WRAP_BANK, STX) + +/*****************************************************************************/ + +/* STY ********************************************************************* */ + +wOP8 (84X1, Direct, WRAP_BANK, STY) +wOP16(84X0, Direct, WRAP_BANK, STY) +wOPX (84Slow, DirectSlow, WRAP_BANK, STY) + +wOP8 (94E1, DirectIndexedXE1, WRAP_BANK, STY) +wOP8 (94E0X1, DirectIndexedXE0, WRAP_BANK, STY) +wOP16(94E0X0, DirectIndexedXE0, WRAP_BANK, STY) +wOPX (94Slow, DirectIndexedXSlow, WRAP_BANK, STY) + +wOP8 (8CX1, Absolute, WRAP_BANK, STY) +wOP16(8CX0, Absolute, WRAP_BANK, STY) +wOPX (8CSlow, AbsoluteSlow, WRAP_BANK, STY) + +/*****************************************************************************/ + +/* STZ ********************************************************************* */ + +wOP8 (64M1, Direct, WRAP_BANK, STZ) +wOP16(64M0, Direct, WRAP_BANK, STZ) +wOPM (64Slow, DirectSlow, WRAP_BANK, STZ) + +wOP8 (74E1, DirectIndexedXE1, WRAP_BANK, STZ) +wOP8 (74E0M1, DirectIndexedXE0, WRAP_BANK, STZ) +wOP16(74E0M0, DirectIndexedXE0, WRAP_BANK, STZ) +wOPM (74Slow, DirectIndexedXSlow, WRAP_BANK, STZ) + +wOP8 (9CM1, Absolute, WRAP_NONE, STZ) +wOP16(9CM0, Absolute, WRAP_NONE, STZ) +wOPM (9CSlow, AbsoluteSlow, WRAP_NONE, STZ) + +wOP8 (9EM1X1, AbsoluteIndexedXX1, WRAP_NONE, STZ) +wOP16(9EM0X1, AbsoluteIndexedXX1, WRAP_NONE, STZ) +wOP8 (9EM1X0, AbsoluteIndexedXX0, WRAP_NONE, STZ) +wOP16(9EM0X0, AbsoluteIndexedXX0, WRAP_NONE, STZ) +wOPM (9ESlow, AbsoluteIndexedXSlow, WRAP_NONE, STZ) + +/*****************************************************************************/ + +/* TRB ********************************************************************* */ + +mOP8 (14M1, Direct, WRAP_BANK, TRB) +mOP16(14M0, Direct, WRAP_BANK, TRB) +mOPM (14Slow, DirectSlow, WRAP_BANK, TRB) + +mOP8 (1CM1, Absolute, WRAP_BANK, TRB) +mOP16(1CM0, Absolute, WRAP_BANK, TRB) +mOPM (1CSlow, AbsoluteSlow, WRAP_BANK, TRB) + +/*****************************************************************************/ + +/* TSB ********************************************************************* */ + +mOP8 (04M1, Direct, WRAP_BANK, TSB) +mOP16(04M0, Direct, WRAP_BANK, TSB) +mOPM (04Slow, DirectSlow, WRAP_BANK, TSB) + +mOP8 (0CM1, Absolute, WRAP_BANK, TSB) +mOP16(0CM0, Absolute, WRAP_BANK, TSB) +mOPM (0CSlow, AbsoluteSlow, WRAP_BANK, TSB) + +/*****************************************************************************/ + +/* Branch Instructions ***************************************************** */ +#ifndef SA1_OPCODES +#define BranchCheck0()\ + if( CPU.BranchSkip) {\ + CPU.BranchSkip = FALSE;\ + if (!Settings.SoundSkipMethod) \ + if( Registers.PCw > newPC.W) \ + return; \ + } + +#define BranchCheck1()\ + if( CPU.BranchSkip)\ + {\ + CPU.BranchSkip = FALSE;\ + if (!Settings.SoundSkipMethod) {\ + if( Registers.PCw > newPC.W)\ + return;\ + } else \ + if (Settings.SoundSkipMethod == 1)\ + return;\ + if (Settings.SoundSkipMethod == 3)\ + if( Registers.PCw > newPC.W)\ + return;\ + else\ + Registers.PCw = newPC.W;\ + } + +#define BranchCheck2()\ + if( CPU.BranchSkip)\ + {\ + CPU.BranchSkip = FALSE;\ + if (!Settings.SoundSkipMethod) {\ + if( Registers.PCw > newPC.W)\ + return;\ + } else \ + if (Settings.SoundSkipMethod == 1)\ + Registers.PCw = newPC.W;\ + if (Settings.SoundSkipMethod == 3)\ + if (Registers.PCw > newPC.W)\ + return;\ + else\ + Registers.PCw = newPC.W;\ + } +#else +#define BranchCheck0() +#define BranchCheck1() +#define BranchCheck2() +#endif +#define BranchCheckX() + +#ifdef CPU_SHUTDOWN +#ifndef SA1_OPCODES +inline void CPUShutdown() +{ + if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress) + { + // Don't skip cycles with a pending NMI or IRQ - could cause delayed + // interrupt. Interrupts are delayed for a few cycles already, but + // the delay could allow the shutdown code to cycle skip again. + // Was causing screen flashing on Top Gear 3000. + + if (CPU.WaitCounter == 0 && + !(CPU.Flags & (IRQ_PENDING_FLAG | NMI_FLAG))) + { + CPU.WaitAddress = 0xffffffff; + if (Settings.SA1) + S9xSA1ExecuteDuringSleep (); + CPU.Cycles = CPU.NextEvent; + S9xUpdateAPUTimer(); + if (IAPU.APUExecuting) + { + ICPU.CPUExecuting = FALSE; + do + { + APU_EXECUTE1(); + } while (APU.Cycles < CPU.NextEvent); + ICPU.CPUExecuting = TRUE; + } + } + else + if (CPU.WaitCounter >= 2) + CPU.WaitCounter = 1; + else + CPU.WaitCounter--; + } +} +#else +inline void CPUShutdown() +{ + if (Settings.Shutdown && Registers.PBPC == CPU.WaitAddress) + { + if (CPU.WaitCounter >= 1) + { + SA1.Executing = FALSE; + SA1.CPUExecuting = FALSE; + } + else + CPU.WaitCounter++; + } +} +#endif +#else +#define CPUShutdown() +#endif + +/* BCC */ +bOP(90E0, !CheckCarry(), 0, 0) +bOP(90E1, !CheckCarry(), 0, 1) +bOP(90Slow, !CheckCarry(), 0, CheckEmulation()) + +/* BCS */ +bOP(B0E0, CheckCarry(), 0, 0) +bOP(B0E1, CheckCarry(), 0, 1) +bOP(B0Slow, CheckCarry(), 0, CheckEmulation()) + +/* BEQ */ +bOP(F0E0, CheckZero(), 2, 0) +bOP(F0E1, CheckZero(), 2, 1) +bOP(F0Slow, CheckZero(), 2, CheckEmulation()) + +/* BMI */ +bOP(30E0, CheckNegative(), 1, 0) +bOP(30E1, CheckNegative(), 1, 1) +bOP(30Slow, CheckNegative(), 1, CheckEmulation()) + +/* BNE */ +bOP(D0E0, !CheckZero(), 1, 0) +bOP(D0E1, !CheckZero(), 1, 1) +bOP(D0Slow, !CheckZero(), 1, CheckEmulation()) + +/* BPL */ +bOP(10E0, !CheckNegative(), 1, 0) +bOP(10E1, !CheckNegative(), 1, 1) +bOP(10Slow, !CheckNegative(), 1, CheckEmulation()) + +/* BRA */ +bOP(80E0, 1, X, 0) +bOP(80E1, 1, X, 1) +bOP(80Slow, 1, X, CheckEmulation()) + +/* BVC */ +bOP(50E0, !CheckOverflow(), 0, 0) +bOP(50E1, !CheckOverflow(), 0, 1) +bOP(50Slow, !CheckOverflow(), 0, CheckEmulation()) + +/* BVS */ +bOP(70E0, CheckOverflow(), 0, 0) +bOP(70E1, CheckOverflow(), 0, 1) +bOP(70Slow, CheckOverflow(), 0, CheckEmulation()) + +/* BRL */ +static void Op82 (void) { + S9xSetPCBase(ICPU.ShiftedPB + RelativeLong(JUMP)); +} + +/*****************************************************************************/ + +/* Flag Instructions ******************************************************* */ + +/* CLC */ +static void Op18 (void) { + ClearCarry (); + AddCycles(ONE_CYCLE); +} + +/* SEC */ +static void Op38 (void) { + SetCarry (); + AddCycles(ONE_CYCLE); +} + +/* CLD */ +static void OpD8 (void) { + ClearDecimal (); + AddCycles(ONE_CYCLE); +} + +/* SED */ +static void OpF8 (void) { + SetDecimal (); + AddCycles(ONE_CYCLE); + missing.decimal_mode = 1; +} + +/* CLI */ +static void Op58 (void) { + ClearIRQ (); + AddCycles(ONE_CYCLE); +/* CHECK_FOR_IRQ(); */ +} + +/* SEI */ +static void Op78 (void) { + SetIRQ (); + AddCycles(ONE_CYCLE); +} + +/* CLV */ +static void OpB8 (void) { + ClearOverflow (); + AddCycles(ONE_CYCLE); +} + +/*****************************************************************************/ + +/* DEX/DEY ***************************************************************** */ + +static void OpCAX1 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.XL--; + SetZN (Registers.XL); +} + +static void OpCAX0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.X.W--; + SetZN (Registers.X.W); +} + +static void OpCASlow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckIndex()){ + Registers.XL--; + SetZN (Registers.XL); + } else { + Registers.X.W--; + SetZN (Registers.X.W); + } +} + +static void Op88X1 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.YL--; + SetZN (Registers.YL); +} + +static void Op88X0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.Y.W--; + SetZN (Registers.Y.W); +} + +static void Op88Slow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckIndex()){ + Registers.YL--; + SetZN (Registers.YL); + } else { + Registers.Y.W--; + SetZN (Registers.Y.W); + } +} + +/*****************************************************************************/ + +/* INX/INY ***************************************************************** */ +static void OpE8X1 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.XL++; + SetZN (Registers.XL); +} + +static void OpE8X0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.X.W++; + SetZN (Registers.X.W); +} + +static void OpE8Slow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckIndex()){ + Registers.XL++; + SetZN (Registers.XL); + } else { + Registers.X.W++; + SetZN (Registers.X.W); + } +} + +static void OpC8X1 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.YL++; + SetZN (Registers.YL); +} + +static void OpC8X0 (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + Registers.Y.W++; + SetZN (Registers.Y.W); +} + +static void OpC8Slow (void) { + AddCycles(ONE_CYCLE); +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = 0xffffffff; +#endif + if(CheckIndex()){ + Registers.YL--; + SetZN (Registers.YL); + } else { + Registers.Y.W--; + SetZN (Registers.Y.W); + } +} + +/*****************************************************************************/ + +/* NOP ********************************************************************* */ +static void OpEA (void) { + AddCycles(ONE_CYCLE); +} + +/*****************************************************************************/ + +/* PUSH Instructions ******************************************************* */ +#define PushW(w) \ + S9xSetWord(w, Registers.S.W - 1, WRAP_BANK, WRITE_10); \ + Registers.S.W -= 2; + +#define PushWE(w) \ + Registers.SL--; \ + S9xSetWord(w, Registers.S.W, WRAP_PAGE, WRITE_10); \ + Registers.SL--; + +#define PushB(b) \ + S9xSetByte(b, Registers.S.W--); + +#define PushBE(b) \ + S9xSetByte (b, Registers.S.W); \ + Registers.SL--; + +/* PEA */ +static void OpF4E0 (void) { + uint16 val=(uint16)Absolute(NONE); + PushW(val); + OpenBus = val&0xff; +} + +static void OpF4E1 (void) { + /* Note: PEA is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + uint16 val=(uint16)Absolute(NONE); + PushW(val); + OpenBus = val&0xff; + Registers.SH=1; +} + +static void OpF4Slow (void) { + uint16 val=(uint16)AbsoluteSlow(NONE); + PushW(val); + OpenBus = val&0xff; + if(CheckEmulation()) Registers.SH=1; +} + +/* PEI */ +static void OpD4E0 (void) { + uint16 val=(uint16)DirectIndirectE0(NONE); + PushW(val); + OpenBus = val&0xff; +} + +static void OpD4E1 (void) { + /* Note: PEI is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + uint16 val=(uint16)DirectIndirectE1(NONE); + PushW(val); + OpenBus = val&0xff; + Registers.SH=1; +} + +static void OpD4Slow (void) { + uint16 val=(uint16)DirectIndirectSlow(NONE); + PushW(val); + OpenBus = val&0xff; + if(CheckEmulation()) Registers.SH=1; +} + +/* PER */ +static void Op62E0 (void) { + uint16 val=(uint16)RelativeLong(NONE); + PushW(val); + OpenBus = val&0xff; +} + +static void Op62E1 (void) { + /* Note: PER is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + uint16 val=(uint16)RelativeLong(NONE); + PushW(val); + OpenBus = val&0xff; + Registers.SH=1; +} + +static void Op62Slow (void) { + uint16 val=(uint16)RelativeLongSlow(NONE); + PushW(val); + OpenBus = val&0xff; + if(CheckEmulation()) Registers.SH=1; +} + +/* PHA */ +static void Op48E1 (void) { + AddCycles(ONE_CYCLE); + PushBE(Registers.AL); + OpenBus = Registers.AL; +} + +static void Op48E0M1 (void) { + AddCycles(ONE_CYCLE); + PushB(Registers.AL); + OpenBus = Registers.AL; +} + +static void Op48E0M0 (void) { + AddCycles(ONE_CYCLE); + PushW(Registers.A.W); + OpenBus = Registers.AL; +} + +static void Op48Slow (void) { + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE(Registers.AL); + } else if(CheckMemory()){ + PushB(Registers.AL); + } else { + PushW(Registers.A.W); + } + OpenBus = Registers.AL; +} + +/* PHB */ +static void Op8BE1 (void) { + AddCycles(ONE_CYCLE); + PushBE (Registers.DB); + OpenBus = Registers.DB; +} + +static void Op8BE0 (void) { + AddCycles(ONE_CYCLE); + PushB (Registers.DB); + OpenBus = Registers.DB; +} + +static void Op8BSlow (void) { + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE (Registers.DB); + } else { + PushB (Registers.DB); + } + OpenBus = Registers.DB; +} + +/* PHD */ +static void Op0BE0 (void) { + AddCycles(ONE_CYCLE); + PushW (Registers.D.W); + OpenBus = Registers.DL; +} + +static void Op0BE1 (void) { + /* Note: PHD is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + AddCycles(ONE_CYCLE); + PushW (Registers.D.W); + OpenBus = Registers.DL; + Registers.SH=1; +} + +static void Op0BSlow (void) { + AddCycles(ONE_CYCLE); + PushW (Registers.D.W); + OpenBus = Registers.DL; + if(CheckEmulation()) Registers.SH=1; +} + +/* PHK */ +static void Op4BE1 (void) { + AddCycles(ONE_CYCLE); + PushBE (Registers.PB); + OpenBus = Registers.PB; +} + +static void Op4BE0 (void) { + AddCycles(ONE_CYCLE); + PushB (Registers.PB); + OpenBus = Registers.PB; +} + +static void Op4BSlow (void) { + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE (Registers.PB); + } else { + PushB (Registers.PB); + } + OpenBus = Registers.PB; +} + +/* PHP */ +static void Op08E0 (void) { + S9xPackStatus (); + AddCycles(ONE_CYCLE); + PushB (Registers.PL); + OpenBus = Registers.PL; +} + +static void Op08E1 (void) { + S9xPackStatus (); + AddCycles(ONE_CYCLE); + PushBE (Registers.PL); + OpenBus = Registers.PL; +} + +static void Op08Slow (void) { + S9xPackStatus (); + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE (Registers.PL); + } else { + PushB (Registers.PL); + } + OpenBus = Registers.PL; +} + +/* PHX */ +static void OpDAE1 (void) { + AddCycles(ONE_CYCLE); + PushBE (Registers.XL); + OpenBus = Registers.XL; +} + +static void OpDAE0X1 (void) { + AddCycles(ONE_CYCLE); + PushB(Registers.XL); + OpenBus = Registers.XL; +} + +static void OpDAE0X0 (void) { + AddCycles(ONE_CYCLE); + PushW(Registers.X.W); + OpenBus = Registers.XL; +} + +static void OpDASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE(Registers.XL); + } else if(CheckIndex()){ + PushB(Registers.XL); + } else { + PushW(Registers.X.W); + } + OpenBus = Registers.XL; +} + +/* PHY */ +static void Op5AE1 (void) { + AddCycles(ONE_CYCLE); + PushBE (Registers.YL); + OpenBus = Registers.YL; +} + +static void Op5AE0X1 (void) { + AddCycles(ONE_CYCLE); + PushB(Registers.YL); + OpenBus = Registers.YL; +} + +static void Op5AE0X0 (void) { + AddCycles(ONE_CYCLE); + PushW(Registers.Y.W); + OpenBus = Registers.YL; +} + +static void Op5ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushBE(Registers.YL); + } else if(CheckIndex()){ + PushB(Registers.YL); + } else { + PushW(Registers.Y.W); + } + OpenBus = Registers.YL; +} + +/*****************************************************************************/ + +/* PULL Instructions ******************************************************* */ +#define PullW(w) \ + w = S9xGetWord(Registers.S.W + 1, WRAP_BANK); \ + Registers.S.W += 2; + +#define PullWE(w) \ + Registers.SL++; \ + w = S9xGetWord(Registers.S.W, WRAP_PAGE); \ + Registers.SL++; + +#define PullB(b) \ + b = S9xGetByte(++Registers.S.W); + +#define PullBE(b) \ + Registers.SL++; \ + b = S9xGetByte(Registers.S.W); + +/* PLA */ +static void Op68E1 (void) { + AddCycles(TWO_CYCLES); + PullBE (Registers.AL); + SetZN (Registers.AL); + OpenBus = Registers.AL; +} + +static void Op68E0M1 (void) { + AddCycles(TWO_CYCLES); + PullB (Registers.AL); + SetZN (Registers.AL); + OpenBus = Registers.AL; +} + +static void Op68E0M0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.A.W); + SetZN (Registers.A.W); + OpenBus = Registers.AH; +} + +static void Op68Slow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullBE (Registers.AL); + SetZN (Registers.AL); + OpenBus = Registers.AL; + } else if(CheckMemory()){ + PullB (Registers.AL); + SetZN (Registers.AL); + OpenBus = Registers.AL; + } else { + PullW (Registers.A.W); + SetZN (Registers.A.W); + OpenBus = Registers.AH; + } +} + +/* PLB */ +static void OpABE1 (void) { + AddCycles(TWO_CYCLES); + PullBE (Registers.DB); + SetZN (Registers.DB); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = Registers.DB; +} + +static void OpABE0 (void) { + AddCycles(TWO_CYCLES); + PullB (Registers.DB); + SetZN (Registers.DB); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = Registers.DB; +} + +static void OpABSlow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullBE (Registers.DB); + } else { + PullB (Registers.DB); + } + SetZN (Registers.DB); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = Registers.DB; +} + +/* PLD */ +static void Op2BE0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.D.W); + SetZN (Registers.D.W); + OpenBus = Registers.DH; +} + +static void Op2BE1 (void) { + /* Note: PHD is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + AddCycles(TWO_CYCLES); + PullW (Registers.D.W); + SetZN (Registers.D.W); + OpenBus = Registers.DH; + Registers.SH=1; +} + +static void Op2BSlow (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.D.W); + SetZN (Registers.D.W); + OpenBus = Registers.DH; + if(CheckEmulation()) Registers.SH=1; +} + +/* PLP */ +static void Op28E1 (void) { + AddCycles(TWO_CYCLES); + PullBE (Registers.PL); + OpenBus = Registers.PL; + SetFlags (MemoryFlag | IndexFlag); + S9xUnpackStatus (); + S9xFixCycles(); +/* CHECK_FOR_IRQ();*/ +} + +static void Op28E0 (void) { + AddCycles(TWO_CYCLES); + PullB (Registers.PL); + OpenBus = Registers.PL; + S9xUnpackStatus (); + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +/* CHECK_FOR_IRQ();*/ +} + +static void Op28Slow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullBE (Registers.PL); + OpenBus = Registers.PL; + SetFlags (MemoryFlag | IndexFlag); + } else { + PullB (Registers.PL); + OpenBus = Registers.PL; + } + S9xUnpackStatus (); + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +/* CHECK_FOR_IRQ();*/ +} + +/* PLX */ +static void OpFAE1 (void) { + AddCycles(TWO_CYCLES); + PullBE (Registers.XL); + SetZN (Registers.XL); + OpenBus = Registers.XL; +} + +static void OpFAE0X1 (void) { + AddCycles(TWO_CYCLES); + PullB (Registers.XL); + SetZN (Registers.XL); + OpenBus = Registers.XL; +} + +static void OpFAE0X0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.X.W); + SetZN (Registers.X.W); + OpenBus = Registers.XH; +} + +static void OpFASlow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullBE (Registers.XL); + SetZN (Registers.XL); + OpenBus = Registers.XL; + } else if(CheckIndex()){ + PullB (Registers.XL); + SetZN (Registers.XL); + OpenBus = Registers.XL; + } else { + PullW (Registers.X.W); + SetZN (Registers.X.W); + OpenBus = Registers.XH; + } +} + +/* PLY */ +static void Op7AE1 (void) { + AddCycles(TWO_CYCLES); + PullBE (Registers.YL); + SetZN (Registers.YL); + OpenBus = Registers.YL; +} + +static void Op7AE0X1 (void) { + AddCycles(TWO_CYCLES); + PullB (Registers.YL); + SetZN (Registers.YL); + OpenBus = Registers.YL; +} + +static void Op7AE0X0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.Y.W); + SetZN (Registers.Y.W); + OpenBus = Registers.YH; +} + +static void Op7ASlow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullBE (Registers.YL); + SetZN (Registers.YL); + OpenBus = Registers.YL; + } else if(CheckIndex()){ + PullB (Registers.YL); + SetZN (Registers.YL); + OpenBus = Registers.YL; + } else { + PullW (Registers.Y.W); + SetZN (Registers.Y.W); + OpenBus = Registers.YH; + } +} + +/*****************************************************************************/ + +/* Transfer Instructions *************************************************** */ +/* TAX */ +static void OpAAX1 (void) { + AddCycles(ONE_CYCLE); + Registers.XL = Registers.AL; + SetZN (Registers.XL); +} + +static void OpAAX0 (void) { + AddCycles(ONE_CYCLE); + Registers.X.W = Registers.A.W; + SetZN (Registers.X.W); +} + +static void OpAASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckIndex()){ + Registers.XL = Registers.AL; + SetZN (Registers.XL); + } else { + Registers.X.W = Registers.A.W; + SetZN (Registers.X.W); + } +} + +/* TAY */ +static void OpA8X1 (void) { + AddCycles(ONE_CYCLE); + Registers.YL = Registers.AL; + SetZN (Registers.YL); +} + +static void OpA8X0 (void) { + AddCycles(ONE_CYCLE); + Registers.Y.W = Registers.A.W; + SetZN (Registers.Y.W); +} + +static void OpA8Slow (void) { + AddCycles(ONE_CYCLE); + if(CheckIndex()){ + Registers.YL = Registers.AL; + SetZN (Registers.YL); + } else { + Registers.Y.W = Registers.A.W; + SetZN (Registers.Y.W); + } +} + +/* TCD */ +static void Op5B (void) { + AddCycles(ONE_CYCLE); + Registers.D.W = Registers.A.W; + SetZN (Registers.D.W); +} + +/* TCS */ +static void Op1B (void) { + AddCycles(ONE_CYCLE); + Registers.S.W = Registers.A.W; + if(CheckEmulation()) Registers.SH = 1; +} + +/* TDC */ +static void Op7B (void) { + AddCycles(ONE_CYCLE); + Registers.A.W = Registers.D.W; + SetZN (Registers.A.W); +} + +/* TSC */ +static void Op3B (void) { + AddCycles(ONE_CYCLE); + Registers.A.W = Registers.S.W; + SetZN (Registers.A.W); +} + +/* TSX */ +static void OpBAX1 (void) { + AddCycles(ONE_CYCLE); + Registers.XL = Registers.SL; + SetZN (Registers.XL); +} + +static void OpBAX0 (void) { + AddCycles(ONE_CYCLE); + Registers.X.W = Registers.S.W; + SetZN (Registers.X.W); +} + +static void OpBASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckIndex()){ + Registers.XL = Registers.SL; + SetZN (Registers.XL); + } else { + Registers.X.W = Registers.S.W; + SetZN (Registers.X.W); + } +} + +/* TXA */ +static void Op8AM1 (void) { + AddCycles(ONE_CYCLE); + Registers.AL = Registers.XL; + SetZN (Registers.AL); +} + +static void Op8AM0 (void) { + AddCycles(ONE_CYCLE); + Registers.A.W = Registers.X.W; + SetZN (Registers.A.W); +} + +static void Op8ASlow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + Registers.AL = Registers.XL; + SetZN (Registers.AL); + } else { + Registers.A.W = Registers.X.W; + SetZN (Registers.A.W); + } +} + +/* TXS */ +static void Op9A (void) { + AddCycles(ONE_CYCLE); + Registers.S.W = Registers.X.W; + if(CheckEmulation()) Registers.SH = 1; +} + +/* TXY */ +static void Op9BX1 (void) { + AddCycles(ONE_CYCLE); + Registers.YL = Registers.XL; + SetZN (Registers.YL); +} + +static void Op9BX0 (void) { + AddCycles(ONE_CYCLE); + Registers.Y.W = Registers.X.W; + SetZN (Registers.Y.W); +} + +static void Op9BSlow (void) { + AddCycles(ONE_CYCLE); + if(CheckIndex()){ + Registers.YL = Registers.XL; + SetZN (Registers.YL); + } else { + Registers.Y.W = Registers.X.W; + SetZN (Registers.Y.W); + } +} + +/* TYA */ +static void Op98M1 (void) { + AddCycles(ONE_CYCLE); + Registers.AL = Registers.YL; + SetZN (Registers.AL); +} + +static void Op98M0 (void) { + AddCycles(ONE_CYCLE); + Registers.A.W = Registers.Y.W; + SetZN (Registers.A.W); +} + +static void Op98Slow (void) { + AddCycles(ONE_CYCLE); + if(CheckMemory()){ + Registers.AL = Registers.YL; + SetZN (Registers.AL); + } else { + Registers.A.W = Registers.Y.W; + SetZN (Registers.A.W); + } +} + +/* TYX */ +static void OpBBX1 (void) { + AddCycles(ONE_CYCLE); + Registers.XL = Registers.YL; + SetZN (Registers.XL); +} + +static void OpBBX0 (void) { + AddCycles(ONE_CYCLE); + Registers.X.W = Registers.Y.W; + SetZN (Registers.X.W); +} + +static void OpBBSlow (void) { + AddCycles(ONE_CYCLE); + if(CheckIndex()){ + Registers.XL = Registers.YL; + SetZN (Registers.XL); + } else { + Registers.X.W = Registers.Y.W; + SetZN (Registers.X.W); + } +} + +/*****************************************************************************/ + +/* XCE ********************************************************************* */ +static void OpFB (void) { + AddCycles(ONE_CYCLE); + + uint8 A1 = ICPU._Carry; + uint8 A2 = Registers.PH; + ICPU._Carry = A2 & 1; + Registers.PH = A1; + + if (CheckEmulation()) { + SetFlags (MemoryFlag | IndexFlag); + Registers.SH = 1; + missing.emulate6502 = 1; + } + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +} + +/*****************************************************************************/ + +/* BRK ********************************************************************* */ +static void Op00 (void) { +#ifdef DEBUGGER + if (CPU.Flags & TRACE_FLAG) + S9xTraceMessage ("*** BRK"); +#endif + +#ifndef SA1_OPCODES + CPU.BRKTriggered = TRUE; +#endif + + AddCycles(CPU.MemSpeed); + + uint16 addr; + if (!CheckEmulation()) { + PushB (Registers.PB); + PushW (Registers.PCw + 1); + S9xPackStatus (); + PushB (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + + addr = S9xGetWord (0xFFE6); + } else { + PushWE (Registers.PCw + 1); + S9xPackStatus (); + PushBE (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + + addr = S9xGetWord (0xFFFE); + } + S9xSetPCBase(addr); + OpenBus = addr>>8; +} + +/*****************************************************************************/ + +/* IRQ ********************************************************************* */ +void S9xOpcode_IRQ (void) { +#ifdef DEBUGGER + if (CPU.Flags & TRACE_FLAG) + S9xTraceMessage ("*** IRQ"); +#endif + + /* IRQ and NMI do an opcode fetch as their first "IO" cycle */ + AddCycles(CPU.MemSpeed + ONE_CYCLE); + + if (!CheckEmulation()) { + PushB (Registers.PB); + PushW (Registers.PCw); + S9xPackStatus (); + PushB (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + +#ifdef SA1_OPCODES + OpenBus = Memory.FillRAM [0x2208]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSA1SetPCBase (Memory.FillRAM [0x2207] | + (Memory.FillRAM [0x2208] << 8)); +#else + if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40)) { + OpenBus = Memory.FillRAM [0x220f]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSetPCBase (Memory.FillRAM [0x220e] | + (Memory.FillRAM [0x220f] << 8)); + } else { + uint16 addr = S9xGetWord (0xFFEE); + OpenBus = addr>>8; + S9xSetPCBase (addr); + } +#endif + } else { + PushWE (Registers.PCw); + S9xPackStatus (); + PushBE (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + +#ifdef SA1_OPCODES + OpenBus = Memory.FillRAM [0x2208]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSA1SetPCBase (Memory.FillRAM [0x2207] | + (Memory.FillRAM [0x2208] << 8)); +#else + if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40)) { + OpenBus = Memory.FillRAM [0x220f]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSetPCBase (Memory.FillRAM [0x220e] | + (Memory.FillRAM [0x220f] << 8)); + } else { + uint16 addr = S9xGetWord (0xFFFE); + OpenBus = addr>>8; + S9xSetPCBase (addr); + } +#endif + } +} + +/*****************************************************************************/ + +/* NMI ********************************************************************* */ +void S9xOpcode_NMI (void) { +#ifdef DEBUGGER + if (CPU.Flags & TRACE_FLAG) + S9xTraceMessage ("*** NMI"); +#endif + + /* IRQ and NMI do an opcode fetch as their first "IO" cycle */ + AddCycles(CPU.MemSpeed + ONE_CYCLE); + + if (!CheckEmulation()) { + PushB (Registers.PB); + PushW (Registers.PCw); + S9xPackStatus (); + PushB (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + +#ifdef SA1_OPCODES + OpenBus = Memory.FillRAM [0x2206]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSA1SetPCBase (Memory.FillRAM [0x2205] | + (Memory.FillRAM [0x2206] << 8)); +#else + if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x20)) { + OpenBus = Memory.FillRAM [0x220d]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSetPCBase (Memory.FillRAM [0x220c] | + (Memory.FillRAM [0x220d] << 8)); + } else { + uint16 addr = S9xGetWord (0xFFEA); + OpenBus = addr>>8; + S9xSetPCBase (addr); + } +#endif + } else { + PushWE (Registers.PCw); + S9xPackStatus (); + PushBE (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + +#ifdef SA1_OPCODES + OpenBus = Memory.FillRAM [0x2206]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSA1SetPCBase (Memory.FillRAM [0x2205] | + (Memory.FillRAM [0x2206] << 8)); +#else + if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x20)) { + OpenBus = Memory.FillRAM [0x220d]; + AddCycles(2*SLOW_ONE_CYCLE); + S9xSetPCBase (Memory.FillRAM [0x220c] | + (Memory.FillRAM [0x220d] << 8)); + } else { + uint16 addr = S9xGetWord (0xFFFA); + OpenBus = addr>>8; + S9xSetPCBase (addr); + } +#endif + } +} + +/*****************************************************************************/ + +/* COP ********************************************************************* */ +static void Op02 (void) { +#ifdef DEBUGGER + if (CPU.Flags & TRACE_FLAG) + S9xTraceMessage ("*** COP"); +#endif + + AddCycles(CPU.MemSpeed); + + uint16 addr; + if (!CheckEmulation()) { + PushB (Registers.PB); + PushW (Registers.PCw + 1); + S9xPackStatus (); + PushB (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + + addr = S9xGetWord (0xFFE4); + } else { + PushWE (Registers.PCw + 1); + S9xPackStatus (); + PushBE (Registers.PL); + OpenBus = Registers.PL; + ClearDecimal (); + SetIRQ (); + + addr = S9xGetWord (0xFFF4); + } + S9xSetPCBase(addr); + OpenBus = addr>>8; +} + +/*****************************************************************************/ + +/* JML ********************************************************************* */ +static void OpDC (void) { + S9xSetPCBase (AbsoluteIndirectLong (JUMP)); +} + +static void OpDCSlow (void) { + S9xSetPCBase (AbsoluteIndirectLongSlow (JUMP)); +} + +static void Op5C (void) { + S9xSetPCBase(AbsoluteLong (JUMP)); +} + +static void Op5CSlow (void) { + S9xSetPCBase(AbsoluteLongSlow (JUMP)); +} + +/*****************************************************************************/ + +/* JMP ********************************************************************* */ +static void Op4C (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)Absolute(JUMP))); +#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES) + CPUShutdown (); +#endif +} + +static void Op4CSlow (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)AbsoluteSlow(JUMP))); +#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES) + CPUShutdown (); +#endif +} + +static void Op6C (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)AbsoluteIndirect(JUMP))); +} + +static void Op6CSlow (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)AbsoluteIndirectSlow(JUMP))); +} + +static void Op7C (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)AbsoluteIndexedIndirect(JUMP))); +} + +static void Op7CSlow (void) { + S9xSetPCBase (ICPU.ShiftedPB + ((uint16)AbsoluteIndexedIndirectSlow(JUMP))); +} + +/*****************************************************************************/ + +/* JSL/RTL ***************************************************************** */ +static void Op22E1 (void) { + /* Note: JSL is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + uint32 addr = AbsoluteLong (JSR); + PushB (Registers.PB); + PushW (Registers.PCw - 1); + Registers.SH = 1; + S9xSetPCBase (addr); +} + +static void Op22E0 (void) { + uint32 addr = AbsoluteLong (JSR); + PushB (Registers.PB); + PushW (Registers.PCw - 1); + S9xSetPCBase (addr); +} + +static void Op22Slow (void) { + uint32 addr = AbsoluteLongSlow (JSR); + PushB (Registers.PB); + PushW (Registers.PCw - 1); + if(CheckEmulation()) Registers.SH = 1; + S9xSetPCBase (addr); +} + +static void Op6BE1 (void) { + /* Note: RTL is a new instruction, and so doesn't respect the emu-mode + * stack bounds */ + AddCycles(TWO_CYCLES); + PullW (Registers.PCw); + PullB (Registers.PB); + Registers.SH = 1; + Registers.PCw++; + S9xSetPCBase(Registers.PBPC); +} + +static void Op6BE0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.PCw); + PullB (Registers.PB); + Registers.PCw++; + S9xSetPCBase(Registers.PBPC); +} + +static void Op6BSlow (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.PCw); + PullB (Registers.PB); + if(CheckEmulation()) Registers.SH = 1; + Registers.PCw++; + S9xSetPCBase(Registers.PBPC); +} + +/*****************************************************************************/ + +/* JSR/RTS ***************************************************************** */ +static void Op20E1 (void) { + uint16 addr = Absolute (JSR); + AddCycles(ONE_CYCLE); + PushWE (Registers.PCw - 1); + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void Op20E0 (void) { + uint16 addr = Absolute (JSR); + AddCycles(ONE_CYCLE); + PushW (Registers.PCw - 1); + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void Op20Slow (void) { + uint16 addr = AbsoluteSlow (JSR); + AddCycles(ONE_CYCLE); + if(CheckEmulation()){ + PushWE (Registers.PCw - 1); + } else { + PushW (Registers.PCw - 1); + } + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void OpFCE1 (void) { + /* Note: JSR (a,X) is a new instruction, and so doesn't respect the + * emu-mode stack bounds */ + uint16 addr = AbsoluteIndexedIndirect (JSR); + PushW (Registers.PCw - 1); + Registers.SH = 1; + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void OpFCE0 (void) { + uint16 addr = AbsoluteIndexedIndirect (JSR); + PushW (Registers.PCw - 1); + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void OpFCSlow (void) { + uint16 addr = AbsoluteIndexedIndirectSlow (JSR); + PushW (Registers.PCw - 1); + if(CheckEmulation()) Registers.SH = 1; + S9xSetPCBase (ICPU.ShiftedPB + addr); +} + +static void Op60E1 (void) { + AddCycles(TWO_CYCLES); + PullWE (Registers.PCw); + AddCycles(ONE_CYCLE); + Registers.PCw++; + S9xSetPCBase (Registers.PBPC); +} + +static void Op60E0 (void) { + AddCycles(TWO_CYCLES); + PullW (Registers.PCw); + AddCycles(ONE_CYCLE); + Registers.PCw++; + S9xSetPCBase (Registers.PBPC); +} + +static void Op60Slow (void) { + AddCycles(TWO_CYCLES); + if(CheckEmulation()){ + PullWE (Registers.PCw); + } else { + PullW (Registers.PCw); + } + AddCycles(ONE_CYCLE); + Registers.PCw++; + S9xSetPCBase (Registers.PBPC); +} + +/*****************************************************************************/ + +/* MVN/MVP ***************************************************************** */ +static void Op54X1 (void) { + uint32 SrcBank; + + Registers.DB = Immediate8(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + Registers.XL++; + Registers.YL++; + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +static void Op54X0 (void) { + uint32 SrcBank; + + Registers.DB = Immediate8(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + Registers.X.W++; + Registers.Y.W++; + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +static void Op54Slow (void) { + uint32 SrcBank; + + OpenBus = Registers.DB = Immediate8Slow(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8Slow(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + if(CheckIndex()){ + Registers.XL++; + Registers.YL++; + } else { + Registers.X.W++; + Registers.Y.W++; + } + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +static void Op44X1 (void) { + uint32 SrcBank; + + Registers.DB = Immediate8(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + Registers.XL--; + Registers.YL--; + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +static void Op44X0 (void) { + uint32 SrcBank; + + Registers.DB = Immediate8(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + Registers.X.W--; + Registers.Y.W--; + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +static void Op44Slow (void) { + uint32 SrcBank; + + OpenBus = Registers.DB = Immediate8(NONE); + ICPU.ShiftedDB = Registers.DB << 16; + OpenBus = SrcBank = Immediate8(NONE); + + S9xSetByte(OpenBus=S9xGetByte ((SrcBank << 16) + Registers.X.W), + ICPU.ShiftedDB + Registers.Y.W); + + if(CheckIndex()){ + Registers.XL--; + Registers.YL--; + } else { + Registers.X.W--; + Registers.Y.W--; + } + Registers.A.W--; + if (Registers.A.W != 0xffff) + Registers.PCw -= 3; + + AddCycles(TWO_CYCLES); +} + +/*****************************************************************************/ + +/* REP/SEP ***************************************************************** */ +static void OpC2 (void) { + uint8 Work8 = ~Immediate8(READ); + Registers.PL &= Work8; + ICPU._Carry &= Work8; + ICPU._Overflow &= (Work8 >> 6); + ICPU._Negative &= Work8; + ICPU._Zero |= ~Work8 & Zero; + + AddCycles(ONE_CYCLE); + if (CheckEmulation()) { + SetFlags (MemoryFlag | IndexFlag); + missing.emulate6502 = 1; + } + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +/* CHECK_FOR_IRQ(); */ +} + +static void OpC2Slow (void) { + uint8 Work8 = ~Immediate8Slow(READ); + Registers.PL &= Work8; + ICPU._Carry &= Work8; + ICPU._Overflow &= (Work8 >> 6); + ICPU._Negative &= Work8; + ICPU._Zero |= ~Work8 & Zero; + + AddCycles(ONE_CYCLE); + if (CheckEmulation()) { + SetFlags (MemoryFlag | IndexFlag); + missing.emulate6502 = 1; + } + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +/* CHECK_FOR_IRQ(); */ +} + +static void OpE2 (void) { + uint8 Work8 = Immediate8(READ); + Registers.PL |= Work8; + ICPU._Carry |= Work8 & 1; + ICPU._Overflow |= (Work8 >> 6) & 1; + ICPU._Negative |= Work8; + if (Work8 & Zero) ICPU._Zero = 0; + + AddCycles(ONE_CYCLE); + if (CheckEmulation()) { + SetFlags (MemoryFlag | IndexFlag); + missing.emulate6502 = 1; + } + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +} + +static void OpE2Slow (void) { + uint8 Work8 = Immediate8Slow(READ); + Registers.PL |= Work8; + ICPU._Carry |= Work8 & 1; + ICPU._Overflow |= (Work8 >> 6) & 1; + ICPU._Negative |= Work8; + if (Work8 & Zero) ICPU._Zero = 0; + + AddCycles(ONE_CYCLE); + if (CheckEmulation()) { + SetFlags (MemoryFlag | IndexFlag); + missing.emulate6502 = 1; + } + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +} + +/*****************************************************************************/ + +/* XBA ********************************************************************* */ +static void OpEB (void) { + uint8 Work8 = Registers.AL; + Registers.AL = Registers.AH; + Registers.AH = Work8; + SetZN (Registers.AL); + AddCycles(TWO_CYCLES); +} + +/*****************************************************************************/ + +/* RTI ********************************************************************* */ +static void Op40Slow (void) { + AddCycles(TWO_CYCLES); + if (!CheckEmulation()) { + PullB (Registers.PL); + S9xUnpackStatus (); + PullW (Registers.PCw); + PullB (Registers.PB); + OpenBus = Registers.PB; + ICPU.ShiftedPB = Registers.PB << 16; + } else { + PullBE (Registers.PL); + S9xUnpackStatus (); + PullWE (Registers.PCw); + OpenBus = Registers.PCh; + SetFlags (MemoryFlag | IndexFlag); + missing.emulate6502 = 1; + } + S9xSetPCBase (Registers.PBPC); + + if (CheckIndex ()) { + Registers.XH = 0; + Registers.YH = 0; + } + S9xFixCycles(); +/* CHECK_FOR_IRQ(); */ +} + +/*****************************************************************************/ + +/* STP/WAI/WDM ************************************************************* */ +// WAI +static void OpCB (void) { + // Ok, let's just C-ify the ASM versions separately. +#ifdef SA1_OPCODES + SA1.WaitingForInterrupt = TRUE; + Registers.PCw--; +#if 0 + // XXX: FIXME + if(Settings.Shutdown){ + SA1.Cycles = SA1.NextEvent; + if (IAPU.APUExecuting) + { + SA1.Executing = FALSE; + do + { + APU_EXECUTE1 (); + } while (APU.Cycles < SA1.NextEvent); + SA1.Executing = TRUE; + } + } +#endif +#else // SA1_OPCODES +#if 0 + if (CPU.IRQActive) { + AddCycles(TWO_CYCLES); + } else +#endif + { + CPU.WaitingForInterrupt = TRUE; + Registers.PCw--; +#ifdef CPU_SHUTDOWN + if (Settings.Shutdown) + { + CPU.Cycles = CPU.NextEvent; + S9xUpdateAPUTimer(); + if (IAPU.APUExecuting) + { + ICPU.CPUExecuting = FALSE; + do + { + APU_EXECUTE1 (); + } while (APU.Cycles < CPU.NextEvent); + ICPU.CPUExecuting = TRUE; + } + } else { + AddCycles(TWO_CYCLES); +#endif + } + } +#endif // SA1_OPCODES +} + +// STP +static void OpDB (void) { + Registers.PCw--; + CPU.Flags |= DEBUG_MODE_FLAG | HALTED_FLAG; +} + +// WDM (Reserved S9xOpcode) +#ifdef DEBUGGER +extern FILE *trace; +extern FILE *trace2; +#endif +static void Op42 (void) { +#ifndef NGC + uint8 byte = S9xGetWord(Registers.PBPC); +#endif + Registers.PCw++; +#ifdef DEBUGGER + // Hey, let's use this to trigger debug modes + switch(byte){ + case 0xdb: // "STP" = Enter debug mode + CPU.Flags |= DEBUG_MODE_FLAG; + break; +#ifndef SA1_OPCODES + case 0xe2: // "SEP" = Trace on + if(!(CPU.Flags & TRACE_FLAG)) {{ + char buf[25]; + CPU.Flags |= TRACE_FLAG; + snprintf(buf, 25, "WDM trace on at $%02X:%04X", Registers.PB, Registers.PCw); + S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf); + if(trace != NULL) fclose(trace); + trace = fopen ("WDMtrace.log", "ab"); + }} + break; + case 0xc2: // "REP" = Trace off + if(CPU.Flags & TRACE_FLAG) {{ + char buf[26]; + CPU.Flags &= ~TRACE_FLAG; + snprintf(buf, 26, "WDM trace off at $%02X:%04X", Registers.PB, Registers.PCw); + S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf); + if(trace != NULL) fclose(trace); + trace = NULL; + }} + break; +#endif + case 0x42: // "WDM" = Snapshot + { + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + + _splitpath (Memory.ROMFilename, drive, dir, def, ext); + snprintf (filename, PATH_MAX, "%s%s%s-%06X.wdm", + S9xGetDirectory (SNAPSHOT_DIR), SLASH_STR, def, Registers.PBPC&0xffffff); + sprintf (def, "WDM Snapshot at $%02X:%04X: %s", Registers.PB, Registers.PCw, filename); + S9xMessage (S9X_DEBUG, S9X_DEBUG_OUTPUT, def); + Snapshot(filename); + } + break; + + default: + break; + } +#endif +} + +/*****************************************************************************/ + +/*****************************************************************************/ +/* CPU-S9xOpcodes Definitions */ +/*****************************************************************************/ +struct SOpcodes S9xOpcodesM1X1[256] = { + {Op00}, {Op01E0M1}, {Op02}, {Op03M1}, {Op04M1}, + {Op05M1}, {Op06M1}, {Op07M1}, {Op08E0}, {Op09M1}, + {Op0AM1}, {Op0BE0}, {Op0CM1}, {Op0DM1}, {Op0EM1}, + {Op0FM1}, {Op10E0}, {Op11E0M1X1}, {Op12E0M1}, {Op13M1}, + {Op14M1}, {Op15E0M1}, {Op16E0M1}, {Op17M1}, {Op18}, + {Op19M1X1}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1X1}, + {Op1EM1X1}, {Op1FM1}, {Op20E0}, {Op21E0M1}, {Op22E0}, + {Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1}, + {Op28E0}, {Op29M1}, {Op2AM1}, {Op2BE0}, {Op2CM1}, + {Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30E0}, {Op31E0M1X1}, + {Op32E0M1}, {Op33M1}, {Op34E0M1}, {Op35E0M1}, {Op36E0M1}, + {Op37M1}, {Op38}, {Op39M1X1}, {Op3AM1}, {Op3B}, + {Op3CM1X1}, {Op3DM1X1}, {Op3EM1X1}, {Op3FM1}, {Op40Slow}, + {Op41E0M1}, {Op42}, {Op43M1}, {Op44X1}, {Op45M1}, + {Op46M1}, {Op47M1}, {Op48E0M1}, {Op49M1}, {Op4AM1}, + {Op4BE0}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1}, + {Op50E0}, {Op51E0M1X1}, {Op52E0M1}, {Op53M1}, {Op54X1}, + {Op55E0M1}, {Op56E0M1}, {Op57M1}, {Op58}, {Op59M1X1}, + {Op5AE0X1}, {Op5B}, {Op5C}, {Op5DM1X1}, {Op5EM1X1}, + {Op5FM1}, {Op60E0}, {Op61E0M1}, {Op62E0}, {Op63M1}, + {Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68E0M1}, + {Op69M1}, {Op6AM1}, {Op6BE0}, {Op6C}, {Op6DM1}, + {Op6EM1}, {Op6FM1}, {Op70E0}, {Op71E0M1X1}, {Op72E0M1}, + {Op73M1}, {Op74E0M1}, {Op75E0M1}, {Op76E0M1}, {Op77M1}, + {Op78}, {Op79M1X1}, {Op7AE0X1}, {Op7B}, {Op7C}, + {Op7DM1X1}, {Op7EM1X1}, {Op7FM1}, {Op80E0}, {Op81E0M1}, + {Op82}, {Op83M1}, {Op84X1}, {Op85M1}, {Op86X1}, + {Op87M1}, {Op88X1}, {Op89M1}, {Op8AM1}, {Op8BE0}, + {Op8CX1}, {Op8DM1}, {Op8EX1}, {Op8FM1}, {Op90E0}, + {Op91E0M1X1}, {Op92E0M1}, {Op93M1}, {Op94E0X1}, {Op95E0M1}, + {Op96E0X1}, {Op97M1}, {Op98M1}, {Op99M1X1}, {Op9A}, + {Op9BX1}, {Op9CM1}, {Op9DM1X1}, {Op9EM1X1}, {Op9FM1}, + {OpA0X1}, {OpA1E0M1}, {OpA2X1}, {OpA3M1}, {OpA4X1}, + {OpA5M1}, {OpA6X1}, {OpA7M1}, {OpA8X1}, {OpA9M1}, + {OpAAX1}, {OpABE0}, {OpACX1}, {OpADM1}, {OpAEX1}, + {OpAFM1}, {OpB0E0}, {OpB1E0M1X1}, {OpB2E0M1}, {OpB3M1}, + {OpB4E0X1}, {OpB5E0M1}, {OpB6E0X1}, {OpB7M1}, {OpB8}, + {OpB9M1X1}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM1X1}, + {OpBEX1}, {OpBFM1}, {OpC0X1}, {OpC1E0M1}, {OpC2}, + {OpC3M1}, {OpC4X1}, {OpC5M1}, {OpC6M1}, {OpC7M1}, + {OpC8X1}, {OpC9M1}, {OpCAX1}, {OpCB}, {OpCCX1}, + {OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0E0}, {OpD1E0M1X1}, + {OpD2E0M1}, {OpD3M1}, {OpD4E0}, {OpD5E0M1}, {OpD6E0M1}, + {OpD7M1}, {OpD8}, {OpD9M1X1}, {OpDAE0X1}, {OpDB}, + {OpDC}, {OpDDM1X1}, {OpDEM1X1}, {OpDFM1}, {OpE0X1}, + {OpE1E0M1}, {OpE2}, {OpE3M1}, {OpE4X1}, {OpE5M1}, + {OpE6M1}, {OpE7M1}, {OpE8X1}, {OpE9M1}, {OpEA}, + {OpEB}, {OpECX1}, {OpEDM1}, {OpEEM1}, {OpEFM1}, + {OpF0E0}, {OpF1E0M1X1}, {OpF2E0M1}, {OpF3M1}, {OpF4E0}, + {OpF5E0M1}, {OpF6E0M1}, {OpF7M1}, {OpF8}, {OpF9M1X1}, + {OpFAE0X1}, {OpFB}, {OpFCE0}, {OpFDM1X1}, {OpFEM1X1}, + {OpFFM1} +}; + +struct SOpcodes S9xOpcodesE1[256] = { + {Op00}, {Op01E1}, {Op02}, {Op03M1}, {Op04M1}, + {Op05M1}, {Op06M1}, {Op07M1}, {Op08E1}, {Op09M1}, + {Op0AM1}, {Op0BE1}, {Op0CM1}, {Op0DM1}, {Op0EM1}, + {Op0FM1}, {Op10E1}, {Op11E1}, {Op12E1}, {Op13M1}, + {Op14M1}, {Op15E1}, {Op16E1}, {Op17M1}, {Op18}, + {Op19M1X1}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1X1}, + {Op1EM1X1}, {Op1FM1}, {Op20E1}, {Op21E1}, {Op22E1}, + {Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1}, + {Op28E1}, {Op29M1}, {Op2AM1}, {Op2BE1}, {Op2CM1}, + {Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30E1}, {Op31E1}, + {Op32E1}, {Op33M1}, {Op34E1}, {Op35E1}, {Op36E1}, + {Op37M1}, {Op38}, {Op39M1X1}, {Op3AM1}, {Op3B}, + {Op3CM1X1}, {Op3DM1X1}, {Op3EM1X1}, {Op3FM1}, {Op40Slow}, + {Op41E1}, {Op42}, {Op43M1}, {Op44X1}, {Op45M1}, + {Op46M1}, {Op47M1}, {Op48E1}, {Op49M1}, {Op4AM1}, + {Op4BE1}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1}, + {Op50E1}, {Op51E1}, {Op52E1}, {Op53M1}, {Op54X1}, + {Op55E1}, {Op56E1}, {Op57M1}, {Op58}, {Op59M1X1}, + {Op5AE1}, {Op5B}, {Op5C}, {Op5DM1X1}, {Op5EM1X1}, + {Op5FM1}, {Op60E1}, {Op61E1}, {Op62E1}, {Op63M1}, + {Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68E1}, + {Op69M1}, {Op6AM1}, {Op6BE1}, {Op6C}, {Op6DM1}, + {Op6EM1}, {Op6FM1}, {Op70E1}, {Op71E1}, {Op72E1}, + {Op73M1}, {Op74E1}, {Op75E1}, {Op76E1}, {Op77M1}, + {Op78}, {Op79M1X1}, {Op7AE1}, {Op7B}, {Op7C}, + {Op7DM1X1}, {Op7EM1X1}, {Op7FM1}, {Op80E1}, {Op81E1}, + {Op82}, {Op83M1}, {Op84X1}, {Op85M1}, {Op86X1}, + {Op87M1}, {Op88X1}, {Op89M1}, {Op8AM1}, {Op8BE1}, + {Op8CX1}, {Op8DM1}, {Op8EX1}, {Op8FM1}, {Op90E1}, + {Op91E1}, {Op92E1}, {Op93M1}, {Op94E1}, {Op95E1}, + {Op96E1}, {Op97M1}, {Op98M1}, {Op99M1X1}, {Op9A}, + {Op9BX1}, {Op9CM1}, {Op9DM1X1}, {Op9EM1X1}, {Op9FM1}, + {OpA0X1}, {OpA1E1}, {OpA2X1}, {OpA3M1}, {OpA4X1}, + {OpA5M1}, {OpA6X1}, {OpA7M1}, {OpA8X1}, {OpA9M1}, + {OpAAX1}, {OpABE1}, {OpACX1}, {OpADM1}, {OpAEX1}, + {OpAFM1}, {OpB0E1}, {OpB1E1}, {OpB2E1}, {OpB3M1}, + {OpB4E1}, {OpB5E1}, {OpB6E1}, {OpB7M1}, {OpB8}, + {OpB9M1X1}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM1X1}, + {OpBEX1}, {OpBFM1}, {OpC0X1}, {OpC1E1}, {OpC2}, + {OpC3M1}, {OpC4X1}, {OpC5M1}, {OpC6M1}, {OpC7M1}, + {OpC8X1}, {OpC9M1}, {OpCAX1}, {OpCB}, {OpCCX1}, + {OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0E1}, {OpD1E1}, + {OpD2E1}, {OpD3M1}, {OpD4E1}, {OpD5E1}, {OpD6E1}, + {OpD7M1}, {OpD8}, {OpD9M1X1}, {OpDAE1}, {OpDB}, + {OpDC}, {OpDDM1X1}, {OpDEM1X1}, {OpDFM1}, {OpE0X1}, + {OpE1E1}, {OpE2}, {OpE3M1}, {OpE4X1}, {OpE5M1}, + {OpE6M1}, {OpE7M1}, {OpE8X1}, {OpE9M1}, {OpEA}, + {OpEB}, {OpECX1}, {OpEDM1}, {OpEEM1}, {OpEFM1}, + {OpF0E1}, {OpF1E1}, {OpF2E1}, {OpF3M1}, {OpF4E1}, + {OpF5E1}, {OpF6E1}, {OpF7M1}, {OpF8}, {OpF9M1X1}, + {OpFAE1}, {OpFB}, {OpFCE1}, {OpFDM1X1}, {OpFEM1X1}, + {OpFFM1} +}; + +struct SOpcodes S9xOpcodesM1X0[256] = { + {Op00}, {Op01E0M1}, {Op02}, {Op03M1}, {Op04M1}, + {Op05M1}, {Op06M1}, {Op07M1}, {Op08E0}, {Op09M1}, + {Op0AM1}, {Op0BE0}, {Op0CM1}, {Op0DM1}, {Op0EM1}, + {Op0FM1}, {Op10E0}, {Op11E0M1X0}, {Op12E0M1}, {Op13M1}, + {Op14M1}, {Op15E0M1}, {Op16E0M1}, {Op17M1}, {Op18}, + {Op19M1X0}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1X0}, + {Op1EM1X0}, {Op1FM1}, {Op20E0}, {Op21E0M1}, {Op22E0}, + {Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1}, + {Op28E0}, {Op29M1}, {Op2AM1}, {Op2BE0}, {Op2CM1}, + {Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30E0}, {Op31E0M1X0}, + {Op32E0M1}, {Op33M1}, {Op34E0M1}, {Op35E0M1}, {Op36E0M1}, + {Op37M1}, {Op38}, {Op39M1X0}, {Op3AM1}, {Op3B}, + {Op3CM1X0}, {Op3DM1X0}, {Op3EM1X0}, {Op3FM1}, {Op40Slow}, + {Op41E0M1}, {Op42}, {Op43M1}, {Op44X0}, {Op45M1}, + {Op46M1}, {Op47M1}, {Op48E0M1}, {Op49M1}, {Op4AM1}, + {Op4BE0}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1}, + {Op50E0}, {Op51E0M1X0}, {Op52E0M1}, {Op53M1}, {Op54X0}, + {Op55E0M1}, {Op56E0M1}, {Op57M1}, {Op58}, {Op59M1X0}, + {Op5AE0X0}, {Op5B}, {Op5C}, {Op5DM1X0}, {Op5EM1X0}, + {Op5FM1}, {Op60E0}, {Op61E0M1}, {Op62E0}, {Op63M1}, + {Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68E0M1}, + {Op69M1}, {Op6AM1}, {Op6BE0}, {Op6C}, {Op6DM1}, + {Op6EM1}, {Op6FM1}, {Op70E0}, {Op71E0M1X0}, {Op72E0M1}, + {Op73M1}, {Op74E0M1}, {Op75E0M1}, {Op76E0M1}, {Op77M1}, + {Op78}, {Op79M1X0}, {Op7AE0X0}, {Op7B}, {Op7C}, + {Op7DM1X0}, {Op7EM1X0}, {Op7FM1}, {Op80E0}, {Op81E0M1}, + {Op82}, {Op83M1}, {Op84X0}, {Op85M1}, {Op86X0}, + {Op87M1}, {Op88X0}, {Op89M1}, {Op8AM1}, {Op8BE0}, + {Op8CX0}, {Op8DM1}, {Op8EX0}, {Op8FM1}, {Op90E0}, + {Op91E0M1X0}, {Op92E0M1}, {Op93M1}, {Op94E0X0}, {Op95E0M1}, + {Op96E0X0}, {Op97M1}, {Op98M1}, {Op99M1X0}, {Op9A}, + {Op9BX0}, {Op9CM1}, {Op9DM1X0}, {Op9EM1X0}, {Op9FM1}, + {OpA0X0}, {OpA1E0M1}, {OpA2X0}, {OpA3M1}, {OpA4X0}, + {OpA5M1}, {OpA6X0}, {OpA7M1}, {OpA8X0}, {OpA9M1}, + {OpAAX0}, {OpABE0}, {OpACX0}, {OpADM1}, {OpAEX0}, + {OpAFM1}, {OpB0E0}, {OpB1E0M1X0}, {OpB2E0M1}, {OpB3M1}, + {OpB4E0X0}, {OpB5E0M1}, {OpB6E0X0}, {OpB7M1}, {OpB8}, + {OpB9M1X0}, {OpBAX0}, {OpBBX0}, {OpBCX0}, {OpBDM1X0}, + {OpBEX0}, {OpBFM1}, {OpC0X0}, {OpC1E0M1}, {OpC2}, + {OpC3M1}, {OpC4X0}, {OpC5M1}, {OpC6M1}, {OpC7M1}, + {OpC8X0}, {OpC9M1}, {OpCAX0}, {OpCB}, {OpCCX0}, + {OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0E0}, {OpD1E0M1X0}, + {OpD2E0M1}, {OpD3M1}, {OpD4E0}, {OpD5E0M1}, {OpD6E0M1}, + {OpD7M1}, {OpD8}, {OpD9M1X0}, {OpDAE0X0}, {OpDB}, + {OpDC}, {OpDDM1X0}, {OpDEM1X0}, {OpDFM1}, {OpE0X0}, + {OpE1E0M1}, {OpE2}, {OpE3M1}, {OpE4X0}, {OpE5M1}, + {OpE6M1}, {OpE7M1}, {OpE8X0}, {OpE9M1}, {OpEA}, + {OpEB}, {OpECX0}, {OpEDM1}, {OpEEM1}, {OpEFM1}, + {OpF0E0}, {OpF1E0M1X0}, {OpF2E0M1}, {OpF3M1}, {OpF4E0}, + {OpF5E0M1}, {OpF6E0M1}, {OpF7M1}, {OpF8}, {OpF9M1X0}, + {OpFAE0X0}, {OpFB}, {OpFCE0}, {OpFDM1X0}, {OpFEM1X0}, + {OpFFM1} +}; + +struct SOpcodes S9xOpcodesM0X0[256] = { + {Op00}, {Op01E0M0}, {Op02}, {Op03M0}, {Op04M0}, + {Op05M0}, {Op06M0}, {Op07M0}, {Op08E0}, {Op09M0}, + {Op0AM0}, {Op0BE0}, {Op0CM0}, {Op0DM0}, {Op0EM0}, + {Op0FM0}, {Op10E0}, {Op11E0M0X0}, {Op12E0M0}, {Op13M0}, + {Op14M0}, {Op15E0M0}, {Op16E0M0}, {Op17M0}, {Op18}, + {Op19M0X0}, {Op1AM0}, {Op1B}, {Op1CM0}, {Op1DM0X0}, + {Op1EM0X0}, {Op1FM0}, {Op20E0}, {Op21E0M0}, {Op22E0}, + {Op23M0}, {Op24M0}, {Op25M0}, {Op26M0}, {Op27M0}, + {Op28E0}, {Op29M0}, {Op2AM0}, {Op2BE0}, {Op2CM0}, + {Op2DM0}, {Op2EM0}, {Op2FM0}, {Op30E0}, {Op31E0M0X0}, + {Op32E0M0}, {Op33M0}, {Op34E0M0}, {Op35E0M0}, {Op36E0M0}, + {Op37M0}, {Op38}, {Op39M0X0}, {Op3AM0}, {Op3B}, + {Op3CM0X0}, {Op3DM0X0}, {Op3EM0X0}, {Op3FM0}, {Op40Slow}, + {Op41E0M0}, {Op42}, {Op43M0}, {Op44X0}, {Op45M0}, + {Op46M0}, {Op47M0}, {Op48E0M0}, {Op49M0}, {Op4AM0}, + {Op4BE0}, {Op4C}, {Op4DM0}, {Op4EM0}, {Op4FM0}, + {Op50E0}, {Op51E0M0X0}, {Op52E0M0}, {Op53M0}, {Op54X0}, + {Op55E0M0}, {Op56E0M0}, {Op57M0}, {Op58}, {Op59M0X0}, + {Op5AE0X0}, {Op5B}, {Op5C}, {Op5DM0X0}, {Op5EM0X0}, + {Op5FM0}, {Op60E0}, {Op61E0M0}, {Op62E0}, {Op63M0}, + {Op64M0}, {Op65M0}, {Op66M0}, {Op67M0}, {Op68E0M0}, + {Op69M0}, {Op6AM0}, {Op6BE0}, {Op6C}, {Op6DM0}, + {Op6EM0}, {Op6FM0}, {Op70E0}, {Op71E0M0X0}, {Op72E0M0}, + {Op73M0}, {Op74E0M0}, {Op75E0M0}, {Op76E0M0}, {Op77M0}, + {Op78}, {Op79M0X0}, {Op7AE0X0}, {Op7B}, {Op7C}, + {Op7DM0X0}, {Op7EM0X0}, {Op7FM0}, {Op80E0}, {Op81E0M0}, + {Op82}, {Op83M0}, {Op84X0}, {Op85M0}, {Op86X0}, + {Op87M0}, {Op88X0}, {Op89M0}, {Op8AM0}, {Op8BE0}, + {Op8CX0}, {Op8DM0}, {Op8EX0}, {Op8FM0}, {Op90E0}, + {Op91E0M0X0}, {Op92E0M0}, {Op93M0}, {Op94E0X0}, {Op95E0M0}, + {Op96E0X0}, {Op97M0}, {Op98M0}, {Op99M0X0}, {Op9A}, + {Op9BX0}, {Op9CM0}, {Op9DM0X0}, {Op9EM0X0}, {Op9FM0}, + {OpA0X0}, {OpA1E0M0}, {OpA2X0}, {OpA3M0}, {OpA4X0}, + {OpA5M0}, {OpA6X0}, {OpA7M0}, {OpA8X0}, {OpA9M0}, + {OpAAX0}, {OpABE0}, {OpACX0}, {OpADM0}, {OpAEX0}, + {OpAFM0}, {OpB0E0}, {OpB1E0M0X0}, {OpB2E0M0}, {OpB3M0}, + {OpB4E0X0}, {OpB5E0M0}, {OpB6E0X0}, {OpB7M0}, {OpB8}, + {OpB9M0X0}, {OpBAX0}, {OpBBX0}, {OpBCX0}, {OpBDM0X0}, + {OpBEX0}, {OpBFM0}, {OpC0X0}, {OpC1E0M0}, {OpC2}, + {OpC3M0}, {OpC4X0}, {OpC5M0}, {OpC6M0}, {OpC7M0}, + {OpC8X0}, {OpC9M0}, {OpCAX0}, {OpCB}, {OpCCX0}, + {OpCDM0}, {OpCEM0}, {OpCFM0}, {OpD0E0}, {OpD1E0M0X0}, + {OpD2E0M0}, {OpD3M0}, {OpD4E0}, {OpD5E0M0}, {OpD6E0M0}, + {OpD7M0}, {OpD8}, {OpD9M0X0}, {OpDAE0X0}, {OpDB}, + {OpDC}, {OpDDM0X0}, {OpDEM0X0}, {OpDFM0}, {OpE0X0}, + {OpE1E0M0}, {OpE2}, {OpE3M0}, {OpE4X0}, {OpE5M0}, + {OpE6M0}, {OpE7M0}, {OpE8X0}, {OpE9M0}, {OpEA}, + {OpEB}, {OpECX0}, {OpEDM0}, {OpEEM0}, {OpEFM0}, + {OpF0E0}, {OpF1E0M0X0}, {OpF2E0M0}, {OpF3M0}, {OpF4E0}, + {OpF5E0M0}, {OpF6E0M0}, {OpF7M0}, {OpF8}, {OpF9M0X0}, + {OpFAE0X0}, {OpFB}, {OpFCE0}, {OpFDM0X0}, {OpFEM0X0}, + {OpFFM0} +}; + +struct SOpcodes S9xOpcodesM0X1[256] = { + {Op00}, {Op01E0M0}, {Op02}, {Op03M0}, {Op04M0}, + {Op05M0}, {Op06M0}, {Op07M0}, {Op08E0}, {Op09M0}, + {Op0AM0}, {Op0BE0}, {Op0CM0}, {Op0DM0}, {Op0EM0}, + {Op0FM0}, {Op10E0}, {Op11E0M0X1}, {Op12E0M0}, {Op13M0}, + {Op14M0}, {Op15E0M0}, {Op16E0M0}, {Op17M0}, {Op18}, + {Op19M0X1}, {Op1AM0}, {Op1B}, {Op1CM0}, {Op1DM0X1}, + {Op1EM0X1}, {Op1FM0}, {Op20E0}, {Op21E0M0}, {Op22E0}, + {Op23M0}, {Op24M0}, {Op25M0}, {Op26M0}, {Op27M0}, + {Op28E0}, {Op29M0}, {Op2AM0}, {Op2BE0}, {Op2CM0}, + {Op2DM0}, {Op2EM0}, {Op2FM0}, {Op30E0}, {Op31E0M0X1}, + {Op32E0M0}, {Op33M0}, {Op34E0M0}, {Op35E0M0}, {Op36E0M0}, + {Op37M0}, {Op38}, {Op39M0X1}, {Op3AM0}, {Op3B}, + {Op3CM0X1}, {Op3DM0X1}, {Op3EM0X1}, {Op3FM0}, {Op40Slow}, + {Op41E0M0}, {Op42}, {Op43M0}, {Op44X1}, {Op45M0}, + {Op46M0}, {Op47M0}, {Op48E0M0}, {Op49M0}, {Op4AM0}, + {Op4BE0}, {Op4C}, {Op4DM0}, {Op4EM0}, {Op4FM0}, + {Op50E0}, {Op51E0M0X1}, {Op52E0M0}, {Op53M0}, {Op54X1}, + {Op55E0M0}, {Op56E0M0}, {Op57M0}, {Op58}, {Op59M0X1}, + {Op5AE0X1}, {Op5B}, {Op5C}, {Op5DM0X1}, {Op5EM0X1}, + {Op5FM0}, {Op60E0}, {Op61E0M0}, {Op62E0}, {Op63M0}, + {Op64M0}, {Op65M0}, {Op66M0}, {Op67M0}, {Op68E0M0}, + {Op69M0}, {Op6AM0}, {Op6BE0}, {Op6C}, {Op6DM0}, + {Op6EM0}, {Op6FM0}, {Op70E0}, {Op71E0M0X1}, {Op72E0M0}, + {Op73M0}, {Op74E0M0}, {Op75E0M0}, {Op76E0M0}, {Op77M0}, + {Op78}, {Op79M0X1}, {Op7AE0X1}, {Op7B}, {Op7C}, + {Op7DM0X1}, {Op7EM0X1}, {Op7FM0}, {Op80E0}, {Op81E0M0}, + {Op82}, {Op83M0}, {Op84X1}, {Op85M0}, {Op86X1}, + {Op87M0}, {Op88X1}, {Op89M0}, {Op8AM0}, {Op8BE0}, + {Op8CX1}, {Op8DM0}, {Op8EX1}, {Op8FM0}, {Op90E0}, + {Op91E0M0X1}, {Op92E0M0}, {Op93M0}, {Op94E0X1}, {Op95E0M0}, + {Op96E0X1}, {Op97M0}, {Op98M0}, {Op99M0X1}, {Op9A}, + {Op9BX1}, {Op9CM0}, {Op9DM0X1}, {Op9EM0X1}, {Op9FM0}, + {OpA0X1}, {OpA1E0M0}, {OpA2X1}, {OpA3M0}, {OpA4X1}, + {OpA5M0}, {OpA6X1}, {OpA7M0}, {OpA8X1}, {OpA9M0}, + {OpAAX1}, {OpABE0}, {OpACX1}, {OpADM0}, {OpAEX1}, + {OpAFM0}, {OpB0E0}, {OpB1E0M0X1}, {OpB2E0M0}, {OpB3M0}, + {OpB4E0X1}, {OpB5E0M0}, {OpB6E0X1}, {OpB7M0}, {OpB8}, + {OpB9M0X1}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM0X1}, + {OpBEX1}, {OpBFM0}, {OpC0X1}, {OpC1E0M0}, {OpC2}, + {OpC3M0}, {OpC4X1}, {OpC5M0}, {OpC6M0}, {OpC7M0}, + {OpC8X1}, {OpC9M0}, {OpCAX1}, {OpCB}, {OpCCX1}, + {OpCDM0}, {OpCEM0}, {OpCFM0}, {OpD0E0}, {OpD1E0M0X1}, + {OpD2E0M0}, {OpD3M0}, {OpD4E0}, {OpD5E0M0}, {OpD6E0M0}, + {OpD7M0}, {OpD8}, {OpD9M0X1}, {OpDAE0X1}, {OpDB}, + {OpDC}, {OpDDM0X1}, {OpDEM0X1}, {OpDFM0}, {OpE0X1}, + {OpE1E0M0}, {OpE2}, {OpE3M0}, {OpE4X1}, {OpE5M0}, + {OpE6M0}, {OpE7M0}, {OpE8X1}, {OpE9M0}, {OpEA}, + {OpEB}, {OpECX1}, {OpEDM0}, {OpEEM0}, {OpEFM0}, + {OpF0E0}, {OpF1E0M0X1}, {OpF2E0M0}, {OpF3M0}, {OpF4E0}, + {OpF5E0M0}, {OpF6E0M0}, {OpF7M0}, {OpF8}, {OpF9M0X1}, + {OpFAE0X1}, {OpFB}, {OpFCE0}, {OpFDM0X1}, {OpFEM0X1}, + {OpFFM0} +}; + +struct SOpcodes S9xOpcodesSlow[256] = { + {Op00}, {Op01Slow}, {Op02}, {Op03Slow}, {Op04Slow}, + {Op05Slow}, {Op06Slow}, {Op07Slow}, {Op08Slow}, {Op09Slow}, + {Op0ASlow}, {Op0BSlow}, {Op0CSlow}, {Op0DSlow}, {Op0ESlow}, + {Op0FSlow}, {Op10Slow}, {Op11Slow}, {Op12Slow}, {Op13Slow}, + {Op14Slow}, {Op15Slow}, {Op16Slow}, {Op17Slow}, {Op18}, + {Op19Slow}, {Op1ASlow}, {Op1B}, {Op1CSlow}, {Op1DSlow}, + {Op1ESlow}, {Op1FSlow}, {Op20Slow}, {Op21Slow}, {Op22Slow}, + {Op23Slow}, {Op24Slow}, {Op25Slow}, {Op26Slow}, {Op27Slow}, + {Op28Slow}, {Op29Slow}, {Op2ASlow}, {Op2BSlow}, {Op2CSlow}, + {Op2DSlow}, {Op2ESlow}, {Op2FSlow}, {Op30Slow}, {Op31Slow}, + {Op32Slow}, {Op33Slow}, {Op34Slow}, {Op35Slow}, {Op36Slow}, + {Op37Slow}, {Op38}, {Op39Slow}, {Op3ASlow}, {Op3B}, + {Op3CSlow}, {Op3DSlow}, {Op3ESlow}, {Op3FSlow}, {Op40Slow}, + {Op41Slow}, {Op42}, {Op43Slow}, {Op44Slow}, {Op45Slow}, + {Op46Slow}, {Op47Slow}, {Op48Slow}, {Op49Slow}, {Op4ASlow}, + {Op4BSlow}, {Op4CSlow}, {Op4DSlow}, {Op4ESlow}, {Op4FSlow}, + {Op50Slow}, {Op51Slow}, {Op52Slow}, {Op53Slow}, {Op54Slow}, + {Op55Slow}, {Op56Slow}, {Op57Slow}, {Op58}, {Op59Slow}, + {Op5ASlow}, {Op5B}, {Op5CSlow}, {Op5DSlow}, {Op5ESlow}, + {Op5FSlow}, {Op60Slow}, {Op61Slow}, {Op62Slow}, {Op63Slow}, + {Op64Slow}, {Op65Slow}, {Op66Slow}, {Op67Slow}, {Op68Slow}, + {Op69Slow}, {Op6ASlow}, {Op6BSlow}, {Op6CSlow}, {Op6DSlow}, + {Op6ESlow}, {Op6FSlow}, {Op70Slow}, {Op71Slow}, {Op72Slow}, + {Op73Slow}, {Op74Slow}, {Op75Slow}, {Op76Slow}, {Op77Slow}, + {Op78}, {Op79Slow}, {Op7ASlow}, {Op7B}, {Op7CSlow}, + {Op7DSlow}, {Op7ESlow}, {Op7FSlow}, {Op80Slow}, {Op81Slow}, + {Op82}, {Op83Slow}, {Op84Slow}, {Op85Slow}, {Op86Slow}, + {Op87Slow}, {Op88Slow}, {Op89Slow}, {Op8ASlow}, {Op8BSlow}, + {Op8CSlow}, {Op8DSlow}, {Op8ESlow}, {Op8FSlow}, {Op90Slow}, + {Op91Slow}, {Op92Slow}, {Op93Slow}, {Op94Slow}, {Op95Slow}, + {Op96Slow}, {Op97Slow}, {Op98Slow}, {Op99Slow}, {Op9A}, + {Op9BSlow}, {Op9CSlow}, {Op9DSlow}, {Op9ESlow}, {Op9FSlow}, + {OpA0Slow}, {OpA1Slow}, {OpA2Slow}, {OpA3Slow}, {OpA4Slow}, + {OpA5Slow}, {OpA6Slow}, {OpA7Slow}, {OpA8Slow}, {OpA9Slow}, + {OpAASlow}, {OpABSlow}, {OpACSlow}, {OpADSlow}, {OpAESlow}, + {OpAFSlow}, {OpB0Slow}, {OpB1Slow}, {OpB2Slow}, {OpB3Slow}, + {OpB4Slow}, {OpB5Slow}, {OpB6Slow}, {OpB7Slow}, {OpB8}, + {OpB9Slow}, {OpBASlow}, {OpBBSlow}, {OpBCSlow}, {OpBDSlow}, + {OpBESlow}, {OpBFSlow}, {OpC0Slow}, {OpC1Slow}, {OpC2Slow}, + {OpC3Slow}, {OpC4Slow}, {OpC5Slow}, {OpC6Slow}, {OpC7Slow}, + {OpC8Slow}, {OpC9Slow}, {OpCASlow}, {OpCB}, {OpCCSlow}, + {OpCDSlow}, {OpCESlow}, {OpCFSlow}, {OpD0Slow}, {OpD1Slow}, + {OpD2Slow}, {OpD3Slow}, {OpD4Slow}, {OpD5Slow}, {OpD6Slow}, + {OpD7Slow}, {OpD8}, {OpD9Slow}, {OpDASlow}, {OpDB}, + {OpDCSlow}, {OpDDSlow}, {OpDESlow}, {OpDFSlow}, {OpE0Slow}, + {OpE1Slow}, {OpE2Slow}, {OpE3Slow}, {OpE4Slow}, {OpE5Slow}, + {OpE6Slow}, {OpE7Slow}, {OpE8Slow}, {OpE9Slow}, {OpEA}, + {OpEB}, {OpECSlow}, {OpEDSlow}, {OpEESlow}, {OpEFSlow}, + {OpF0Slow}, {OpF1Slow}, {OpF2Slow}, {OpF3Slow}, {OpF4Slow}, + {OpF5Slow}, {OpF6Slow}, {OpF7Slow}, {OpF8}, {OpF9Slow}, + {OpFASlow}, {OpFB}, {OpFCSlow}, {OpFDSlow}, {OpFESlow}, + {OpFFSlow} +}; diff --git a/source/snes9x/cpuops.h b/source/snes9x/cpuops.h new file mode 100644 index 0000000..c6abd0b --- /dev/null +++ b/source/snes9x/cpuops.h @@ -0,0 +1,155 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _CPUOPS_H_ +#define _CPUOPS_H_ +void S9xOpcode_NMI (); +void S9xOpcode_IRQ (); + +#define CHECK_FOR_IRQ() \ +if (CPU.IRQActive && !CheckFlag (IRQ) && !Settings.DisableIRQ) \ + S9xOpcode_IRQ() + +#endif + diff --git a/source/snes9x/crosshairs.cpp b/source/snes9x/crosshairs.cpp new file mode 100644 index 0000000..3f32d13 --- /dev/null +++ b/source/snes9x/crosshairs.cpp @@ -0,0 +1,626 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifdef HAVE_CONFIG_H + #include +#endif +#include +#include + +#ifdef HAVE_LIBPNG +#include +#endif + +#include "port.h" +#include "crosshairs.h" + +static char *crosshairs[32]={ + "` " /* Crosshair 0 (no image) */ + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " ", + + "` " /* Crosshair 1 (the classic small dot) */ + " " + " " + " " + " " + " " + " " + " #. " + " " + " " + " " + " " + " " + " " + " ", + + "` " /* Crosshair 2 (a standard cross) */ + " " + " " + " " + " .#. " + " .#. " + " ...#... " + " ####### " + " ...#... " + " .#. " + " .#. " + " " + " " + " " + " ", + + "` .#. " /* Crosshair 3 (a standard cross) */ + " .#. " + " .#. " + " .#. " + " .#. " + " .#. " + ".......#......." + "###############" + ".......#......." + " .#. " + " .#. " + " .#. " + " .#. " + " .#. " + " .#. ", + + "` " /* Crosshair 4 (an X) */ + " " + " " + " . . " + " .#. .#. " + " .#. .#. " + " .#.#. " + " .#. " + " .#.#. " + " .#. .#. " + " .#. .#. " + " . . " + " " + " " + " ", + + "`. . " /* Crosshair 5 (an X) */ + ".#. .#." + " .#. .#. " + " .#. .#. " + " .#. .#. " + " .#. .#. " + " .#.#. " + " .#. " + " .#.#. " + " .#. .#. " + " .#. .#. " + " .#. .#. " + " .#. .#. " + ".#. .#." + " . . ", + + "` " /* Crosshair 6 (a combo) */ + " " + " " + " " + " # . # " + " # . # " + " #.# " + " ...#... " + " #.# " + " # . # " + " # . # " + " " + " " + " " + " ", + + "` . " /* Crosshair 7 (a combo) */ + " # . # " + " # . # " + " # . # " + " # . # " + " # . # " + " #.# " + ".......#......." + " #.# " + " # . # " + " # . # " + " # . # " + " # . # " + " # . # " + " . ", + + "` # " /* Crosshair 8 (a diamond cross) */ + " #.# " + " # . # " + " # . # " + " # . # " + " # . # " + " # . # " + "#......#......#" + " # . # " + " # . # " + " # . # " + " # . # " + " # . # " + " #.# " + " # ", + + "` ### " /* Crosshair 9 (a circle cross) */ + " ## . ## " + " # . # " + " # . # " + " # . # " + " # . # " + "# . #" + "#......#......#" + "# . #" + " # . # " + " # . # " + " # . # " + " # . # " + " ## . ## " + " ### ", + + "` .#. " /* Crosshair 10 (a square cross) */ + " .#. " + " .#. " + " ....#.... " + " .#######. " + " .# #. " + "....# #...." + "##### #####" + "....# #...." + " .# #. " + " .#######. " + " ....#.... " + " .#. " + " .#. " + " .#. ", + + "` .#. " /* Crosshair 11 (an interrupted cross) */ + " .#. " + " .#. " + " .#. " + " .#. " + " " + "..... ....." + "##### #####" + "..... ....." + " " + " .#. " + " .#. " + " .#. " + " .#. " + " .#. ", + + "`. . " /* Crosshair 12 (an interrupted X) */ + ".#. .#." + " .#. .#. " + " .#. .#. " + " .#. .#. " + " " + " " + " " + " " + " " + " .#. .#. " + " .#. .#. " + " .#. .#. " + ".#. .#." + " . . ", + + "` . " /* Crosshair 13 (an interrupted combo) */ + " # . # " + " # . # " + " # . # " + " # . # " + " " + " " + "..... ....." + " " + " " + " # . # " + " # . # " + " # . # " + " # . # " + " . ", + + "`#### #### " /* Crosshair 14 */ + "#.... ....#" + "#. .#" + "#. .#" + "#. .#" + " # " + " # " + " ##### " + " # " + " # " + "#. .#" + "#. .#" + "#. .#" + "#.... ....#" + " #### #### ", + + "` .# #. " /* Crosshair 15 */ + " .# #. " + " .# #. " + "....# #...." + "##### #####" + " " + " " + " " + " " + " " + "##### #####" + "....# #...." + " .# #. " + " .# #. " + " .# #. ", + + "` # " /* Crosshair 16 */ + " # " + " # " + " ....#.... " + " . # . " + " . # . " + " . # . " + "###############" + " . # . " + " . # . " + " . # . " + " ....#.... " + " # " + " # " + " # ", + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL +}; + +bool S9xLoadCrosshairFile(int idx, const char *filename){ + int i, r; + char *s; + FILE *fp; + + if(idx<1 || idx>31) return false; + if((s=(char *)calloc(15*15+1, sizeof(char)))==NULL){ + fprintf(stderr, "S9xLoadCrosshairFile: malloc error while reading "); + perror(filename); + return false; + } + + if((fp=fopen(filename, "rb"))==NULL){ + fprintf(stderr, "S9xLoadCrosshairFile: Couldn't open "); + perror(filename); + free(s); + return false; + } + + i=fread(s, 1, 8, fp); + if(i!=8){ + fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); + free(s); + fclose(fp); + return false; + } +#ifdef HAVE_LIBPNG + png_structp png_ptr; + png_infop info_ptr; + + if(!png_sig_cmp((png_byte *)s, 0, 8)){ + png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr){ + free(s); + fclose(fp); + return false; + } + info_ptr=png_create_info_struct(png_ptr); + if(!info_ptr){ + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + + png_uint_32 width, height; + int bit_depth, color_type; + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); + if(color_type!=PNG_COLOR_TYPE_PALETTE){ + fprintf(stderr, "S9xLoadCrosshairFile: Input PNG is not a palettized image!\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + if(bit_depth==16) + png_set_strip_16(png_ptr); + + if(width!=15 || height!=15){ + fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 15x15 PNG\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + + int num_palette=0, num_trans=0; + int fgcol=-1, bgcol=-1, transcol=-1; + png_color *pngpal; + png_byte *trans; + + png_get_PLTE(png_ptr, info_ptr, &pngpal, &num_palette); + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); + + if(num_palette!=3 || num_trans!=1){ + fprintf(stderr, "S9xLoadCrosshairFile: Expecting a 3-color PNG with 1 trasnparent color\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + + for(i=0; i<3; i++){ + if(trans[0]==i){ + transcol=i; + } else if(pngpal[i].red==0 && pngpal[i].green==0 && pngpal[i].blue==0){ + bgcol=i; + } else if(pngpal[i].red==255 && pngpal[i].green==255 && pngpal[i].blue==255){ + fgcol=i; + } + } + + if(transcol<0 || fgcol<0 || bgcol<0){ + fprintf(stderr, "S9xLoadCrosshairFile: PNG must have 3 colors: white (fg), black (bg), and transparent.\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + + png_set_packing(png_ptr); + png_read_update_info(png_ptr, info_ptr); + png_byte *row_pointer = new png_byte [png_get_rowbytes(png_ptr, info_ptr)]; + + for(r=0; r<15*15; r+=15){ + png_read_row(png_ptr, row_pointer, NULL); + for(i=0; i<15; i++){ + if(row_pointer[i]==transcol) s[r+i]=' '; + else if(row_pointer[i]==fgcol) s[r+i]='#'; + else if(row_pointer[i]==bgcol) s[r+i]='.'; + else { + fprintf(stderr, "S9xLoadCrosshairFile: WTF? This was supposed to be a 3-color PNG!\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(s); + fclose(fp); + return false; + } + } + } + s[15*15]=0; + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + } else +#endif + { + i=fread(s+8, 1, 15-8, fp); + if(i!=15-8){ + fprintf(stderr, "S9xLoadCrosshairFile: File is too short!\n"); + free(s); + fclose(fp); + return false; + } + if(getc(fp)!='\n'){ + fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format!"); +#ifndef HAVE_LIBPNG + fprintf(stderr, " (note: PNG support is not available)"); +#endif + fprintf(stderr, "\n"); + free(s); + fclose(fp); + return false; + } + for(r=1; r<15; r++){ + i=fread(s+r*15, 1, 15, fp); + if(i!=15){ + fprintf(stderr, "S9xLoadCrosshairFile: File is too short!"); +#ifndef HAVE_LIBPNG + fprintf(stderr, " (note: PNG support is not available)"); +#endif + fprintf(stderr, "\n"); + free(s); + fclose(fp); + return false; + } + if(getc(fp)!='\n'){ + fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format!"); +#ifndef HAVE_LIBPNG + fprintf(stderr, " (note: PNG support is not available)"); +#endif + fprintf(stderr, "\n"); + free(s); + fclose(fp); + return false; + } + } + for(i=0; i<15*15; i++){ + if(s[i]!=' ' && s[i]!='#' && s[i]!='.'){ + fprintf(stderr, "S9xLoadCrosshairFile: Invalid file format!"); +#ifndef HAVE_LIBPNG + fprintf(stderr, " (note: PNG support is not available)"); +#endif + fprintf(stderr, "\n"); + free(s); + fclose(fp); + return false; + } + } + } + fclose(fp); + + if(crosshairs[idx]!=NULL && crosshairs[idx][0]!='`') free(crosshairs[idx]); + crosshairs[idx]=s; + return true; +} + +const char *S9xGetCrosshair(int idx){ + if(idx<0 || idx>31) return NULL; + return crosshairs[idx]; +} diff --git a/source/snes9x/crosshairs.h b/source/snes9x/crosshairs.h new file mode 100644 index 0000000..02df50f --- /dev/null +++ b/source/snes9x/crosshairs.h @@ -0,0 +1,201 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef CROSSHAIRS_H +#define CROSSHAIRS_H + +/* + * Read in the specified crosshair file, replacing whatever data might be in + * that slot. Available slots are 1-31. The input file must be a PNG file, + * 15x15 pixels, palettized, with 3 colors: white, black, and transparent. Or a + * text file, 15 lines of 16 characters (counting the \n), consisting of ' ', + * '#', or '.'. + */ +bool S9xLoadCrosshairFile(int idx, const char *filename); + +/* + * Return the specified crosshair. Woo-hoo. char * to a 225-byte string, with + * '#' marking foreground, '.' marking background, and anything else + * transparent. + */ +const char *S9xGetCrosshair(int idx); + +/* + * In controls.cpp. Sets the crosshair for the specified device. Defaults are: + * cross fgcolor bgcolor + * Mouse 1: 1 White Black + * Mouse 2: 1 Purple White + * Superscope: 2 White Black + * Justifier 1: 4 Blue Black + * Justifier 2: 4 MagicPink Black + * + * Available colors are: Trans, Black, 25Grey, 50Grey, 75Grey, White, Red, + * Orange, Yellow, Green, Cyan, Sky, Blue, Violet, MagicPink, and Purple. You + * may also prefix a 't' (e.g. tBlue) for a 50%-transparent version. + * + * Use idx=-1 or fg/bg=NULL to keep the current setting. + */ +enum crosscontrols { + X_MOUSE1, + X_MOUSE2, + X_SUPERSCOPE, + X_JUSTIFIER1, + X_JUSTIFIER2 +}; +void S9xSetControllerCrosshair(enum crosscontrols ctl, int8 idx, const char *fg, const char *bg); +void S9xGetControllerCrosshair(enum crosscontrols ctl, int8 *idx, const char **fg, const char **bg); + +/* + * In gfx.cpp, much like DisplayChar() except it takes the parameters listed + * and looks up GFX.Screen. The 'crosshair' arg is a 15x15 image, with '#' + * meaning fgcolor, '.' meaning bgcolor, and anything else meaning transparent. + * Color values should be (RGB): + * 0 = transparent 4=23 23 23 8=31 31 0 12= 0 0 31 + * 1 = 0 0 0 5=31 31 31 9= 0 31 0 13=23 0 31 + * 2 = 8 8 8 6=31 00 00 10= 0 31 31 14=31 0 31 + * 3 = 16 16 16 7=31 16 00 11= 0 23 31 15=31 0 16 + * 16-31 are 50% transparent versions of 0-15. + */ +void S9xDrawCrosshair(const char *crosshair, uint8 fgcolor, uint8 bgcolor, int16 x, int16 y); + +#endif diff --git a/source/snes9x/data.cpp b/source/snes9x/data.cpp new file mode 100644 index 0000000..738b45a --- /dev/null +++ b/source/snes9x/data.cpp @@ -0,0 +1,594 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" + +uint8 add32_32 [32][32] = { +{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d, + 0x1e,0x1f}, +{ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e, + 0x1f,0x1f}, +{ 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10, + 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x1f,0x1f}, +{ 0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11, + 0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12, + 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13, + 0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14, + 0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15, + 0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19, + 0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a, + 0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, + 0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c, + 0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d, + 0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1b,0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1c,0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1d,0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1e,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f}, +{ 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, + 0x1f,0x1f} +}; + +uint8 add32_32_half [32][32] = { +{ 0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07, + 0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e, + 0x0f,0x0f}, +{ 0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07, + 0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f, + 0x0f,0x10}, +{ 0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08, + 0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f, + 0x10,0x10}, +{ 0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08, + 0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10, + 0x10,0x11}, +{ 0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09, + 0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10, + 0x11,0x11}, +{ 0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09, + 0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11, + 0x11,0x12}, +{ 0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a, + 0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11, + 0x12,0x12}, +{ 0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a, + 0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12, + 0x12,0x13}, +{ 0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b, + 0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12, + 0x13,0x13}, +{ 0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b, + 0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13, + 0x13,0x14}, +{ 0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c, + 0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13, + 0x14,0x14}, +{ 0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c, + 0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14, + 0x14,0x15}, +{ 0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d, + 0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14, + 0x15,0x15}, +{ 0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d, + 0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15, + 0x15,0x16}, +{ 0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e, + 0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15, + 0x16,0x16}, +{ 0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e, + 0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16, + 0x16,0x17}, +{ 0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f, + 0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16, + 0x17,0x17}, +{ 0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f, + 0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17, + 0x17,0x18}, +{ 0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10, + 0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17, + 0x18,0x18}, +{ 0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10, + 0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18, + 0x18,0x19}, +{ 0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11, + 0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18, + 0x19,0x19}, +{ 0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11, + 0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19, + 0x19,0x1a}, +{ 0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12, + 0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19, + 0x1a,0x1a}, +{ 0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12, + 0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a, + 0x1a,0x1b}, +{ 0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13, + 0x13,0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a, + 0x1b,0x1b}, +{ 0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13, + 0x14,0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b, + 0x1b,0x1c}, +{ 0x0d,0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14, + 0x14,0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b, + 0x1c,0x1c}, +{ 0x0d,0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14, + 0x15,0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c, + 0x1c,0x1d}, +{ 0x0e,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15, + 0x15,0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c, + 0x1d,0x1d}, +{ 0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15, + 0x16,0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d, + 0x1d,0x1e}, +{ 0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16, + 0x16,0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1d, + 0x1e,0x1e}, +{ 0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x16,0x16, + 0x17,0x17,0x18,0x18,0x19,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1e, + 0x1e,0x1f} +}; +uint8 sub32_32 [32][32] = { +{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d, + 0x1e,0x1f}, +{ 0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d, + 0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c, + 0x1d,0x1e}, +{ 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c, + 0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, + 0x1c,0x1d}, +{ 0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b, + 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a, + 0x1b,0x1c}, +{ 0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a, + 0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19, + 0x1a,0x1b}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, + 0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, + 0x19,0x1a}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15, + 0x16,0x17}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05, + 0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14, + 0x15,0x16}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04, + 0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13, + 0x14,0x15}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03, + 0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12, + 0x13,0x14}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02, + 0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11, + 0x12,0x13}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10, + 0x11,0x12}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d, + 0x0e,0x0f}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c, + 0x0d,0x0e}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b, + 0x0c,0x0d}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a, + 0x0b,0x0c}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, + 0x0a,0x0b}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x09,0x0a}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05, + 0x06,0x07}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04, + 0x05,0x06}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03, + 0x04,0x05}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02, + 0x03,0x04}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x02,0x03}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00} +}; + +uint8 sub32_32_half [32][32] = { +{ 0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07, + 0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e, + 0x0f,0x0f}, +{ 0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06, + 0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e, + 0x0e,0x0f}, +{ 0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06, + 0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d, + 0x0e,0x0e}, +{ 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05, + 0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d, + 0x0d,0x0e}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05, + 0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c, + 0x0d,0x0d}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04, + 0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c, + 0x0c,0x0d}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04, + 0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b, + 0x0c,0x0c}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03, + 0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b, + 0x0b,0x0c}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03, + 0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a, + 0x0b,0x0b}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02, + 0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09,0x0a, + 0x0a,0x0b}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02, + 0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09,0x09, + 0x0a,0x0a}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01, + 0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08,0x09, + 0x09,0x0a}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08,0x08, + 0x09,0x09}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07,0x08, + 0x08,0x09}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07, + 0x08,0x08}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07, + 0x07,0x08}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06, + 0x07,0x07}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06, + 0x06,0x07}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05, + 0x06,0x06}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05, + 0x05,0x06}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04, + 0x05,0x05}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04, + 0x04,0x05}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03, + 0x04,0x04}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,0x03, + 0x03,0x04}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02, + 0x03,0x03}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02, + 0x02,0x03}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01, + 0x02,0x02}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x01,0x02}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x01}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00} +}; + + +uint8 mul_brightness [16][32] = { +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00}, +{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02, + 0x02,0x02}, +{ 0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02, + 0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x04,0x04, + 0x04,0x04}, +{ 0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x03,0x03, + 0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x05,0x06,0x06, + 0x06,0x06}, +{ 0x00,0x00,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x04, + 0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x08, + 0x08,0x08}, +{ 0x00,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x04,0x05, + 0x05,0x05,0x06,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a, + 0x0a,0x0a}, +{ 0x00,0x00,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x04,0x04,0x04,0x05,0x05,0x06, + 0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0a,0x0b,0x0b,0x0c, + 0x0c,0x0c}, +{ 0x00,0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07, + 0x07,0x07,0x08,0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e, + 0x0e,0x0e}, +{ 0x00,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x05,0x05,0x06,0x06,0x07,0x07, + 0x08,0x09,0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x0f, + 0x10,0x11}, +{ 0x00,0x01,0x01,0x02,0x02,0x03,0x04,0x04,0x05,0x05,0x06,0x07,0x07,0x08,0x08, + 0x09,0x0a,0x0a,0x0b,0x0b,0x0c,0x0d,0x0d,0x0e,0x0e,0x0f,0x10,0x10,0x11,0x11, + 0x12,0x13}, +{ 0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x05,0x06,0x07,0x07,0x08,0x09,0x09, + 0x0a,0x0b,0x0b,0x0c,0x0d,0x0d,0x0e,0x0f,0x0f,0x10,0x11,0x11,0x12,0x13,0x13, + 0x14,0x15}, +{ 0x00,0x01,0x01,0x02,0x03,0x04,0x04,0x05,0x06,0x07,0x07,0x08,0x09,0x0a,0x0a, + 0x0b,0x0c,0x0c,0x0d,0x0e,0x0f,0x0f,0x10,0x11,0x12,0x12,0x13,0x14,0x15,0x15, + 0x16,0x17}, +{ 0x00,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x06,0x07,0x08,0x09,0x0a,0x0a,0x0b, + 0x0c,0x0d,0x0e,0x0e,0x0f,0x10,0x11,0x12,0x12,0x13,0x14,0x15,0x16,0x16,0x17, + 0x18,0x19}, +{ 0x00,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0a,0x0b,0x0c, + 0x0d,0x0e,0x0f,0x10,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x17,0x18,0x19, + 0x1a,0x1b}, +{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d, + 0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b, + 0x1c,0x1d}, +{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d, + 0x1e,0x1f} +}; + + diff --git a/source/snes9x/debug.cpp b/source/snes9x/debug.cpp new file mode 100644 index 0000000..0a531aa --- /dev/null +++ b/source/snes9x/debug.cpp @@ -0,0 +1,2305 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#include "snes9x.h" +#include "memmap.h" +#include "cpuops.h" + +#ifndef NGC +#include "cheats.h" +#endif + +#include "ppu.h" +#include "cpuexec.h" +#include "debug.h" +#include "missing.h" +#include "display.h" +#include "apu.h" +#include "sa1.h" +#include "spc7110.h" + +#ifdef DEBUGGER +static void WhatsMissing (); +static void WhatsUsed (); +EXTERN_C SDMA DMA[8]; +extern struct SCheatData Cheat; + +#ifdef SPCTOOL +#include "spctool/spc700.h" +extern "C" void TraceSPC (unsigned char *PC, unsigned short YA, unsigned char X, + SPCFlags PS, unsigned char *SP); +#endif + +FILE *trace = NULL; +FILE *trace2 = NULL; +struct SBreakPoint S9xBreakpoint[6]; +struct SDebug +{ + struct + { + uint8 Bank; + uint16 Address; + } Dump; + struct + { + uint8 Bank; + uint16 Address; + } Unassemble; +} Debug = +{ + { + 0, 0 + }, + { + 0, 0 + } +}; +char *HelpMessage[] = { + "Command Help:", + "? - Shows this Command Help", + "r - Shows the Registers", + "i - Shows the interrupt vectors", + "t - Trace current instruction [Step-into]", + "T - Toggle CPU instruction tracing to trace.log", + "D - Toggle DMA tracing to stdout", + "H - Toggle H-DMA tracing to stdout", + "P - Toggle DSP tracing to stdout", + "U - Toggle unknown register read/write tracing", + "V - Toggle non-DMA V-RAM read/write tracing", + "R - Reset ROM.", + "p - Proceed to next instruction [Step-over]", + "s - Skip to next instruction [Skip]", + "S - dump sprite (OBJ) status", + "g [Address] - Go or Go to [Address]", + "u [Address] - Disassemble from PC or [Address]", + "d [Address] - Dump from PC or [Address]", + "bv [Number] - View Breakpoints or View Breakpoint [Number]", + "bs [Number] [Address] - Enable/Disable Breakpoint", + " [Enable example: BS #2 $02:8002]", + " [Disable example: BS #2]", + "c - Dump SNES colour palette", + "W - Show what SNES hardware features a ROM is using", + " which might not be implemented yet.", + "w - Show some SNES hardware features used so far in this frame", + "q - Quit emulator", + "", + "[Address] - $Bank:Address or $Address", + " [For example: $01:8123]", + "[Number] - #Number", + " [For example: #1]", + "a - Show Sound CPU status", + "A - Toggle sound CPU instruction tracing to aputrace.log", + "B - Toggle sound DSP register tracing", + "C - Dump sound sample addresses", + "ad [Address] - Dump sound CPU RAM from PC or [Address]", + "", NULL}; + +char *S9xMnemonics[256] = { + "BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", + "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA", + "BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", + "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA", + "JSR", "AND", "JSL", "AND", "BIT", "AND", "ROL", "AND", + "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND", + "BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", + "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND", + "RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", + "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR", + "BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", + "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR", + "RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", + "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC", + "BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", + "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC", + "BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", + "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA", + "BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", + "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA", + "LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", + "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA", + "BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", + "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA", + "CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", + "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP", + "BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", + "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP", + "CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", + "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC", + "BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", + "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC" +}; +int AddrModes[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 3, 10, 3, 19, 6, 6, 6, 12, 0, 1,24, 0, 14, 14, 14, 17, //0 + 4, 11, 9, 20, 6, 7, 7, 13, 0, 16,24, 0, 14, 15, 15, 18, //1 + 14, 10,17, 19, 6, 6, 6, 12, 0, 1,24, 0, 14, 14, 14, 17, //2 + 4, 11, 9, 20, 7, 7, 7, 13, 0, 16,24, 0, 15, 15, 15, 18, //3 + 0, 10, 3, 19, 25,6, 6, 12, 0, 1,24, 0, 14, 14, 14, 17, //4 + 4, 11, 9, 20, 25,7, 7, 13, 0, 16, 0, 0, 17, 15, 15, 18, //5 + 0, 10, 5, 19, 6, 6, 6, 12, 0, 1,24, 0, 21, 14, 14, 17, //6 + 4, 11, 9, 20, 7, 7, 7, 13, 0, 16, 0, 0, 23, 15, 15, 18, //7 + 4, 10, 5, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, //8 + 4, 11, 9, 20, 7, 7, 8, 13, 0, 16, 0, 0, 14, 15, 15, 18, //9 + 2, 10, 2, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, //A + 4, 11, 9, 20, 7, 7, 8, 13, 0, 16, 0, 0, 15, 15, 16, 18, //B + 2, 10, 3, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, //C + 4, 11, 9, 9,27, 7, 7, 13, 0, 16, 0, 0, 22, 15, 15, 18, //D + 2, 10, 3, 19, 6, 6, 6, 12, 0, 1, 0, 0, 14, 14, 14, 17, //E + 4, 11, 9, 20,26, 7, 7, 13, 0, 16, 0, 0, 23, 15, 15, 18 //F +}; + +uint8 S9xOPrint (char *Line, uint8 Bank, uint16 Address) +{ + uint8 S9xOpcode; + uint8 Operant[3]; + uint16 Word; + uint8 Byte; + uint8 Size = 0; + char SByte; + short SWord; + +#if 0 + sprintf (Line, "%04X%04X%04X%04X%02X%04X%c%c%c%c%c%c%c%c%c%03d%03d", + Registers.A.W, Registers.X.W, Registers.Y.W, + Registers.D.W, Registers.DB, Registers.S.W, + CheckEmulation () ? 'E' : 'e', + CheckNegative () ? 'N' : 'n', + CheckOverflow () ? 'V' : 'v', + CheckMemory () ? 'M' : 'm', + CheckIndex () ? 'X' : 'x', + CheckDecimal () ? 'D' : 'd', + CheckIRQ () ? 'I' : 'i', + CheckZero () ? 'Z' : 'z', + CheckCarry () ? 'C' : 'c', + CPU.Cycles, + CPU.V_Counter); + return (0); + +#else + int32 Cycles = CPU.Cycles; + uint32 WaitAddress = CPU.WaitAddress; + + S9xOpcode = S9xGetByte ((Bank << 16) + Address); + sprintf (Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); + Operant[0] = S9xGetByte ((Bank << 16) + Address + 1); + Operant[1] = S9xGetByte ((Bank << 16) + Address + 2); + Operant[2] = S9xGetByte ((Bank << 16) + Address + 3); + + switch (AddrModes[S9xOpcode]) + { + case 0: + //Implied + sprintf (Line, "%s %s", Line, S9xMnemonics[S9xOpcode]); + Size = 1; + break; + case 1: + //Immediate[MemoryFlag] + if (!CheckFlag (MemoryFlag)) + { + //Accumulator 16 - Bit + sprintf (Line, "%s%02X %02X %s #$%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Size = 3; + } + else + { + //Accumulator 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 2: + //Immediate[IndexFlag] + if (!CheckFlag (IndexFlag)) + { + //X / Y 16 - Bit + sprintf (Line, "%s%02X %02X %s #$%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Size = 3; + } + else + { + //X / Y 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 3: + //Immediate[Always 8 - Bit] + if (1) + { + //Always 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 4: + //Relative + sprintf (Line, "%s%02X %s $%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + SByte = Operant[0]; + Word = Address; + Word += SByte; + Word += 2; + sprintf (Line, "%-32s[$%04X]", Line, Word); + Size = 2; + break; + case 5: + //Relative Long + sprintf (Line, "%s%02X %02X %s $%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + SWord = (Operant[1] << 8) | Operant[0]; + Word = Address; + Word += SWord; + Word += 3; + sprintf (Line, "%-32s[$%04X]", Line, Word); + Size = 3; + break; + case 6: + //Direct + sprintf (Line, "%s%02X %s $%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 7: + //Direct indexed (with x) + sprintf (Line, "%s%02X %s $%02X,x", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word += Registers.X.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 8: + //Direct indexed (with y) + sprintf (Line, "%s%02X %s $%02X,y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word += Registers.Y.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 9: + //Direct Indirect + sprintf (Line, "%s%02X %s ($%02X)", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 2; + break; + case 10: + //Direct Indexed Indirect + sprintf (Line, "%s%02X %s ($%02X,x)", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word += Registers.X.W; + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 2; + break; + case 11: + //Direct Indirect Indexed + sprintf (Line, "%s%02X %s ($%02X),y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word = S9xGetWord (Word); + Word += Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 2; + break; + case 12: + //Direct Indirect Long + sprintf (Line, "%s%02X %s [$%02X]", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Byte = S9xGetByte (Word + 2); + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 2; + break; + case 13: + //Direct Indirect Indexed Long + sprintf (Line, "%s%02X %s [$%02X],y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Byte = S9xGetByte (Word + 2); + Word = S9xGetWord (Word); + Word += Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 2; + break; + case 14: + //Absolute + sprintf (Line, "%s%02X %02X %s $%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 3; + break; + case 15: + //Absolute Indexed (With X) + sprintf (Line, "%s%02X %02X %s $%02X%02X,x", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += Registers.X.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 3; + break; + case 16: + //Absolute Indexed (With Y) + sprintf (Line, "%s%02X %02X %s $%02X%02X,y", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 3; + break; + case 17: + //Absolute long + sprintf (Line, "%s%02X %02X %02X %s $%02X%02X%02X", + Line, + Operant[0], + Operant[1], + Operant[2], + S9xMnemonics[S9xOpcode], + Operant[2], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); + Size = 4; + break; + case 18: + //Absolute Indexed long + sprintf (Line, "%s%02X %02X %02X %s $%02X%02X%02X,x", + Line, + Operant[0], + Operant[1], + Operant[2], + S9xMnemonics[S9xOpcode], + Operant[2], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += Registers.X.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); + Size = 4; + break; + case 19: + //StackRelative + sprintf (Line, "%s%02X %s $%02X,s", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Registers.S.W; + Word += Operant[0]; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 20: + //Stack Relative Indirect Indexed + sprintf (Line, "%s%02X %s ($%02X,s),y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Registers.S.W; + Word += Operant[0]; + Word = S9xGetWord (Word); + Word += Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.DB, Word); + Size = 2; + break; + case 21: + //Absolute Indirect + sprintf (Line, "%s%02X %02X %s ($%02X%02X)", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); + Size = 3; + break; + case 22: + //Absolute Indirect Long + sprintf (Line, "%s%02X %02X %s [$%02X%02X]", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Byte = S9xGetByte (Word + 2); + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 3; + break; + case 23: + //Absolute Indexed Indirect + sprintf (Line, "%s%02X %02X %s ($%02X%02X,x)", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += Registers.X.W; + Word = S9xGetWord (ICPU.ShiftedPB + Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Registers.PB, Word); + Size = 3; + break; + case 24: + //Implied accumulator + sprintf (Line, "%s %s A", Line, S9xMnemonics[S9xOpcode]); + Size = 1; + break; + case 25: + // MVN/MVP SRC DST + sprintf (Line, "%s%02X %02X %s %02X %02X", Line, Operant[0], Operant[1], S9xMnemonics[S9xOpcode], + Operant[1], Operant[0]); + Size = 3; + break; + case 26: + // PEA + sprintf (Line, "%s%02X %02X %s $%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Size = 3; + break; + case 27: + // PEI Direct Indirect + sprintf (Line, "%s%02X %s ($%02X)", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += Registers.D.W; + Word = S9xGetWord (Word); + sprintf (Line, "%-32s[$%04X]", Line, Word); + Size = 2; + break; + } +// XXX: + sprintf (Line, "%-44s A:%04X X:%04X Y:%04X D:%04X DB:%02X S:%04X P:%c%c%c%c%c%c%c%c%c HC:%03d VC:%03ld %02x", + Line, Registers.A.W, Registers.X.W, Registers.Y.W, + Registers.D.W, Registers.DB, Registers.S.W, + CheckEmulation () ? 'E' : 'e', + CheckNegative () ? 'N' : 'n', + CheckOverflow () ? 'V' : 'v', + CheckMemory () ? 'M' : 'm', + CheckIndex () ? 'X' : 'x', + CheckDecimal () ? 'D' : 'd', + CheckIRQ () ? 'I' : 'i', + CheckZero () ? 'Z' : 'z', + CheckCarry () ? 'C' : 'c', + Cycles, + CPU.V_Counter, + CPU.IRQActive); + + CPU.Cycles = Cycles; + CPU.WaitAddress = WaitAddress; + return Size; +#endif +} + +uint8 S9xSA1OPrint (char *Line, uint8 Bank, uint16 Address) +{ + uint8 S9xOpcode; + uint8 Operant[3]; + uint16 Word; + uint8 Byte; + uint8 Size = 0; + char SByte; + short SWord; + +#if 0 + sprintf (Line, "%04X%04X%04X%04X%02X%04X%c%c%c%c%c%c%c%c%c%03d%03d", + SA1Registers.A.W, SA1Registers.X.W, SA1Registers.Y.W, + SA1Registers.D.W, SA1Registers.DB, SA1Registers.S.W, + SA1CheckEmulation () ? 'E' : 'e', + SA1CheckNegative () ? 'N' : 'n', + SA1CheckOverflow () ? 'V' : 'v', + SA1CheckMemory () ? 'M' : 'm', + SA1CheckIndex () ? 'X' : 'x', + SA1CheckDecimal () ? 'D' : 'd', + SA1CheckIRQ () ? 'I' : 'i', + SA1CheckZero () ? 'Z' : 'z', + SA1CheckCarry () ? 'C' : 'c', + CPU.Cycles, + CPU.V_Counter); + return (0); + +#else + S9xOpcode = S9xSA1GetByte ((Bank << 16) + Address); + sprintf (Line, "$%02X:%04X %02X ", Bank, Address, S9xOpcode); + Operant[0] = S9xSA1GetByte ((Bank << 16) + Address + 1); + Operant[1] = S9xSA1GetByte ((Bank << 16) + Address + 2); + Operant[2] = S9xSA1GetByte ((Bank << 16) + Address + 3); + + switch (AddrModes[S9xOpcode]) + { + case 0: + //Implied + sprintf (Line, "%s %s", Line, S9xMnemonics[S9xOpcode]); + Size = 1; + break; + case 1: + //Immediate[MemoryFlag] + if (!SA1CheckFlag (MemoryFlag)) + { + //Accumulator 16 - Bit + sprintf (Line, "%s%02X %02X %s #$%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Size = 3; + } + else + { + //Accumulator 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 2: + //Immediate[IndexFlag] + if (!SA1CheckFlag (IndexFlag)) + { + //X / Y 16 - Bit + sprintf (Line, "%s%02X %02X %s #$%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Size = 3; + } + else + { + //X / Y 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 3: + //Immediate[Always 8 - Bit] + if (1) + { + //Always 8 - Bit + sprintf (Line, "%s%02X %s #$%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Size = 2; + } + break; + case 4: + //Relative + sprintf (Line, "%s%02X %s $%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + SByte = Operant[0]; + Word = Address; + Word += SByte; + Word += 2; + sprintf (Line, "%-32s[$%04X]", Line, Word); + Size = 2; + break; + case 5: + //Relative Long + sprintf (Line, "%s%02X %02X %s $%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + SWord = (Operant[1] << 8) | Operant[0]; + Word = Address; + Word += SWord; + Word += 3; + sprintf (Line, "%-32s[$%04X]", Line, Word); + Size = 3; + break; + case 6: + //Direct + sprintf (Line, "%s%02X %s $%02X", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 7: + //Direct indexed (with x) + sprintf (Line, "%s%02X %s $%02X,x", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Word += SA1Registers.X.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 8: + //Direct indexed (with y) + sprintf (Line, "%s%02X %s $%02X,y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Word += SA1Registers.Y.W; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 9: + //Direct Indirect + sprintf (Line, "%s%02X %s ($%02X)", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Word = S9xSA1GetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 2; + break; + case 10: + //Direct Indexed Indirect + sprintf (Line, "%s%02X %s ($%02X,x)", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Word += SA1Registers.X.W; + Word = S9xSA1GetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 2; + break; + case 11: + //Direct Indirect Indexed + sprintf (Line, "%s%02X %s ($%02X),y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Word = S9xSA1GetWord (Word); + Word += SA1Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 2; + break; + case 12: + //Direct Indirect Long + sprintf (Line, "%s%02X %s [$%02X]", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Byte = S9xSA1GetByte (Word + 2); + Word = S9xSA1GetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 2; + break; + case 13: + //Direct Indirect Indexed Long + sprintf (Line, "%s%02X %s [$%02X],y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = Operant[0]; + Word += SA1Registers.D.W; + Byte = S9xSA1GetByte (Word + 2); + Word = S9xSA1GetWord (Word); + Word += SA1Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 2; + break; + case 14: + //Absolute + sprintf (Line, "%s%02X %02X %s $%02X%02X", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 3; + break; + case 15: + //Absolute Indexed (With X) + sprintf (Line, "%s%02X %02X %s $%02X%02X,x", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += SA1Registers.X.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 3; + break; + case 16: + //Absolute Indexed (With Y) + sprintf (Line, "%s%02X %02X %s $%02X%02X,y", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += SA1Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 3; + break; + case 17: + //Absolute long + sprintf (Line, "%s%02X %02X %02X %s $%02X%02X%02X", + Line, + Operant[0], + Operant[1], + Operant[2], + S9xMnemonics[S9xOpcode], + Operant[2], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); + Size = 4; + break; + case 18: + //Absolute Indexed long + sprintf (Line, "%s%02X %02X %02X %s $%02X%02X%02X,x", + Line, + Operant[0], + Operant[1], + Operant[2], + S9xMnemonics[S9xOpcode], + Operant[2], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += SA1Registers.X.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, Operant[2], Word); + Size = 4; + break; + case 19: + //StackRelative + sprintf (Line, "%s%02X %s $%02X,s", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = SA1Registers.S.W; + Word += Operant[0]; + sprintf (Line, "%-32s[$00:%04X]", Line, Word); + Size = 2; + break; + case 20: + //Stack Relative Indirect Indexed + sprintf (Line, "%s%02X %s ($%02X,s),y", + Line, + Operant[0], + S9xMnemonics[S9xOpcode], + Operant[0]); + Word = SA1Registers.S.W; + Word += Operant[0]; + Word = S9xSA1GetWord (Word); + Word += SA1Registers.Y.W; + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.DB, Word); + Size = 2; + break; + case 21: + //Absolute Indirect + sprintf (Line, "%s%02X %02X %s ($%02X%02X)", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word = S9xSA1GetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); + Size = 3; + break; + case 22: + //Absolute Indirect Long + sprintf (Line, "%s%02X %02X %s [$%02X%02X]", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Byte = S9xSA1GetByte (Word + 2); + Word = S9xSA1GetWord (Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, Byte, Word); + Size = 3; + break; + case 23: + //Absolute Indexed Indirect + sprintf (Line, "%s%02X %02X %s ($%02X%02X,x)", + Line, + Operant[0], + Operant[1], + S9xMnemonics[S9xOpcode], + Operant[1], + Operant[0]); + Word = (Operant[1] << 8) | Operant[0]; + Word += SA1Registers.X.W; + Word = S9xSA1GetWord (SA1.ShiftedPB + Word); + sprintf (Line, "%-32s[$%02X:%04X]", Line, SA1Registers.PB, Word); + Size = 3; + break; + case 24: + //Implied accumulator + sprintf (Line, "%s %s A", Line, S9xMnemonics[S9xOpcode]); + Size = 1; + break; + case 25: + // MVN/MVP SRC DST + sprintf (Line, "%s %s %02X %02X", Line, S9xMnemonics[S9xOpcode], + Operant[0], Operant[1]); + Size = 3; + break; + } + sprintf (Line, "%-44s A:%04X X:%04X Y:%04X D:%04X DB:%02X S:%04X P:%c%c%c%c%c%c%c%c%c HC:%03ld VC:%03ld", + Line, SA1Registers.A.W, SA1Registers.X.W, SA1Registers.Y.W, + SA1Registers.D.W, SA1Registers.DB, SA1Registers.S.W, + SA1CheckEmulation () ? 'E' : 'e', + SA1CheckNegative () ? 'N' : 'n', + SA1CheckOverflow () ? 'V' : 'v', + SA1CheckMemory () ? 'M' : 'm', + SA1CheckIndex () ? 'X' : 'x', + SA1CheckDecimal () ? 'D' : 'd', + SA1CheckIRQ () ? 'I' : 'i', + SA1CheckZero () ? 'Z' : 'z', + SA1CheckCarry () ? 'C' : 'c', + CPU.Cycles, + CPU.V_Counter); + + return Size; +#endif +} + +/**********************************************************************************************/ +/* DPrint() */ +/* This function prints a line in the debug listbox and deletes upperlines if needed */ +/**********************************************************************************************/ +void DPrint (char *Line) +{ + printf ("%s\n", Line); +} +/**********************************************************************************************/ +/* GetNumber() */ +/* This function gets a number from a debug command */ +/**********************************************************************************************/ +int GetNumber (char *Line, uint16 * Number) +{ + int i; + if (sscanf (Line, " #%d", &i) == 1) + { + *Number = i; + return (1); + } + return (-1); +} +/**********************************************************************************************/ +/* GetStartAddress() */ +/* This function gets a starting address from a debug command */ +/**********************************************************************************************/ +short GetStartAddress (char *Line, uint8 *Bank, uint32 *Address) +{ + uint32 a, b; + if (sscanf (Line + 1, " $%x:%x", &b, &a) != 2) + return (-1); + *Bank = b; + *Address = a; + return (1); +} +/**********************************************************************************************/ +/* ProcessDebugCommand() */ +/* This function processes a debug command */ +/**********************************************************************************************/ +static void ProcessDebugCommand (char *Line) +{ + uint8 Bank = Registers.PB; + uint32 Address = Registers.PCw; + uint16 Hold; + uint16 Number; + char String [512]; + short ErrorCode; + + if (strcasecmp (Line, "cheat") == 0) + { + S9xStartCheatSearch (&Cheat); + printf ("Cheat Search Started\n"); + return; + } + if (strcasecmp (Line, "less") == 0) + { + S9xSearchForChange (&Cheat, S9X_LESS_THAN, S9X_8_BITS, FALSE, TRUE); + printf ("Recorded all values that have decreased\n"); + return; + } + if (strcasecmp (Line, "print") == 0) + { + printf ("Cheat search results:\n"); + S9xOutputCheatSearchResults (&Cheat); + return; + } + + if (strncasecmp (Line, "constant", 8) == 0) + { + uint32 Byte; + if (sscanf (&Line [8], "%x %x", &Address, &Byte) == 2) + S9xAddCheat (TRUE, TRUE, Address, Byte); + return; + } + + if (strncasecmp (Line, "dump", 4) == 0) + { + int Count; + if (sscanf (&Line [4], "%x %d", &Address, &Count) == 2) + { + sprintf (String, "%06x%05d.sd2", Address, Count); + FILE *fs = fopen (String, "wb"); + if (fs) + { + int i; + for (i = 0; i < Count; i++) + putc (S9xGetByte (Address + i), fs); + + fclose (fs); + } + else + printf ("Can't open %s for writing\n", String); + } + else + printf ("Usage: dump start_address_in_hex count_in_decimal\n"); + return; + } + if (Line[0] == 'i') + { + printf ("Vectors:\n"); + sprintf (String, " 8 Bit 16 Bit "); + DPrint (String); + sprintf (String, "ABT $00:%04X|$00:%04X", S9xGetWord (0xFFF8), S9xGetWord (0xFFE8)); + DPrint (String); + sprintf (String, "BRK $00:%04X|$00:%04X", S9xGetWord (0xFFFE), S9xGetWord (0xFFE6)); + DPrint (String); + sprintf (String, "COP $00:%04X|$00:%04X", S9xGetWord (0xFFF4), S9xGetWord (0xFFE4)); + DPrint (String); + sprintf (String, "IRQ $00:%04X|$00:%04X", S9xGetWord (0xFFFE), S9xGetWord (0xFFEE)); + DPrint (String); + sprintf (String, "NMI $00:%04X|$00:%04X", S9xGetWord (0xFFFA), S9xGetWord (0xFFEA)); + DPrint (String); + sprintf (String, "RES $00:%04X", S9xGetWord (0xFFFC)); + DPrint (String); + } + if (strncmp (Line, "ai", 2) == 0) + { + printf ("APU vectors:"); + for (int i = 0; i < 0x40; i += 2) + { + if (i % 16 == 0) + printf ("\n%04x ", 0xffc0 + i); + printf ("%04x ", APU.ExtraRAM [i]); + } + printf ("\n"); + } + if (Line[0] == 's') + { + Registers.PCw += S9xOPrint (String, Bank, Address); + Bank = Registers.PB; + Address = Registers.PCw; + Line[0] = 'r'; + } + if (Line[0] == 'z') + { + uint16 *p = (uint16 *) &Memory.VRAM [PPU.BG[2].SCBase << 1]; + for (int l = 0; l < 32; l++) + { + for (int c = 0; c < 32; c++, p++) + { + printf ("%04x,", *p++); + } + printf ("\n"); + } + } + if (*Line == 'c') + { + printf ("Colours:\n"); + for (int i = 0; i < 256; i++) + { + printf ("%02x%02x%02x ", PPU.CGDATA[i] & 0x1f, + (PPU.CGDATA[i] >> 5) & 0x1f, + (PPU.CGDATA[i] >> 10) & 0x1f); + } + printf ("\n"); + } + if (*Line == 'S') + { + int SmallWidth, LargeWidth; + int SmallHeight, LargeHeight; + switch ((Memory.FillRAM[0x2101] >> 5) & 7) + { + case 0: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 16; + break; + case 1: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 32; + break; + case 2: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 64; + break; + case 3: + SmallWidth = SmallHeight = 16; + LargeWidth = LargeHeight = 32; + break; + case 4: + SmallWidth = SmallHeight = 16; + LargeWidth = LargeHeight = 64; + break; + default: + case 5: + SmallWidth = SmallHeight = 32; + LargeWidth = LargeHeight = 64; + break; + case 6: + SmallWidth = 16; SmallHeight = 32; + LargeWidth = 32; LargeHeight = 64; + break; + case 7: + SmallWidth = 16; SmallHeight = 32; + LargeWidth = LargeHeight = 32; + break; + } + printf ("Sprites: Small: %dx%d, Large: %dx%d, OAMAddr: 0x%04x, OBJNameBase: 0x%04x, OBJNameSelect: 0x%04x, First: %d\n", + SmallWidth,SmallHeight, LargeWidth,LargeHeight, PPU.OAMAddr, + PPU.OBJNameBase, PPU.OBJNameSelect, PPU.FirstSprite); +// for (int p = 0; p < 4; p++) +// { +// int c = 0; +// int i; +// for (i = 0; GFX.OBJList [i] >= 0; i++) +// { +// if (PPU.OBJ[GFX.OBJList [i]].Priority == p) +// c++; +// } +// printf ("Priority %d: %03d, ", p, c); +// } +// printf ("\n"); + for (int i = 0; i < 128; i++) + { + printf ("X:%3d Y:%3d %c%c%d%c ", + PPU.OBJ[i].HPos, + PPU.OBJ[i].VPos, + PPU.OBJ[i].VFlip ? 'V' : 'v', + PPU.OBJ[i].HFlip ? 'H' : 'h', + PPU.OBJ[i].Priority, + PPU.OBJ[i].Size ? 'S' : 's'); + if (i % 4 == 3) + printf ("\n"); + } + } + if (*Line == 'T') + { + if (Line [1] == 'S') + { + SA1.Flags ^= TRACE_FLAG; + if (SA1.Flags & TRACE_FLAG) + { + printf ("SA1 CPU instruction tracing enabled.\n"); + if (trace2 == NULL) + trace2 = fopen ("trace_sa1.log", "wb"); + } + else + { + printf ("SA1 CPU instruction tracing disabled.\n"); + fclose (trace2); + trace2 = NULL; + } + } + else + { + CPU.Flags ^= TRACE_FLAG; + if (CPU.Flags & TRACE_FLAG) + { + printf ("CPU instruction tracing enabled.\n"); + if (trace == NULL) + trace = fopen ("trace.log", "wb"); + } + else + { + printf ("CPU instruction tracing disabled.\n"); + fclose (trace); + trace = NULL; + } + } + } + if (*Line == 'A') + { + APU.Flags ^= TRACE_FLAG; + + extern FILE *apu_trace; + if (APU.Flags & TRACE_FLAG) + { +#ifdef SPCTOOL + printf ("ENABLED\n"); + _SetSPCDbg (TraceSPC); //Install debug handler +#endif + if (apu_trace == NULL) + apu_trace = fopen ("aputrace.log", "wb"); + } + else + { +#ifdef SPCTOOL + _SetSPCDbg (NULL); +#endif + if (apu_trace) + { + fclose (apu_trace); + apu_trace = NULL; + } + } + + printf ("APU tracing %s\n", APU.Flags & TRACE_FLAG ? "enabled" : + "disabled"); + } + if (*Line == 'B') + { + Settings.TraceSoundDSP ^= 1; + printf ("Sound DSP register tracing %s\n", Settings.TraceSoundDSP ? + "enabled" : "disabled"); + + S9xOpenCloseSoundTracingFile (Settings.TraceSoundDSP); + } + + if (*Line == 'b') + S9xPrintAPUState (); + + if (*Line == 'C') + { + printf ("SPC700 sample addresses at 0x%04x:\n", APU.DSP [APU_DIR] << 8); + for (int i = 0; i < 256; i++) + { + uint8 *dir = IAPU.RAM + + (((APU.DSP [APU_DIR] << 8) + + i * 4) & 0xffff); + int addr = *dir + (*(dir + 1) << 8); + int addr2 = *(dir + 2) + (*(dir + 3) << 8); + printf ("%04X %04X;", addr, addr2); + if (i % 8 == 7) + printf ("\n"); + } + } + if (*Line == 'R') + { + S9xReset (); + printf ("SNES reset.\n"); + CPU.Flags |= DEBUG_MODE_FLAG; + } + if (strncmp (Line, "ad", 2) == 0) + { + uint32 Count = 16; + Address = 0; + if (sscanf (Line+2, "%x,%x", &Address, &Count) != 2) + { + if (sscanf (Line + 2, "%x", &Address) == 1) + Count = 16; + } + printf ("APU RAM dump:\n"); + for (uint32 l = 0; l < Count; l += 16) + { + printf ("%04X ", Address); + for (int i = 0; i < 16; i++) + printf ("%02X ", IAPU.RAM [Address++]); + printf ("\n"); + } + *Line = 0; + } + if (*Line == 'a') + { + printf ("APU in-ports: %02X %02X %02X %02X\n", + IAPU.RAM [0xF4], IAPU.RAM [0xF5], IAPU.RAM [0xF6], IAPU.RAM [0xF7]); +#ifdef SPCTOOL + printf ("APU out-ports: %02X %02X %02X %02X\n", + _SPCOutP [0], _SPCOutP [1], _SPCOutP [2], _SPCOutP [3]); +#else + printf ("APU out-ports: %02X %02X %02X %02X\n", + APU.OutPorts [0], APU.OutPorts [1], APU.OutPorts [2], APU.OutPorts [3]); +#endif + printf ("ROM/RAM switch: %s\n", (IAPU.RAM [0xf1] & 0x80) ? "ROM" : "RAM"); + for (int i = 0; i < 3; i++) + if (APU.TimerEnabled [i]) + printf ("Timer%d enabled, Value: 0x%03X, 4-bit: 0x%02X, Target: 0x%03X\n", + i, APU.Timer [i], IAPU.RAM [0xfd + i], APU.TimerTarget [i]); + } + if (*Line == 'P') + { + Settings.TraceDSP = !Settings.TraceDSP; + printf ("DSP tracing %s\n", Settings.TraceDSP ? "enabled" : "disabled"); + } + if (Line[0] == 'p') + { + S9xBreakpoint[5].Enabled = FALSE; + Address += S9xOPrint (String, Bank, Address); + if (strncmp (&String[18], "JMP", 3) != 0 && + strncmp (&String[18], "JML", 3) != 0 && + strncmp (&String[18], "RT", 2) != 0 && + strncmp (&String[18], "BRA", 3)) + { + S9xBreakpoint[5].Enabled = TRUE; + S9xBreakpoint[5].Bank = Bank; + S9xBreakpoint[5].Address = Address; + } + else + { + CPU.Flags |= SINGLE_STEP_FLAG; + CPU.Flags &= ~DEBUG_MODE_FLAG; + } + } + if (Line[0] == 'b') + { + if (Line[1] == 's') + { + GetNumber (Line + 2, &Hold); + if (Hold > 4) + Hold = 0; + if (Hold < 5) + if (GetStartAddress (Line + 5, &Bank, &Address) == -1) + { + //Clear S9xBreakpoint + S9xBreakpoint[Hold].Enabled = FALSE; + } + else + { + //Set S9xBreakpoint + S9xBreakpoint[Hold].Enabled = TRUE; + S9xBreakpoint[Hold].Bank = Bank; + S9xBreakpoint[Hold].Address = Address; + CPU.Flags |= BREAK_FLAG; + } + Line = "bv"; + } + if (Line[1] == 'v') + { + Number = 0; + if (GetNumber (Line + 2, &Number) == -1 && + Number < 5) + { + //Show All Breakpoints + DPrint ("Breakpoints:"); + for (Number = 0; Number != 5; Number++) + { + if (S9xBreakpoint[Number].Enabled) + sprintf (String, "%i @ $%02X:%04X", Number, S9xBreakpoint[Number].Bank, S9xBreakpoint[Number].Address); + else + sprintf (String, "%i @ Disabled", Number); + DPrint (String); + } + } + else + { + //Show selected S9xBreakpoint + DPrint ("Breakpoint:"); + if (S9xBreakpoint[Number].Enabled) + sprintf (String, "%i @ $%02X:%04X", Number, S9xBreakpoint[Number].Bank, S9xBreakpoint[Number].Address); + else + sprintf (String, "%i @ Disabled", Number); + DPrint (String); + } + } + } + if (Line[0] == '?' || strcasecmp (Line, "help") == 0) + { + for (short Counter = 0; HelpMessage[Counter] != NULL; Counter++) + DPrint (HelpMessage[Counter]); + } + if (Line[0] == 't') + { + CPU.Flags |= SINGLE_STEP_FLAG; + CPU.Flags &= ~DEBUG_MODE_FLAG; + } + if (Line[0] == 'f') + { + CPU.Flags |= FRAME_ADVANCE_FLAG; + CPU.Flags &= ~DEBUG_MODE_FLAG; + // Render this frame + IPPU.RenderThisFrame = TRUE; + IPPU.FrameSkip = 0; + if (sscanf (&Line [1], "%u", &ICPU.FrameAdvanceCount) != 1) + ICPU.Frame = 0; + } + + if (Line[0] == 'g') + { + S9xBreakpoint[5].Enabled = FALSE; + int i; + bool8 found = FALSE; + for (i = 0; i < 5; i++) + { + if (S9xBreakpoint[i].Enabled) + { + found = TRUE; + if (S9xBreakpoint[i].Bank == Registers.PB && + S9xBreakpoint[i].Address == Registers.PCw) + { + S9xBreakpoint[i].Enabled = 2; + break; + } + } + } + if (!found) + CPU.Flags &= ~BREAK_FLAG; + ErrorCode = GetStartAddress (Line, &Bank, &Address); + if (ErrorCode == 1) + { + S9xBreakpoint[5].Enabled = TRUE; + S9xBreakpoint[5].Bank = Bank; + S9xBreakpoint[5].Address = Address; + CPU.Flags |= BREAK_FLAG; + } + CPU.Flags &= ~DEBUG_MODE_FLAG; + } + if (*Line == 'D') + { + Settings.TraceDMA = !Settings.TraceDMA; + printf ("DMA tracing %s\n", Settings.TraceDMA ? "enabled" : "disabled"); + } + if (*Line == 'V') + { + Settings.TraceVRAM = !Settings.TraceVRAM; + printf ("Non-DMA VRAM write tracing %s\n", Settings.TraceVRAM ? "enabled" : "disabled"); + } + if (*Line == 'H') + { + Settings.TraceHDMA = !Settings.TraceHDMA; + printf ("H-DMA tracing %s\n", Settings.TraceHDMA ? "enabled" : "disabled"); + } + if (*Line == 'U') + { + Settings.TraceUnknownRegisters = !Settings.TraceUnknownRegisters; + printf ("Unknown registers read/write tracing %s\n", + Settings.TraceUnknownRegisters ? "enabled" : "disabled"); + } + if (Line[0] == 'd') + { + int CLine; + int CByte; + int32 Cycles = CPU.Cycles; + uint8 MemoryByte; + + if (Debug.Dump.Bank != 0 || Debug.Dump.Address != 0) + { + Bank = Debug.Dump.Bank; + Address = Debug.Dump.Address; + } + ErrorCode = GetStartAddress (Line, &Bank, &Address); + for (CLine = 0; CLine != 10; CLine++) + { + sprintf (String, "$%02X:%04X", Bank, Address); + for (CByte = 0; CByte != 16; CByte++) + { + if (Address + CByte == 0x2140 || + Address + CByte == 0x2141 || + Address + CByte == 0x2142 || + Address + CByte == 0x2143 || + Address + CByte == 0x4210) + { + MemoryByte = 0; + } + else + { + MemoryByte = S9xGetByte ((Bank << 16) + Address + CByte); + } + sprintf (String, "%s %02X", String, MemoryByte); + } + sprintf (String, "%s-", String); + for (CByte = 0; CByte != 16; CByte++) + { + if (Address + CByte == 0x2140 || + Address + CByte == 0x2141 || + Address + CByte == 0x2142 || + Address + CByte == 0x2143 || + Address + CByte == 0x4210) + { + MemoryByte = 0; + } + else + { + MemoryByte = S9xGetByte ((Bank << 16) + Address + CByte); + } + if (MemoryByte < 32 || MemoryByte >= 127) + MemoryByte = '?'; + sprintf (String, "%s%c", String, MemoryByte); + } + Address += 16; + DPrint (String); + } + Debug.Dump.Bank = Bank; + Debug.Dump.Address = Address; + CPU.Cycles = Cycles; + } + + if (*Line == 'q') + S9xExit (); + if (*Line == 'W') + WhatsMissing (); + if (*Line == 'w') + WhatsUsed (); + if (Line[0] == 'r') + { +#if 0 + sprintf (String, + "A[%04X] X[%04X] Y[%04X] S[%04X] D[%04X] DB[%02X] P[%02X] F[%s %s %s %s %s %s %s %s / %s]", + Registers.A.W, + Registers.X.W, + Registers.Y.W, + Registers.S.W, + Registers.D.W, + Registers.DB, + Registers.PL, + (Registers.P.W & 128) != 0 ? "N" : "n", + (Registers.P.W & 64) != 0 ? "V" : "v", + (Registers.P.W & 32) != 0 ? "M" : "m", + (Registers.P.W & 16) != 0 ? "X" : "x", + (Registers.P.W & 8) != 0 ? "D" : "d", + (Registers.P.W & 4) != 0 ? "I" : "i", + (Registers.P.W & 2) != 0 ? "Z" : "z", + (Registers.P.W & 1) != 0 ? "C" : "c", + (Registers.P.W & 256) != 0 ? "E" : "e"); + DPrint (String); +#endif + S9xOPrint (String, Bank, Address); + DPrint (String); + } + if (Line[0] == 'u') + { + if (Debug.Unassemble.Bank != 0 || Debug.Unassemble.Address != 0) + { + Bank = Debug.Unassemble.Bank; + Address = Debug.Unassemble.Address; + } + ErrorCode = GetStartAddress (Line, &Bank, &Address); + for (short Counter = 0; Counter != 10; Counter++) + { + Address += S9xOPrint (String, Bank, Address); + DPrint (String); + } + Debug.Unassemble.Bank = Bank; + Debug.Unassemble.Address = Address; + } + DPrint (""); + return; +} +static void PrintWindow (uint8 * a) +{ + for (int i = 0; i < 6; i++) + if (a[i]) + switch (i) + { + case 0: + printf ("Background 0, "); + break; + case 1: + printf ("Background 1, "); + break; + case 2: + printf ("Background 2, "); + break; + case 3: + printf ("Background 3, "); + break; + case 4: + printf ("Objects, "); + break; + case 5: + printf ("Colour window, "); + break; + } +} +static char *ClipFn (int logic) +{ + switch (logic) + { + case CLIP_OR: + return ("OR"); + case CLIP_AND: + return ("AND"); + case CLIP_XOR: + return ("XOR"); + case CLIP_XNOR: + return ("XNOR"); + default: + return ("???"); + } +} + +static void WhatsUsed () +{ + printf ("V-line: %ld, H-Pos: %ld\n", CPU.V_Counter, CPU.Cycles); + printf ("Screen mode: %d, ", PPU.BGMode); + if (PPU.BGMode <= 1 && (Memory.FillRAM [0x2105] & 8)) + printf ("(BG#2 Priority)"); + + printf ("Brightness: %d", PPU.Brightness); + if (Memory.FillRAM[0x2100] & 0x80) + printf (" (screen blanked)"); + printf ("\n"); + if (Memory.FillRAM[0x2133] & 1) + printf ("Interlace, "); + if (Memory.FillRAM[0x2133] & 4) + printf ("240 line visible, "); + if (Memory.FillRAM[0x2133] & 8) + printf ("Pseudo 512 pixels horizontal resolution, "); + if (Memory.FillRAM[0x2133] & 0x40) + printf ("Mode 7 priority per pixel, "); + printf ("\n"); + if (PPU.BGMode == 7 && (Memory.FillRAM[0x211a] & 3)) + printf ("Mode 7 flipping, "); + if (PPU.BGMode == 7) + printf ("Mode 7 screen repeat: %d,", (Memory.FillRAM[0x211a] & 0xc0) >> 6); + if (Memory.FillRAM[0x2130] & 1) + printf ("32K colour mode, "); + if (PPU.BGMode == 7) + { + // Sign extend 13 bit values to 16 bit values... + if (PPU.CentreX & (1 << 12)) + PPU.CentreX |= 0xe000; + if (PPU.CentreY & (1 << 12)) + PPU.CentreY |= 0xe000; + + printf ("\nMatrix A: %.3f, B: %.3f, C: %.3f, D: %.3f, Centre X: %d Y:%d\n", + (double) PPU.MatrixA / 256, (double) PPU.MatrixB / 256, + (double) PPU.MatrixC / 256, (double) PPU.MatrixD / 256, + PPU.CentreX, PPU.CentreY); + } + if ((Memory.FillRAM[0x2106] & 0xf0) && (Memory.FillRAM[0x2106] & 0x0f)) + { + printf ("\nMosaic effect(%d) on ", PPU.Mosaic); + for (int i = 0; i < 4; i++) + if (Memory.FillRAM[0x2106] & (1 << i)) + printf ("BG%d,", i); + printf (","); + } + if (PPU.HVBeamCounterLatched) + printf ("V and H beam pos latched, "); + if (Memory.FillRAM[0x4200] & 0x20) + printf ("V-IRQ enabled at %d\n", PPU.IRQVBeamPos); + if (Memory.FillRAM[0x4200] & 0x10) + printf ("H-IRQ enabled at %d\n", PPU.IRQHBeamPos); + if (Memory.FillRAM[0x4200] & 0x80) + printf ("V-blank NMI enabled\n"); + int i; + for (i = 0; i < 8; i++) + { + if (missing.hdma_this_frame & (1 << i)) + { + printf ("H-DMA %d [%d] 0x%02X%04X->0x21%02X %s %s 0x%02X%04X %s addressing\n", + i, DMA[i].TransferMode, + DMA[i].ABank, DMA[i].AAddress, DMA[i].BAddress, + DMA[i].AAddressDecrement ? "dec" : "inc", + DMA[i].Repeat ? "repeat" : "continue", + DMA[i].IndirectBank, DMA[i].IndirectAddress, + DMA[i].HDMAIndirectAddressing ? "indirect" : "absolute"); + } + } + for (i = 0; i < 8; i++) + { + if (missing.dma_this_frame & (1 << i)) + { + printf ("DMA %d %d 0x%02X%04X->0x21%02X Num: %d %s\n", + i, DMA[i].TransferMode, DMA[i].ABank, DMA[i].AAddress, + DMA[i].BAddress, DMA[i].TransferBytes, + DMA[i].AAddressFixed ? "fixed" : + (DMA[i].AAddressDecrement ? "dec" : "inc")); + } + } + printf ("VRAM write address: 0x%04x(%s), Full Graphic: %d, Address inc: %d\n", + PPU.VMA.Address, + PPU.VMA.High ? "Byte" : "Word", + PPU.VMA.FullGraphicCount, PPU.VMA.Increment); + + for (i = 0; i < 4; i++) + { + printf ("BG%d: VOffset:%d, HOffset:%d, W:%d, H:%d, TS:%d, BA:0x%04x, TA:0x%04X\n", + i, PPU.BG[i].VOffset, PPU.BG[i].HOffset, + (PPU.BG[i].SCSize & 1) * 32 + 32, + (PPU.BG[i].SCSize & 2) * 16 + 32, + PPU.BG[i].BGSize * 8 + 8, + PPU.BG[i].SCBase, + PPU.BG[i].NameBase); + } + char *s = ""; + switch ((Memory.FillRAM [0x2130] & 0xc0) >> 6) + { + case 0: s = "always on"; break; + case 1: s = "inside"; break; + case 2: s = "outside"; break; + case 3: s = "always off"; break; + } + printf ("Main screen (%s): ", s); + for (i = 0; i < 5; i++) + if (Memory.FillRAM[0x212c] & (1 << i)) + switch (i) + { + case 0: + printf ("BG0,"); + break; + case 1: + printf ("BG1,"); + break; + case 2: + printf ("BG2,"); + break; + case 3: + printf ("BG3,"); + break; + case 4: + printf ("OBJ,"); + break; + } + + switch ((Memory.FillRAM [0x2130] & 0x30) >> 4) + { + case 0: s = "always on"; break; + case 1: s = "inside"; break; + case 2: s = "outside"; break; + case 3: s = "always off"; break; + } + + printf ("\nSub-screen (%s): ", s); + for (i = 0; i < 5; i++) + if (Memory.FillRAM[0x212d] & (1 << i)) + switch (i) + { + case 0: + printf ("BG0,"); + break; + case 1: + printf ("BG1,"); + break; + case 2: + printf ("BG2,"); + break; + case 3: + printf ("BG3,"); + break; + case 4: + printf ("OBJ,"); + break; + } + printf ("\n"); + if ((Memory.FillRAM[0x2131] & 0x3f)) + { + if (Memory.FillRAM[0x2131] & 0x80) + { + if (Memory.FillRAM[0x2130] & 0x02) + printf ("Subscreen subtract"); + else + printf ("Fixed colour subtract"); + } + else + { + if (Memory.FillRAM[0x2130] & 0x02) + printf ("Subscreen addition"); + else + printf ("Fixed colour addition"); + } + if (Memory.FillRAM [0x2131] & 0x40) + printf ("(half):"); + else + printf (":"); + + for (i = 0; i < 6; i++) + if (Memory.FillRAM[0x2131] & (1 << i)) + { + switch (i) + { + case 0: + printf ("BG0,"); + break; + case 1: + printf ("BG1,"); + break; + case 2: + printf ("BG2,"); + break; + case 3: + printf ("BG3,"); + break; + case 4: + printf ("OBJ,"); + break; + case 5: + printf ("BACK,"); + break; + } + } + printf ("\n"); + } + printf ("\nWindow 1 (%d, %d, %02x, %02x): ", PPU.Window1Left, + PPU.Window1Right, Memory.FillRAM [0x212e], Memory.FillRAM [0x212f]); + for (i = 0; i < 6; i++) + if (PPU.ClipWindow1Enable [i]) + switch (i) + { + case 0: + printf ("BG0(%s-%s),", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[0])); + break; + case 1: + printf ("BG1(%s-%s),", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[1])); + break; + case 2: + printf ("BG2(%s-%s),", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[2])); + break; + case 3: + printf ("BG3(%s-%s),", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[3])); + break; + case 4: + printf ("OBJ(%s-%s),", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[4])); + break; + case 5: + printf ("COL(%s-%s)", PPU.ClipWindow1Inside [i] ? "I" : "O", + ClipFn (PPU.ClipWindowOverlapLogic[5])); + break; + } + + printf ("\nWindow 2 (%d, %d): ", PPU.Window2Left, + PPU.Window2Right); + for (i = 0; i < 6; i++) + if (PPU.ClipWindow2Enable [i]) + switch (i) + { + case 0: + printf ("BG0(%s),", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + case 1: + printf ("BG1(%s),", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + case 2: + printf ("BG2(%s),", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + case 3: + printf ("BG3(%s),", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + case 4: + printf ("OBJ(%s),", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + case 5: + printf ("COL(%s)", PPU.ClipWindow2Inside [i] ? "I" : "O"); + break; + } + + printf ("\nFixed colour: %02x%02x%02x\n", PPU.FixedColourRed, + PPU.FixedColourGreen, PPU.FixedColourBlue); +} + +static void WhatsMissing () +{ + printf ("Processor: "); + if (missing.emulate6502) + printf ("emulation mode, "); + if (missing.decimal_mode) + printf ("decimal mode,"); + if (missing.mv_8bit_index) + printf ("MVP/MVN with 8bit index registers and XH or YH > 0,"); + if (missing.mv_8bit_acc) + printf ("MVP/MVN with 8bit accumulator > 255"); + printf ("\nScreen modes used:"); + int i; + for (i = 0; i < 8; i++) + if (missing.modes[i]) + printf (" %d,", i); + printf ("\n"); + if (missing.interlace) + printf ("Interlace, "); + if (missing.pseudo_512) + printf ("Pseudo 512 pixels horizontal resolution, "); + if (missing.lines_239) + printf ("240 lines visible,"); + if (missing.sprite_double_height) + printf ("double-hight sprites,"); + printf ("\n"); + if (missing.mode7_fx) + printf ("Mode 7 rotation/scaling, "); + if (missing.matrix_read) + printf ("Mode 7 read matrix registers, "); + if (missing.mode7_flip) + printf ("Mode 7 flipping, "); + if (missing.mode7_bgmode) + printf ("Mode 7 priority per pixel, "); + if (missing.direct) + printf ("Direct 32000 colour mode"); + printf ("\n"); + if (missing.mosaic) + printf ("Mosaic effect, "); + if (missing.subscreen) + printf ("Subscreen enabled, "); + if (missing.subscreen_add) + printf ("Subscreen colour add, "); + if (missing.subscreen_sub) + printf ("Subscreen colour subtract, "); + if (missing.fixed_colour_add) + printf ("Fixed colour add, "); + if (missing.fixed_colour_sub) + printf ("Fixed colour subtract"); + printf ("\n"); + printf ("Window 1 enabled on:"); + PrintWindow (missing.window1); + printf ("\nWindow 2 enabled on:"); + PrintWindow (missing.window2); + printf ("\n"); + if (missing.bg_offset_read) + printf ("BG offset read, "); + if (missing.oam_address_read) + printf ("OAM address read,"); + if (missing.sprite_priority_rotation) + printf ("Sprite priority rotation, "); + if (missing.fast_rom) + printf ("Fast 3.58MHz ROM access enabled, "); + if (missing.matrix_multiply) + printf ("Matrix multiply 16bit by 8bit used"); + printf ("\n"); + if (missing.virq) + printf ("V-position IRQ used at line %d, ", missing.virq_pos); + if (missing.hirq) + printf ("H-position IRQ used at position %d, ", missing.hirq_pos); + printf ("\n"); + if (missing.h_v_latch) + printf ("H and V-Pos latched, "); + if (missing.h_counter_read) + printf ("H-Pos read, "); + if (missing.v_counter_read) + printf ("V-Pos read"); + printf ("\n"); + if (missing.oam_read) + printf ("OAM read, "); + if (missing.vram_read) + printf ("VRAM read, "); + if (missing.cgram_read) + printf ("CG-RAM read, "); + if (missing.wram_read) + printf ("WRAM read, "); + if (missing.dma_read) + printf ("DMA read,"); + if (missing.vram_inc) + printf ("VRAM inc: %d,", missing.vram_inc); + if (missing.vram_full_graphic_inc) + printf ("VRAM full graphic inc: %d,", missing.vram_full_graphic_inc); + printf ("\n"); + for (i = 0; i < 8; i++) + { + if (missing.hdma[i].used) + { + printf ("HDMA %d, 0x%02X%04X->0x21%02X %s ", i, + missing.hdma[i].abus_bank, missing.hdma[i].abus_address, + missing.hdma[i].bbus_address, + missing.hdma[i].indirect_address ? "indirect" : "absolute"); + if (missing.hdma[i].force_table_address_write) + printf ("Forced address write, "); + if (missing.hdma[i].force_table_address_read) + printf ("Current address read, "); + if (missing.hdma[i].line_count_write) + printf ("Line count write, "); + if (missing.hdma[i].line_count_read) + printf ("Line count read"); + printf ("\n"); + } + } + for (i = 0; i < 8; i++) + { + if (missing.dma_channels & (1 << i)) + { + printf ("DMA %d %d 0x%02X%04X->0x21%02X Num: %d %s\n", + i, DMA[i].TransferMode, DMA[i].ABank, DMA[i].AAddress, + DMA[i].BAddress, DMA[i].TransferBytes, + DMA[i].AAddressFixed ? "fixed" : + (DMA[i].AAddressDecrement ? "dec" : "inc")); + } + } + if (missing.unknownppu_read) + printf ("Read from unknown PPU register: $%04X\n", missing.unknownppu_read); + if (missing.unknownppu_write) + printf ("Write to unknown PPU register: $%04X\n", missing.unknownppu_write); + if (missing.unknowncpu_read) + printf ("Read from unknown CPU register: $%04X\n", missing.unknowncpu_read); + if (missing.unknowncpu_write) + printf ("Write to unknown CPU register: $%04X\n", missing.unknowncpu_write); + if (missing.unknowndsp_read) + printf ("Read from unknown DSP register: $%04X\n", missing.unknowndsp_read); + if (missing.unknowndsp_write) + printf ("Write to unknown DSP register: $%04X\n", missing.unknowndsp_write); +} + +void S9xDoDebug () +{ + char Line[513]; + Debug.Dump.Bank = 0; + Debug.Dump.Address = 0; + Debug.Unassemble.Bank = 0; + Debug.Unassemble.Address = 0; + S9xTextMode (); + ProcessDebugCommand ("r"); + while (CPU.Flags & DEBUG_MODE_FLAG) + { + printf ("> "); + fflush (stdout); + fgets (Line, sizeof (Line) - 1, stdin); + Line [strlen (Line) - 1] = 0; + int32 Cycles = CPU.Cycles; + ProcessDebugCommand (Line); + CPU.Cycles = Cycles; + } + if (!(CPU.Flags & SINGLE_STEP_FLAG)) + S9xGraphicsMode (); +} + +void S9xTrace () +{ + if(!trace) + trace=fopen("trace.log", "a"); + char String [512]; + S9xOPrint (String, Registers.PB, Registers.PCw); + fprintf (trace, "%s\n", String); +} + +void S9xSA1Trace () +{ + char String [512]; + S9xSA1OPrint (String, SA1Registers.PB, SA1Registers.PCw); + fprintf (trace2, "%s\n", String); + fflush (trace2); +} + +void S9xTraceMessage (const char *s) +{ + if(s) + { + if (trace) + fprintf (trace, "%s\n", s); + else + if (trace2) + fprintf (trace2, "%s\n", s); + } +} + +extern "C" void TraceSA1 () +{ + SA1.Flags ^= TRACE_FLAG; + if (SA1.Flags & TRACE_FLAG) + { + printf ("SA1 CPU instruction tracing enabled.\n"); + if (trace2 == NULL) + trace2 = fopen ("trace_sa1.log", "wb"); + } + else + { + printf ("SA1 CPU instruction tracing disabled.\n"); + fclose (trace2); + trace2 = NULL; + } +} + +extern "C" void Trace () +{ + CPU.Flags ^= TRACE_FLAG; + if (CPU.Flags & TRACE_FLAG) + { + if (trace == NULL) + trace = fopen ("trace.log", "wb"); + printf ("CPU instruction tracing enabled.\n"); + } + else + { + printf ("CPU instruction tracing disabled.\n"); + fclose (trace); + trace = NULL; + } +} + +#endif + diff --git a/source/snes9x/debug.h b/source/snes9x/debug.h new file mode 100644 index 0000000..3d193c3 --- /dev/null +++ b/source/snes9x/debug.h @@ -0,0 +1,168 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +START_EXTERN_C +void S9xDoDebug (); +void S9xTrace (); +void S9xSA1Trace (); +void S9xTraceMessage (const char *); + +// Structures +struct SBreakPoint{ + bool8 Enabled; + uint8 Bank; + uint16 Address; +}; + +uint8 S9xOPrint( char *Line, uint8 Bank, uint16 Address); +uint8 S9xSA1OPrint( char *Line, uint8 Bank, uint16 Address); + +extern struct SBreakPoint S9xBreakpoint[ 6]; +extern char *S9xMnemonics[256]; +END_EXTERN_C +#endif + diff --git a/source/snes9x/display.h b/source/snes9x/display.h new file mode 100644 index 0000000..9565ab9 --- /dev/null +++ b/source/snes9x/display.h @@ -0,0 +1,204 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +START_EXTERN_C +// Routines the port specific code has to implement +void S9xSetPalette (); +void S9xTextMode (); +void S9xGraphicsMode (); +void S9xLoadConfigFiles(char **argv, int argc); +char *S9xParseArgs (char **argv, int argc); +void S9xParseArg (char **argv, int &index, int argc); +void S9xExtraUsage (); + +void S9xUsage (); +void S9xInitDisplay (int argc, char **argv); +void S9xDeinitDisplay (); +void S9xInitInputDevices (); +void S9xSetTitle (const char *title); +void S9xProcessEvents (bool8 block); +void S9xPutImage (int width, int height); +void S9xParseDisplayArg (char **argv, int &index, int argc); +void S9xExtraDisplayUsage (); +void S9xToggleSoundChannel (int channel); +void S9xSetInfoString (const char *string); +int S9xMinCommandLineArgs (); +void S9xNextController (); +bool8 S9xLoadROMImage (const char *string); +const char *S9xSelectFilename (const char *def, const char *dir, + const char *ext, const char *title); + +const char *S9xChooseFilename (bool8 read_only); +bool8 S9xOpenSnapshotFile (const char *base, bool8 read_only, STREAM *file); +void S9xCloseSnapshotFile (STREAM file); + +const char *S9xBasename (const char *filename); + +int S9xFStrcmp (FILE *, const char *); + +enum s9x_getdirtype { + DEFAULT_DIR, + HOME_DIR, + ROM_DIR, + ROMFILENAME_DIR, + SNAPSHOT_DIR, + SRAM_DIR, + SCREENSHOT_DIR, + SPC_DIR, + PATCH_DIR, + CHEAT_DIR, + PACK_DIR, + BIOS_DIR, + LOG_DIR +}; +const char *S9xGetDirectory (enum s9x_getdirtype dirtype); +const char *S9xGetFilename (const char *extension, enum s9x_getdirtype dirtype); +const char *S9xGetFilenameInc (const char *, enum s9x_getdirtype); +END_EXTERN_C + +#endif + diff --git a/source/snes9x/dma.cpp b/source/snes9x/dma.cpp new file mode 100644 index 0000000..c5df50f --- /dev/null +++ b/source/snes9x/dma.cpp @@ -0,0 +1,1641 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "snes9x.h" + +#include "memmap.h" +#include "ppu.h" +#include "cpuexec.h" +#include "missing.h" +#include "dma.h" +#include "apu.h" +#include "gfx.h" +#include "sa1.h" +#include "spc7110.h" + +#ifdef SDD1_DECOMP +#include "sdd1emu.h" +#endif + +#ifdef SDD1_DECOMP +uint8 buffer[0x10000]; +#endif + +extern int HDMA_ModeByteCounts [8]; +extern uint8 *HDMAMemPointers [8]; + +#if defined(__linux__) || defined(__WIN32__) || defined(__MACOSX__) +static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2) +{ + return (*(uint32 *) p1 - *(uint32 *) p2); +} +#endif + +static inline void S9xTrySyncAPUInDMA (void) +{ +#ifdef SPC700_C + S9xUpdateAPUTimer(); + APU_EXECUTE(); +#endif +} + +/**********************************************************************************************/ +/* S9xDoDMA() */ +/* This function preforms the general dma transfer */ +/**********************************************************************************************/ + +void S9xDoDMA (uint8 Channel) +{ + uint8 Work; + + if (Channel > 7 || CPU.InDMA) + return; + + CPU.InDMA = TRUE; + bool8 in_sa1_dma = FALSE; + uint8 *in_sdd1_dma = NULL; + uint8 *spc7110_dma=NULL; + bool s7_wrap=false; + SDMA *d = &DMA[Channel]; + + + int32 count = d->TransferBytes; + + if (count == 0) + count = 0x10000; + + int inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1); + + if((d->ABank==0x7E || d->ABank==0x7F) && d->BAddress==0x80 && !d->TransferDirection) + { + d->AAddress+= d->TransferBytes; + //does an invalid DMA actually take time? + // I'd say yes, since 'invalid' is probably just the WRAM chip + // not being able to read and write itself at the same time + // And no, PPU.WRAM should not be updated. + CPU.Cycles+=(d->TransferBytes+1)*SLOW_ONE_CYCLE; + S9xTrySyncAPUInDMA(); + +#ifdef DEBUGGER + if (Settings.TraceDMA) + { + sprintf (String, "DMA[%d]: %s Mode: %d 0x%02X%04X->0x21%02X Bytes: %d (%s) V-Line:%ld -- ABORT WRAM Bank%02X->$2180", + Channel, d->TransferDirection ? "read" : "write", + d->TransferMode, d->ABank, d->AAddress, + d->BAddress, d->TransferBytes, + d->AAddressFixed ? "fixed" : + (d->AAddressDecrement ? "dec" : "inc"), + CPU.V_Counter, d->ABank); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + goto update_address; + } + switch (d->BAddress) + { + case 0x18: + case 0x19: + if (IPPU.RenderThisFrame) + FLUSH_REDRAW (); + break; + } + if (Settings.SDD1) + { + if (d->AAddressFixed && Memory.FillRAM [0x4801] > 0) + { + // XXX: Should probably verify that we're DMAing from ROM? And + // somewhere we should make sure we're not running across a mapping + // boundary too. + // Hacky support for pre-decompressed S-DD1 data + inc = !d->AAddressDecrement ? 1 : -1; + uint32 address = (((d->ABank << 16) | d->AAddress) & 0xfffff) << 4; + + address |= Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)]; + +#ifdef SDD1_DECOMP + if(Settings.SDD1Pack) + { + uint8* in_ptr=GetBasePointer(((d->ABank << 16) | d->AAddress)); + if(in_ptr){ + in_ptr+=d->AAddress; + SDD1_decompress(buffer,in_ptr,d->TransferBytes); + } else { + sprintf(String, "S-DD1 DMA from non-block address $%02X:%04X", d->ABank, d->AAddress); + S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String); + } + in_sdd1_dma=buffer; +#ifdef SDD1_VERIFY + void *ptr = bsearch (&address, Memory.SDD1Index, + Memory.SDD1Entries, 12, S9xCompareSDD1IndexEntries); + if(memcmp(buffer, ptr, d->TransferBytes)) + { + uint8 *p = Memory.SDD1LoggedData; + bool8 found = FALSE; + uint8 SDD1Bank = Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)] | 0xf0; + + for (uint32 i = 0; i < Memory.SDD1LoggedDataCount; i++, p += 8) + { + if (*p == d->ABank || + *(p + 1) == (d->AAddress >> 8) && + *(p + 2) == (d->AAddress & 0xff) && + *(p + 3) == (count >> 8) && + *(p + 4) == (count & 0xff) && + *(p + 7) == SDD1Bank) + { + found = TRUE; + } + } + if (!found && Memory.SDD1LoggedDataCount < MEMMAP_MAX_SDD1_LOGGED_ENTRIES) + { + int j=0; + while(ptr[j]==buffer[j]) + j++; + + *p = d->ABank; + *(p + 1) = d->AAddress >> 8; + *(p + 2) = d->AAddress & 0xff; + *(p + 3) = j&0xFF; + *(p + 4) = (j>>8)&0xFF; + *(p + 7) = SDD1Bank; + Memory.SDD1LoggedDataCount += 1; + } + } +#endif + } + + else + { +#endif +#if defined(__linux__) || defined(__WIN32__) || defined(__MACOSX__) + void *ptr = bsearch (&address, Memory.SDD1Index, + Memory.SDD1Entries, 12, S9xCompareSDD1IndexEntries); + if (ptr) + in_sdd1_dma = *(uint32 *) ((uint8 *) ptr + 4) + Memory.SDD1Data; +#else + uint8 *ptr = Memory.SDD1Index; + + for (uint32 e = 0; e < Memory.SDD1Entries; e++, ptr += 12) + { + if (address == *(uint32 *) ptr) + { + in_sdd1_dma = *(uint32 *) (ptr + 4) + Memory.SDD1Data; + break; + } + } +#endif + + if (!in_sdd1_dma) + { + // No matching decompressed data found. Must be some new + // graphics not encountered before. Log it if it hasn't been + // already. + uint8 *p = Memory.SDD1LoggedData; + bool8 found = FALSE; + uint8 SDD1Bank = Memory.FillRAM [0x4804 + ((d->ABank - 0xc0) >> 4)] | 0xf0; + + for (uint32 i = 0; i < Memory.SDD1LoggedDataCount; i++, p += 8) + { + if (*p == d->ABank || + *(p + 1) == (d->AAddress >> 8) && + *(p + 2) == (d->AAddress & 0xff) && + *(p + 3) == (count >> 8) && + *(p + 4) == (count & 0xff) && + *(p + 7) == SDD1Bank) + { + found = TRUE; + break; + } + } + if (!found && Memory.SDD1LoggedDataCount < MEMMAP_MAX_SDD1_LOGGED_ENTRIES) + { + *p = d->ABank; + *(p + 1) = d->AAddress >> 8; + *(p + 2) = d->AAddress & 0xff; + *(p + 3) = count >> 8; + *(p + 4) = count & 0xff; + *(p + 7) = SDD1Bank; + Memory.SDD1LoggedDataCount += 1; + } + } + } +#ifdef SDD1_DECOMP + } +#endif + + Memory.FillRAM [0x4801] = 0; + } + if(Settings.SPC7110&&(d->AAddress==0x4800||d->ABank==0x50)) + { + uint32 i,j; + i=(s7r.reg4805|(s7r.reg4806<<8)); +#ifdef SPC7110_DEBUG + printf("DMA Transfer of %04X bytes from %02X%02X%02X:%02X, offset of %04X, internal bank of %04X, multiplier %02X\n",d->TransferBytes,s7r.reg4803,s7r.reg4802,s7r.reg4801, s7r.reg4804,i, s7r.bank50Internal, s7r.AlignBy); +#endif + i*=s7r.AlignBy; + i+=s7r.bank50Internal; + i%=DECOMP_BUFFER_SIZE; + j=0; + if((i+d->TransferBytes)TransferBytes]; + j=DECOMP_BUFFER_SIZE-i; + memcpy(spc7110_dma, &s7r.bank50[i], j); + memcpy(&spc7110_dma[j],s7r.bank50,d->TransferBytes-j); + s7_wrap=true; + } + int icount=s7r.reg4809|(s7r.reg480A<<8); + icount-=d->TransferBytes; + s7r.reg4809=0x00ff&icount; + s7r.reg480A=(0xff00&icount)>>8; + + s7r.bank50Internal+=d->TransferBytes; + s7r.bank50Internal%=DECOMP_BUFFER_SIZE; + inc=1; + d->AAddress-=count; + } + if (d->BAddress == 0x18 && SA1.in_char_dma && (d->ABank & 0xf0) == 0x40) + { + // Perform packed bitmap to PPU character format conversion on the + // data before transmitting it to V-RAM via-DMA. + int num_chars = 1 << ((Memory.FillRAM [0x2231] >> 2) & 7); + int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 : + (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2; + + int bytes_per_char = 8 * depth; + int bytes_per_line = depth * num_chars; + int char_line_bytes = bytes_per_char * num_chars; + uint32 addr = (d->AAddress / char_line_bytes) * char_line_bytes; + uint8 *base = GetBasePointer ((d->ABank << 16) + addr); + if(!base){ + sprintf(String, "SA-1 DMA from non-block address $%02X:%04X", d->ABank, addr); + S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String); + base=Memory.ROM; + } + base+=addr; + uint8 *buffer = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000]; + uint8 *p = buffer; + uint32 inc = char_line_bytes - (d->AAddress % char_line_bytes); + uint32 char_count = inc / bytes_per_char; + + in_sa1_dma = TRUE; + + //printf ("%08x,", base); fflush (stdout); + //printf ("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n", + //depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes); + int i; + + switch (depth) + { + case 2: + for (i = 0; i < count; i += inc, base += char_line_bytes, + inc = char_line_bytes, char_count = num_chars) + { + uint8 *line = base + (num_chars - char_count) * 2; + for (uint32 j = 0; j < char_count && p - buffer < count; + j++, line += 2) + { + uint8 *q = line; + for (int l = 0; l < 8; l++, q += bytes_per_line) + { + for (int b = 0; b < 2; b++) + { + uint8 r = *(q + b); + *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); + *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1); + *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); + *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1); + } + p += 2; + } + } + } + break; + case 4: + for (i = 0; i < count; i += inc, base += char_line_bytes, + inc = char_line_bytes, char_count = num_chars) + { + uint8 *line = base + (num_chars - char_count) * 4; + for (uint32 j = 0; j < char_count && p - buffer < count; + j++, line += 4) + { + uint8 *q = line; + for (int l = 0; l < 8; l++, q += bytes_per_line) + { + for (int b = 0; b < 4; b++) + { + uint8 r = *(q + b); + *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); + *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); + *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); + *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1); + *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1); + *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1); + } + p += 2; + } + p += 32 - 16; + } + } + break; + case 8: + for (i = 0; i < count; i += inc, base += char_line_bytes, + inc = char_line_bytes, char_count = num_chars) + { + uint8 *line = base + (num_chars - char_count) * 8; + for (uint32 j = 0; j < char_count && p - buffer < count; + j++, line += 8) + { + uint8 *q = line; + for (int l = 0; l < 8; l++, q += bytes_per_line) + { + for (int b = 0; b < 8; b++) + { + uint8 r = *(q + b); + *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); + *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); + *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); + *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1); + *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1); + *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1); + *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1); + } + p += 2; + } + p += 64 - 16; + } + } + break; + } + } + +#ifdef DEBUGGER + if (Settings.TraceDMA) + { + sprintf (String, "DMA[%d]: %s Mode: %d 0x%02X%04X->0x21%02X Bytes: %d (%s) V-Line:%ld", + Channel, d->TransferDirection ? "read" : "write", + d->TransferMode, d->ABank, d->AAddress, + d->BAddress, d->TransferBytes, + d->AAddressFixed ? "fixed" : + (d->AAddressDecrement ? "dec" : "inc"), + CPU.V_Counter); + if (d->BAddress == 0x18 || d->BAddress == 0x19 || d->BAddress == 0x39 || d->BAddress == 0x3a) + sprintf (String, "%s VRAM: %04X (%d,%d) %s", String, + PPU.VMA.Address, + PPU.VMA.Increment, PPU.VMA.FullGraphicCount, + PPU.VMA.High ? "word" : "byte"); + + else + if (d->BAddress == 0x22 || d->BAddress == 0x3b) + + sprintf (String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, + PPU.CGFLIP); + else + if (d->BAddress == 0x04 || d->BAddress == 0x38) + sprintf (String, "%s OBJADDR: %04X", String, PPU.OAMAddr); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + + if (!d->TransferDirection) + { + //reflects extra cycle used by DMA + CPU.Cycles += SLOW_ONE_CYCLE * (count+1); + S9xTrySyncAPUInDMA(); + + uint8 *base = GetBasePointer((d->ABank << 16) + d->AAddress); + uint16 p = d->AAddress; + int rem = count; + int b = 0; + count = d->AAddressFixed ? rem : (d->AAddressDecrement ? ((p&MEMMAP_MASK)+1) : (MEMMAP_BLOCK_SIZE-(p&MEMMAP_MASK))); + bool8 inWRAM_DMA = FALSE; + + if (in_sa1_dma) + { + base = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000]; + p = 0; + count = rem; + } + + if (in_sdd1_dma) + { + base = in_sdd1_dma; + p = 0; + count = rem; + } + + if (spc7110_dma) + { + base = spc7110_dma; + p = 0; + count = rem; + } + + inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) && + (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000))); + + while(1){ + if(count>rem) count=rem; + rem -= count; + if (inc > 0) + d->AAddress += count; + else if (inc < 0) + d->AAddress -= count; + //CPU.InWRAM_DMA = (base>=Memory.RAM && baseTransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6) + { + do + { + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } + else if (d->TransferMode == 1 || d->TransferMode == 5) + { + // This is a variation on Duff's Device. It is legal C/C++, + // see http://www.lysator.liu.se/c/duffs-device.html + switch(b){ + default: + while (count > 1) + { + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + count--; + + case 1: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + CHECK_SOUND(); + count --; + } + } + if (count == 1) + { + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + b = 1; + } else { + b = 0; + } + } + else if (d->TransferMode == 3 || d->TransferMode == 7) + { + switch(b){ + default: + do + { + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 1; + break; + } + + case 1: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 2; + break; + } + + case 2: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 3; + break; + } + + case 3: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + CHECK_SOUND(); + if(--count<=0){ + b = 0; + break; + } + } while (1); + } + } + else if (d->TransferMode == 4) + { + switch(b){ + default: + do + { + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 1; + break; + } + + case 1: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 2; + break; + } + + case 2: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2102 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 3; + break; + } + + case 3: + Work = S9xGetByte((d->ABank << 16) + p); + S9xSetPPU (Work, 0x2103 + d->BAddress); + p += inc; + CHECK_SOUND(); + if (--count <= 0){ + b = 0; + break; + } + } while (1); + } + } + else + { +#ifdef DEBUGGER + // if (Settings.TraceDMA) + { + sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n", + d->TransferMode, Channel); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + } + } else { + // DMA FAST PATH + if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6) + { + switch (d->BAddress) + { + case 0x04: + do + { + Work = *(base + p); + REGISTER_2104(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + break; + case 0x18: +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = TRUE; +#endif + if (!PPU.VMA.FullGraphicCount) + { + do + { + Work = *(base + p); + REGISTER_2118_linear(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } + else + { + do + { + Work = *(base + p); + REGISTER_2118_tile(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } + break; + case 0x19: +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = TRUE; +#endif + if (!PPU.VMA.FullGraphicCount) + { + do + { + Work = *(base + p); + REGISTER_2119_linear(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } + else + { + do + { + Work = *(base + p); + REGISTER_2119_tile(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } + break; + case 0x22: + do + { + Work = *(base + p); + REGISTER_2122(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + break; + case 0x80: + if(!CPU.InWRAM_DMA){ + do + { + Work = *(base + p); + REGISTER_2180(Work); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + } else { + count=0; + } + break; + default: + do + { + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + CHECK_SOUND(); + } while (--count > 0); + break; + } + } + else if (d->TransferMode == 1 || d->TransferMode == 5) + { + if (d->BAddress == 0x18) + { + // Write to V-RAM +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = TRUE; +#endif + if (!PPU.VMA.FullGraphicCount) + { + switch(b){ + default: + while (count > 1) + { + Work = *(base + p); + REGISTER_2118_linear(Work); + p += inc; + count--; + + case 1: + Work = *(base + p); + REGISTER_2119_linear(Work); + p += inc; + CHECK_SOUND(); + count--; + } + } + if (count == 1) + { + Work = *(base + p); + REGISTER_2118_linear(Work); + p += inc; + b = 1; + } else { + b = 0; + } + } + else + { + switch(b){ + default: + while (count > 1) + { + Work = *(base + p); + REGISTER_2118_tile(Work); + p += inc; + count--; + + case 1: + Work = *(base + p); + REGISTER_2119_tile(Work); + p += inc; + CHECK_SOUND(); + count--; + } + } + if (count == 1) + { + Work = *(base + p); + REGISTER_2118_tile(Work); + p += inc; + b = 1; + } else { + b = 0; + } + } + } + else + { + // DMA mode 1 general case + switch(b){ + default: + while (count > 1) + { + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + count--; + + case 1: + Work = *(base + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + CHECK_SOUND(); + count --; + } + } + if (count == 1) + { + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + b = 1; + } else { + b = 0; + } + } + } + else if (d->TransferMode == 3 || d->TransferMode == 7) + { + switch(b){ + default: + do + { + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 1; + break; + } + + case 1: + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 2; + break; + } + + case 2: + Work = *(base + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 3; + break; + } + + case 3: + Work = *(base + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + CHECK_SOUND(); + if(--count<=0){ + b = 0; + break; + } + } while (1); + } + } + else if (d->TransferMode == 4) + { + switch(b){ + default: + do + { + Work = *(base + p); + S9xSetPPU (Work, 0x2100 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 1; + break; + } + + case 1: + Work = *(base + p); + S9xSetPPU (Work, 0x2101 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 2; + break; + } + + case 2: + Work = *(base + p); + S9xSetPPU (Work, 0x2102 + d->BAddress); + p += inc; + if (--count <= 0){ + b = 3; + break; + } + + case 3: + Work = *(base + p); + S9xSetPPU (Work, 0x2103 + d->BAddress); + p += inc; + CHECK_SOUND(); + if (--count <= 0){ + b = 0; + break; + } + } while (1); + } + } + else + { +#ifdef DEBUGGER + // if (Settings.TraceDMA) + { + sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n", + d->TransferMode, Channel); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + } + } + if(rem<=0) break; + base = GetBasePointer((d->ABank << 16) + d->AAddress); + count=MEMMAP_BLOCK_SIZE; + inWRAM_DMA = ((!in_sa1_dma && !in_sdd1_dma && !spc7110_dma) && + (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000))); + } + } + else + { + if(d->BAddress>0x80-4 && d->BAddress<=0x83 && !(d->ABank&0x40)){ + // REVERSE-DMA REALLY-SLOW PATH + do + { + switch (d->TransferMode) + { + case 0: + case 2: + case 6: + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + --count; + break; + + case 1: + case 5: + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + case 3: + case 7: + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + case 4: + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2102 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + CPU.InWRAM_DMA = (d->AAddress<0x2000); + Work = S9xGetPPU (0x2103 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + default: +#ifdef DEBUGGER + if (1) //Settings.TraceDMA) + { + sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n", + d->TransferMode, Channel); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + count = 0; + break; + } + CHECK_SOUND(); + } while (count); + } else { + // REVERSE-DMA FASTER PATH + CPU.InWRAM_DMA = (d->ABank==0x7e || d->ABank==0x7f); + do + { + switch (d->TransferMode) + { + case 0: + case 2: + case 6: + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + --count; + break; + + case 1: + case 5: + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + case 3: + case 7: + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + case 4: + Work = S9xGetPPU (0x2100 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2101 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2102 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + if (!--count) + break; + + Work = S9xGetPPU (0x2103 + d->BAddress); + S9xSetByte (Work, (d->ABank << 16) + d->AAddress); + d->AAddress += inc; + count--; + break; + + default: +#ifdef DEBUGGER + if (1) //Settings.TraceDMA) + { + sprintf (String, "Unknown DMA transfer mode: %d on channel %d\n", + d->TransferMode, Channel); + S9xMessage (S9X_TRACE, S9X_DMA_TRACE, String); + } +#endif + count = 0; + break; + } + CHECK_SOUND(); + } while(count); + } + } + + while (CPU.Cycles >= CPU.NextEvent) + S9xDoHEventProcessing (); + if ((CPU.Cycles >= Timings.WRAMRefreshPos) && (CPU.Cycles < (Timings.WRAMRefreshPos + SNES_WRAM_REFRESH_CYCLES))) + { + int32 mc = Timings.WRAMRefreshPos + SNES_WRAM_REFRESH_CYCLES - CPU.Cycles; + S9xCheckMissingHTimerPositionRange(CPU.Cycles, mc); + CPU.Cycles += mc; + } + + S9xTrySyncAPUInDMA(); + + if(Settings.SPC7110&&spc7110_dma) + { + if(spc7110_dma&&s7_wrap) + delete [] spc7110_dma; + } + +update_address: + d->TransferBytes = 0; + + CPU.InDMA = CPU.InWRAM_DMA = FALSE; +} + +static inline bool8 HDMAReadLineCount(int d){ + //remember, InDMA is set. + //Get/Set incur no charges! + uint8 line = S9xGetByte ((DMA[d].ABank << 16) + DMA[d].Address); + CPU.Cycles+=SLOW_ONE_CYCLE; + if(!line){ + DMA[d].Repeat = FALSE; + DMA[d].LineCount = 128; + if(DMA[d].HDMAIndirectAddressing){ + CPU.Cycles+=SLOW_ONE_CYCLE; + DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address); + DMA[d].Address++; + } + DMA[d].Address++; + HDMAMemPointers[d] = NULL; + return FALSE; + } else if (line == 0x80) { + DMA[d].Repeat = TRUE; + DMA[d].LineCount = 128; + } else { + DMA[d].Repeat = !(line & 0x80); + DMA[d].LineCount = line & 0x7f; + } + + DMA[d].Address++; + DMA[d].DoTransfer = TRUE; + if (DMA[d].HDMAIndirectAddressing) { + //again, no cycle charges while InDMA is set! + CPU.Cycles+=SLOW_ONE_CYCLE<<1; + DMA[d].IndirectAddress = S9xGetWord ((DMA[d].ABank << 16) + DMA[d].Address); + DMA[d].Address += 2; + HDMAMemPointers [d] = S9xGetMemPointer ((DMA[d].IndirectBank << 16) + DMA[d].IndirectAddress); + } else { + HDMAMemPointers [d] = S9xGetMemPointer ((DMA[d].ABank << 16) + DMA[d].Address); + } + return TRUE; +} + +void S9xStartHDMA () { + if (Settings.DisableHDMA) + IPPU.HDMA = 0; + else + missing.hdma_this_frame = IPPU.HDMA = Memory.FillRAM [0x420c]; + + IPPU.HDMAEnded = 0; + CPU.InDMA = TRUE; + CPU.InWRAM_DMA = FALSE; + + // XXX: Not quite right... + if(IPPU.HDMA!=0) CPU.Cycles+=18; + + for (uint8 i = 0; i < 8; i++) + { + if (IPPU.HDMA & (1 << i)) + { + DMA [i].Address = DMA[i].AAddress; + // Disable H-DMA'ing into V-RAM (register 2118) for Hook + /* XXX: instead of DMA[i].BAddress == 0x18, make S9xSetPPU fail + * XXX: writes to $2118/9 when appropriate (leave the + * !HDMAReadLineCount(i) test though) + */ + if (!HDMAReadLineCount(i) || DMA[i].BAddress == 0x18) { + IPPU.HDMA &= ~(1<HDMAIndirectAddressing) { + ShiftedIBank = (p->IndirectBank << 16); + IAddr = p->IndirectAddress; + } else { + ShiftedIBank = (p->ABank << 16); + IAddr = p->Address; + } + if (!HDMAMemPointers [d]) { + HDMAMemPointers [d] = S9xGetMemPointer (ShiftedIBank + IAddr); + } + + if (p->DoTransfer) { + // XXX: Hack for Uniracers, because we don't understand + // OAM Address Invalidation + if (p->BAddress == 0x04){ + if(SNESGameFixes.Uniracers){ + PPU.OAMAddr = 0x10c; + PPU.OAMFlip=0; + } + } + +#ifdef DEBUGGER + if (Settings.TraceSoundDSP && p->DoTransfer && + p->BAddress >= 0x40 && p->BAddress <= 0x43) + S9xTraceSoundDSP ("Spooling data!!!\n"); + if (Settings.TraceHDMA && p->DoTransfer) + { + sprintf (String, "H-DMA[%d] %s (%d) 0x%06X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X", + p-DMA, p->TransferDirection? "read" : "write", + p->TransferMode, ShiftedIBank+IAddr, p->BAddress, + p->HDMAIndirectAddressing ? "ind" : "abs", + p->LineCount, + p->Repeat ? "yes" : "no ", CPU.V_Counter, + p->ABank, p->Address); + S9xMessage (S9X_TRACE, S9X_HDMA_TRACE, String); + } +#endif + + if (!p->TransferDirection) { + if((IAddr&MEMMAP_MASK)+HDMA_ModeByteCounts[p->TransferMode]>=MEMMAP_BLOCK_SIZE){ + // HDMA REALLY-SLOW PATH + HDMAMemPointers[d]=NULL; +#define DOBYTE(Addr, RegOff) \ + CPU.InWRAM_DMA = (ShiftedIBank==0x7e0000 || ShiftedIBank==0x7f0000 || (!(ShiftedIBank&0x400000) && ((uint16)(Addr))<0x2000)); \ + S9xSetPPU (S9xGetByte(ShiftedIBank + ((uint16)(Addr))), 0x2100 + p->BAddress + RegOff); + switch (p->TransferMode) { + case 0: + CPU.Cycles += SLOW_ONE_CYCLE; + DOBYTE(IAddr, 0); + break; + case 5: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + DOBYTE(IAddr+2, 0); + DOBYTE(IAddr+3, 1); + break; + case 1: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + break; + case 2: + case 6: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 0); + break; + case 3: + case 7: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 0); + DOBYTE(IAddr+2, 1); + DOBYTE(IAddr+3, 1); + break; + case 4: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + DOBYTE(IAddr+2, 2); + DOBYTE(IAddr+3, 3); + break; + } +#undef DOBYTE + } else { + CPU.InWRAM_DMA = (ShiftedIBank==0x7e0000 || ShiftedIBank==0x7f0000 || (!(ShiftedIBank&0x400000) && IAddr<0x2000)); + if(!HDMAMemPointers[d]){ + // HDMA SLOW PATH + uint32 Addr = ShiftedIBank + IAddr; + switch (p->TransferMode) { + case 0: + CPU.Cycles += SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr), 0x2100 + p->BAddress); + break; + case 5: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr+0), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+1), 0x2101 + p->BAddress); + Addr+=2; + /* fall through */ + case 1: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr+0), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+1), 0x2101 + p->BAddress); + break; + case 2: + case 6: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr+0), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+1), 0x2100 + p->BAddress); + break; + case 3: + case 7: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr+0), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+1), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+2), 0x2101 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+3), 0x2101 + p->BAddress); + break; + case 4: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + S9xSetPPU (S9xGetByte(Addr+0), 0x2100 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+1), 0x2101 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+2), 0x2102 + p->BAddress); + S9xSetPPU (S9xGetByte(Addr+3), 0x2103 + p->BAddress); + break; + } + } else { + // HDMA FAST PATH + switch (p->TransferMode) { + case 0: + CPU.Cycles += SLOW_ONE_CYCLE; + S9xSetPPU (*HDMAMemPointers [d]++, 0x2100 + p->BAddress); + break; + case 5: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress); + HDMAMemPointers [d] += 2; + /* fall through */ + case 1: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress); + HDMAMemPointers [d] += 2; + break; + case 2: + case 6: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress); + HDMAMemPointers [d] += 2; + break; + case 3: + case 7: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2101 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2101 + p->BAddress); + HDMAMemPointers [d] += 4; + break; + case 4: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + S9xSetPPU (*(HDMAMemPointers [d] + 0), 0x2100 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 1), 0x2101 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 2), 0x2102 + p->BAddress); + S9xSetPPU (*(HDMAMemPointers [d] + 3), 0x2103 + p->BAddress); + HDMAMemPointers [d] += 4; + break; + } + } + } + } else { + // REVERSE HDMA REALLY-SLOW PATH + // anomie says: Since this is apparently never used + // (otherwise we would have noticed before now), let's not + // bother with faster paths. + HDMAMemPointers[d]=NULL; +#define DOBYTE(Addr, RegOff) \ + CPU.InWRAM_DMA = (ShiftedIBank==0x7e0000 || ShiftedIBank==0x7f0000 || (!(ShiftedIBank&0x400000) && ((uint16)(Addr))<0x2000)); \ + S9xSetByte (S9xGetPPU(0x2100 + p->BAddress + RegOff), ShiftedIBank + ((uint16)(Addr))); + switch (p->TransferMode) { + case 0: + CPU.Cycles += SLOW_ONE_CYCLE; + DOBYTE(IAddr, 0); + break; + case 5: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + DOBYTE(IAddr+2, 0); + DOBYTE(IAddr+3, 1); + break; + case 1: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + break; + case 2: + case 6: + CPU.Cycles += 2*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 0); + break; + case 3: + case 7: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 0); + DOBYTE(IAddr+2, 1); + DOBYTE(IAddr+3, 1); + break; + case 4: + CPU.Cycles += 4*SLOW_ONE_CYCLE; + DOBYTE(IAddr+0, 0); + DOBYTE(IAddr+1, 1); + DOBYTE(IAddr+2, 2); + DOBYTE(IAddr+3, 3); + break; + } +#undef DOBYTE + } + if (p->HDMAIndirectAddressing){ + p->IndirectAddress += HDMA_ModeByteCounts [p->TransferMode]; + } else { + p->Address += HDMA_ModeByteCounts [p->TransferMode]; + } + } + + p->DoTransfer = !p->Repeat; + if (!--p->LineCount) { + if (!HDMAReadLineCount(d)) { + byte &= ~mask; + IPPU.HDMAEnded |= mask; + p->DoTransfer = FALSE; + continue; + } + } else { + CPU.Cycles += SLOW_ONE_CYCLE; + } + + S9xTrySyncAPUInDMA(); + } + } + CPU.InDMA=CPU.InWRAM_DMA=FALSE; + + return (byte); +} + +void S9xResetDMA () { + int d; + for (d = 0; d < 8; d++) { + DMA[d].TransferDirection = FALSE; + DMA[d].HDMAIndirectAddressing = FALSE; + DMA[d].AAddressFixed = TRUE; + DMA[d].AAddressDecrement = FALSE; + DMA[d].TransferMode = 7; + DMA[d].BAddress = 0xff; + DMA[d].AAddress = 0xffff; + DMA[d].ABank = 0xff; + DMA[d].DMACount_Or_HDMAIndirectAddress = 0xffff; + DMA[d].IndirectBank = 0xff; + DMA[d].Address = 0xffff; + DMA[d].Repeat = FALSE; + DMA[d].LineCount = 0x7f; + DMA[d].UnknownByte = 0xff; + DMA[d].DoTransfer = FALSE; + } +} diff --git a/source/snes9x/dma.h b/source/snes9x/dma.h new file mode 100644 index 0000000..147a5ad --- /dev/null +++ b/source/snes9x/dma.h @@ -0,0 +1,156 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _DMA_H_ +#define _DMA_H_ + +START_EXTERN_C +void S9xResetDMA (); +uint8 S9xDoHDMA (uint8); +void S9xStartHDMA (); +void S9xDoDMA (uint8); +END_EXTERN_C + +#endif + diff --git a/source/snes9x/dsp1.cpp b/source/snes9x/dsp1.cpp new file mode 100644 index 0000000..8a840f0 --- /dev/null +++ b/source/snes9x/dsp1.cpp @@ -0,0 +1,1036 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "snes9x.h" +#include "dsp1.h" +#include "missing.h" +#include "memmap.h" +#include + +#include "dsp1emu.c.inc" +#include "dsp2emu.c.inc" +#include "dsp3emu.c.inc" +#include "dsp4emu.c.inc" + +void (*SetDSP)(uint8, uint16)=&DSP1SetByte; +uint8 (*GetDSP)(uint16)=&DSP1GetByte; + +void S9xInitDSP1 () +{ + static bool8 init = FALSE; + + if (!init) + { + InitDSP (); + init = TRUE; + } +} + +void S9xResetDSP1 () +{ + S9xInitDSP1 (); + + DSP1.waiting4command = TRUE; + DSP1.in_count = 0; + DSP1.out_count = 0; + DSP1.in_index = 0; + DSP1.out_index = 0; + DSP1.first_parameter = TRUE; + + DSP4.waiting4command = TRUE; + //printf("DSP-4 Reset\n"); +} + +uint8 S9xGetDSP (uint16 address) +{ + uint8 t; + +#ifdef DEBUGGER + if (Settings.TraceDSP) + { + sprintf (String, "DSP read: 0x%04X", address); + S9xMessage (S9X_TRACE, S9X_TRACE_DSP1, String); + } +#endif + + t=(*GetDSP)(address); + //DSP1GetByte(address); + return (t); +} + +void S9xSetDSP (uint8 byte, uint16 address) +{ +#ifdef DEBUGGER + missing.unknowndsp_write = address; + if (Settings.TraceDSP) + { + sprintf (String, "DSP write: 0x%04X=0x%02X", address, byte); + S9xMessage (S9X_TRACE, S9X_TRACE_DSP1, String); + } +#endif + (*SetDSP)(byte, address); + //DSP1SetByte(byte, address); +} + +void DSP1SetByte(uint8 byte, uint16 address) +{ + if( (address & 0xf000) == 0x6000 || (address & 0x7fff) < 0x4000 ) + { +// if ((address & 1) == 0) +// { + if((DSP1.command==0x0A||DSP1.command==0x1A)&&DSP1.out_count!=0) + { + DSP1.out_count--; + DSP1.out_index++; + return; + } + else if (DSP1.waiting4command) + { + DSP1.command = byte; + DSP1.in_index = 0; + DSP1.waiting4command = FALSE; + DSP1.first_parameter = TRUE; +// printf("Op%02X\n",byte); + // Mario Kart uses 0x00, 0x02, 0x06, 0x0c, 0x28, 0x0a + switch (byte) + { + case 0x00: DSP1.in_count = 2; break; + case 0x30: + case 0x10: DSP1.in_count = 2; break; + case 0x20: DSP1.in_count = 2; break; + case 0x24: + case 0x04: DSP1.in_count = 2; break; + case 0x08: DSP1.in_count = 3; break; + case 0x18: DSP1.in_count = 4; break; + case 0x28: DSP1.in_count = 3; break; + case 0x38: DSP1.in_count = 4; break; + case 0x2c: + case 0x0c: DSP1.in_count = 3; break; + case 0x3c: + case 0x1c: DSP1.in_count = 6; break; + case 0x32: + case 0x22: + case 0x12: + case 0x02: DSP1.in_count = 7; break; + case 0x0a: DSP1.in_count = 1; break; + case 0x3a: + case 0x2a: + case 0x1a: + DSP1. command =0x1a; + DSP1.in_count = 1; break; + case 0x16: + case 0x26: + case 0x36: + case 0x06: DSP1.in_count = 3; break; + case 0x1e: + case 0x2e: + case 0x3e: + case 0x0e: DSP1.in_count = 2; break; + case 0x05: + case 0x35: + case 0x31: + case 0x01: DSP1.in_count = 4; break; + case 0x15: + case 0x11: DSP1.in_count = 4; break; + case 0x25: + case 0x21: DSP1.in_count = 4; break; + case 0x09: + case 0x39: + case 0x3d: + case 0x0d: DSP1.in_count = 3; break; + case 0x19: + case 0x1d: DSP1.in_count = 3; break; + case 0x29: + case 0x2d: DSP1.in_count = 3; break; + case 0x33: + case 0x03: DSP1.in_count = 3; break; + case 0x13: DSP1.in_count = 3; break; + case 0x23: DSP1.in_count = 3; break; + case 0x3b: + case 0x0b: DSP1.in_count = 3; break; + case 0x1b: DSP1.in_count = 3; break; + case 0x2b: DSP1.in_count = 3; break; + case 0x34: + case 0x14: DSP1.in_count = 6; break; + case 0x07: + case 0x0f: DSP1.in_count = 1; break; + case 0x27: + case 0x2F: DSP1.in_count=1; break; + case 0x17: + case 0x37: + case 0x3F: + DSP1.command=0x1f; + case 0x1f: DSP1.in_count = 1; break; + // case 0x80: DSP1.in_count = 2; break; + default: + //printf("Op%02X\n",byte); + case 0x80: + DSP1.in_count = 0; + DSP1.waiting4command = TRUE; + DSP1.first_parameter = TRUE; + break; + } + DSP1.in_count<<=1; + } + else + { + DSP1.parameters [DSP1.in_index] = byte; + DSP1.first_parameter = FALSE; + DSP1.in_index++; + } + + if (DSP1.waiting4command || + (DSP1.first_parameter && byte == 0x80)) + { + DSP1.waiting4command = TRUE; + DSP1.first_parameter = FALSE; + } + else if(DSP1.first_parameter && (DSP1.in_count != 0 || (DSP1.in_count==0&&DSP1.in_index==0))) + { + } +// else if (DSP1.first_parameter) +// { +// } + else + { + if (DSP1.in_count) + { + //DSP1.parameters [DSP1.in_index] |= (byte << 8); + if (--DSP1.in_count == 0) + { + // Actually execute the command + DSP1.waiting4command = TRUE; + DSP1.out_index = 0; + switch (DSP1.command) + { + case 0x1f: + DSP1.out_count=2048; + break; + case 0x00: // Multiple + Op00Multiplicand = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op00Multiplier = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + + DSPOp00 (); + + DSP1.out_count = 2; + DSP1.output [0] = Op00Result&0xFF; + DSP1.output [1] = (Op00Result>>8)&0xFF; + break; + + case 0x20: // Multiple + Op20Multiplicand = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op20Multiplier = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + + DSPOp20 (); + + DSP1.out_count = 2; + DSP1.output [0] = Op20Result&0xFF; + DSP1.output [1] = (Op20Result>>8)&0xFF; + break; + + case 0x30: + case 0x10: // Inverse + Op10Coefficient = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op10Exponent = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + + DSPOp10 (); + + DSP1.out_count = 4; + DSP1.output [0] = (uint8) (((int16) Op10CoefficientR)&0xFF); + DSP1.output [1] = (uint8) ((((int16) Op10CoefficientR)>>8)&0xFF); + DSP1.output [2] = (uint8) (((int16) Op10ExponentR)&0xff); + DSP1.output [3] = (uint8) ((((int16) Op10ExponentR)>>8)&0xff); + break; + + case 0x24: + case 0x04: // Sin and Cos of angle + Op04Angle = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op04Radius = (uint16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + + DSPOp04 (); + + DSP1.out_count = 4; + DSP1.output [0] = (uint8) (Op04Sin&0xFF); + DSP1.output [1] = (uint8) ((Op04Sin>>8)&0xFF); + DSP1.output [2] = (uint8) (Op04Cos&0xFF); + DSP1.output [3] = (uint8) ((Op04Cos>>8)&0xFF); + break; + + case 0x08: // Radius + Op08X = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op08Y = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op08Z = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp08 (); + + DSP1.out_count = 4; + DSP1.output [0] = (uint8) (((int16) Op08Ll)&0xFF); + DSP1.output [1] = (uint8) ((((int16) Op08Ll)>>8)&0xFF); + DSP1.output [2] = (uint8) (((int16) Op08Lh)&0xFF); + DSP1.output [3] = (uint8) ((((int16) Op08Lh)>>8)&0xFF); + break; + + case 0x18: // Range + + Op18X = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op18Y = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op18Z = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op18R = (int16) (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + + DSPOp18 (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op18D&0xFF); + DSP1.output [1] = (uint8) ((Op18D>>8)&0xFF); + break; + + case 0x38: // Range + + Op38X = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op38Y = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op38Z = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op38R = (int16) (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + + DSPOp38 (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op38D&0xFF); + DSP1.output [1] = (uint8) ((Op38D>>8)&0xFF); + break; + + case 0x28: // Distance (vector length) + Op28X = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op28Y = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op28Z = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp28 (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op28R&0xFF); + DSP1.output [1] = (uint8) ((Op28R>>8)&0xFF); + break; + + case 0x2c: + case 0x0c: // Rotate (2D rotate) + Op0CA = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op0CX1 = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op0CY1 = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp0C (); + + DSP1.out_count = 4; + DSP1.output [0] = (uint8) (Op0CX2&0xFF); + DSP1.output [1] = (uint8) ((Op0CX2>>8)&0xFF); + DSP1.output [2] = (uint8) (Op0CY2&0xFF); + DSP1.output [3] = (uint8) ((Op0CY2>>8)&0xFF); + break; + + case 0x3c: + case 0x1c: // Polar (3D rotate) + Op1CZ = (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + //MK: reversed X and Y on neviksti and John's advice. + Op1CY = (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op1CX = (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op1CXBR = (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + Op1CYBR = (DSP1.parameters [8]|(DSP1.parameters[9]<<8)); + Op1CZBR = (DSP1.parameters [10]|(DSP1.parameters[11]<<8)); + + DSPOp1C (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op1CXAR&0xFF); + DSP1.output [1] = (uint8) ((Op1CXAR>>8)&0xFF); + DSP1.output [2] = (uint8) (Op1CYAR&0xFF); + DSP1.output [3] = (uint8) ((Op1CYAR>>8)&0xFF); + DSP1.output [4] = (uint8) (Op1CZAR&0xFF); + DSP1.output [5] = (uint8) ((Op1CZAR>>8)&0xFF); + break; + + case 0x32: + case 0x22: + case 0x12: + case 0x02: // Parameter (Projection) + Op02FX = (short)(DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op02FY = (short)(DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op02FZ = (short)(DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op02LFE = (short)(DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + Op02LES = (short)(DSP1.parameters [8]|(DSP1.parameters[9]<<8)); + Op02AAS = (unsigned short)(DSP1.parameters [10]|(DSP1.parameters[11]<<8)); + Op02AZS = (unsigned short)(DSP1.parameters [12]|(DSP1.parameters[13]<<8)); + + DSPOp02 (); + + DSP1.out_count = 8; + DSP1.output [0] = (uint8) (Op02VOF&0xFF); + DSP1.output [1] = (uint8) ((Op02VOF>>8)&0xFF); + DSP1.output [2] = (uint8) (Op02VVA&0xFF); + DSP1.output [3] = (uint8) ((Op02VVA>>8)&0xFF); + DSP1.output [4] = (uint8) (Op02CX&0xFF); + DSP1.output [5] = (uint8) ((Op02CX>>8)&0xFF); + DSP1.output [6] = (uint8) (Op02CY&0xFF); + DSP1.output [7] = (uint8) ((Op02CY>>8)&0xFF); + break; + + case 0x3a: //1a Mirror + case 0x2a: //1a Mirror + case 0x1a: // Raster mode 7 matrix data + case 0x0a: + Op0AVS = (short)(DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + + DSPOp0A (); + + DSP1.out_count = 8; + DSP1.output [0] = (uint8) (Op0AA&0xFF); + DSP1.output [2] = (uint8) (Op0AB&0xFF); + DSP1.output [4] = (uint8) (Op0AC&0xFF); + DSP1.output [6] = (uint8) (Op0AD&0xFF); + DSP1.output [1] = (uint8) ((Op0AA>>8)&0xFF); + DSP1.output [3] = (uint8) ((Op0AB>>8)&0xFF); + DSP1.output [5] = (uint8) ((Op0AC>>8)&0xFF); + DSP1.output [7] = (uint8) ((Op0AD>>8)&0xFF); + DSP1.in_index=0; + break; + + case 0x16: + case 0x26: + case 0x36: + case 0x06: // Project object + Op06X = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op06Y = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op06Z = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp06 (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op06H&0xff); + DSP1.output [1] = (uint8) ((Op06H>>8)&0xFF); + DSP1.output [2] = (uint8) (Op06V&0xFF); + DSP1.output [3] = (uint8) ((Op06V>>8)&0xFF); + DSP1.output [4] = (uint8) (Op06M&0xFF); + DSP1.output [5] = (uint8) ((Op06M>>8)&0xFF); + break; + + case 0x1e: + case 0x2e: + case 0x3e: + case 0x0e: // Target + Op0EH = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op0EV = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + + DSPOp0E (); + + DSP1.out_count = 4; + DSP1.output [0] = (uint8) (Op0EX&0xFF); + DSP1.output [1] = (uint8) ((Op0EX>>8)&0xFF); + DSP1.output [2] = (uint8) (Op0EY&0xFF); + DSP1.output [3] = (uint8) ((Op0EY>>8)&0xFF); + break; + + // Extra commands used by Pilot Wings + case 0x05: + case 0x35: + case 0x31: + case 0x01: // Set attitude matrix A + Op01m = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op01Zr = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op01Yr = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op01Xr = (int16) (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + + DSPOp01 (); + break; + + case 0x15: + case 0x11: // Set attitude matrix B + Op11m = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op11Zr = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op11Yr = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op11Xr = (int16) (DSP1.parameters [7]|(DSP1.parameters[7]<<8)); + + DSPOp11 (); + break; + + case 0x25: + case 0x21: // Set attitude matrix C + Op21m = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op21Zr = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op21Yr = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op21Xr = (int16) (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + + DSPOp21 (); + break; + + case 0x09: + case 0x39: + case 0x3d: + case 0x0d: // Objective matrix A + Op0DX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op0DY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op0DZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp0D (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op0DF&0xFF); + DSP1.output [1] = (uint8) ((Op0DF>>8)&0xFF); + DSP1.output [2] = (uint8) (Op0DL&0xFF); + DSP1.output [3] = (uint8) ((Op0DL>>8)&0xFF); + DSP1.output [4] = (uint8) (Op0DU&0xFF); + DSP1.output [5] = (uint8) ((Op0DU>>8)&0xFF); + break; + + case 0x19: + case 0x1d: // Objective matrix B + Op1DX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op1DY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op1DZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp1D (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op1DF&0xFF); + DSP1.output [1] = (uint8) ((Op1DF>>8)&0xFF); + DSP1.output [2] = (uint8) (Op1DL&0xFF); + DSP1.output [3] = (uint8) ((Op1DL>>8)&0xFF); + DSP1.output [4] = (uint8) (Op1DU&0xFF); + DSP1.output [5] = (uint8) ((Op1DU>>8)&0xFF); + break; + + case 0x29: + case 0x2d: // Objective matrix C + Op2DX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op2DY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op2DZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp2D (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op2DF&0xFF); + DSP1.output [1] = (uint8) ((Op2DF>>8)&0xFF); + DSP1.output [2] = (uint8) (Op2DL&0xFF); + DSP1.output [3] = (uint8) ((Op2DL>>8)&0xFF); + DSP1.output [4] = (uint8) (Op2DU&0xFF); + DSP1.output [5] = (uint8) ((Op2DU>>8)&0xFF); + break; + + case 0x33: + case 0x03: // Subjective matrix A + Op03F = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op03L = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op03U = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp03 (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op03X&0xFF); + DSP1.output [1] = (uint8) ((Op03X>>8)&0xFF); + DSP1.output [2] = (uint8) (Op03Y&0xFF); + DSP1.output [3] = (uint8) ((Op03Y>>8)&0xFF); + DSP1.output [4] = (uint8) (Op03Z&0xFF); + DSP1.output [5] = (uint8) ((Op03Z>>8)&0xFF); + break; + + case 0x13: // Subjective matrix B + Op13F = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op13L = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op13U = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp13 (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op13X&0xFF); + DSP1.output [1] = (uint8) ((Op13X>>8)&0xFF); + DSP1.output [2] = (uint8) (Op13Y&0xFF); + DSP1.output [3] = (uint8) ((Op13Y>>8)&0xFF); + DSP1.output [4] = (uint8) (Op13Z&0xFF); + DSP1.output [5] = (uint8) ((Op13Z>>8)&0xFF); + break; + + case 0x23: // Subjective matrix C + Op23F = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op23L = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op23U = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp23 (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op23X&0xFF); + DSP1.output [1] = (uint8) ((Op23X>>8)&0xFF); + DSP1.output [2] = (uint8) (Op23Y&0xFF); + DSP1.output [3] = (uint8) ((Op23Y>>8)&0xFF); + DSP1.output [4] = (uint8) (Op23Z&0xFF); + DSP1.output [5] = (uint8) ((Op23Z>>8)&0xFF); + break; + + case 0x3b: + case 0x0b: + Op0BX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op0BY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op0BZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp0B (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op0BS&0xFF); + DSP1.output [1] = (uint8) ((Op0BS>>8)&0xFF); + break; + + case 0x1b: + Op1BX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op1BY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op1BZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp1B (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op1BS&0xFF); + DSP1.output [1] = (uint8) ((Op1BS>>8)&0xFF); + break; + + case 0x2b: + Op2BX = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op2BY = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op2BZ = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + + DSPOp2B (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8) (Op2BS&0xFF); + DSP1.output [1] = (uint8) ((Op2BS>>8)&0xFF); + break; + + case 0x34: + case 0x14: + Op14Zr = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + Op14Xr = (int16) (DSP1.parameters [2]|(DSP1.parameters[3]<<8)); + Op14Yr = (int16) (DSP1.parameters [4]|(DSP1.parameters[5]<<8)); + Op14U = (int16) (DSP1.parameters [6]|(DSP1.parameters[7]<<8)); + Op14F = (int16) (DSP1.parameters [8]|(DSP1.parameters[9]<<8)); + Op14L = (int16) (DSP1.parameters [10]|(DSP1.parameters[11]<<8)); + + DSPOp14 (); + + DSP1.out_count = 6; + DSP1.output [0] = (uint8) (Op14Zrr&0xFF); + DSP1.output [1] = (uint8) ((Op14Zrr>>8)&0xFF); + DSP1.output [2] = (uint8) (Op14Xrr&0xFF); + DSP1.output [3] = (uint8) ((Op14Xrr>>8)&0xFF); + DSP1.output [4] = (uint8) (Op14Yrr&0xFF); + DSP1.output [5] = (uint8) ((Op14Yrr>>8)&0xFF); + break; + + case 0x27: + case 0x2F: + Op2FUnknown = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + + DSPOp2F (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8)(Op2FSize&0xFF); + DSP1.output [1] = (uint8)((Op2FSize>>8)&0xFF); + break; + + + case 0x07: + case 0x0F: + Op0FRamsize = (int16) (DSP1.parameters [0]|(DSP1.parameters[1]<<8)); + + DSPOp0F (); + + DSP1.out_count = 2; + DSP1.output [0] = (uint8)(Op0FPass&0xFF); + DSP1.output [1] = (uint8)((Op0FPass>>8)&0xFF); + break; + + default: + break; + } + } + } + } + } +} + +uint8 DSP1GetByte(uint16 address) +{ + uint8 t; + if ((address & 0xf000) == 0x6000 || +// (address >= 0x8000 && address < 0xc000)) + (address&0x7fff) < 0x4000) + { + if (DSP1.out_count) + { + //if ((address & 1) == 0) + t = (uint8) DSP1.output [DSP1.out_index]; + //else + //{ + // t = (uint8) (DSP1.output [DSP1.out_index] >> 8); + DSP1.out_index++; + if (--DSP1.out_count == 0) + { + if (DSP1.command == 0x1a || DSP1.command == 0x0a) + { + DSPOp0A (); + DSP1.out_count = 8; + DSP1.out_index = 0; + DSP1.output [0] = (Op0AA&0xFF); + DSP1.output [1] = (Op0AA>>8)&0xFF; + DSP1.output [2] = (Op0AB&0xFF); + DSP1.output [3] = (Op0AB>>8)&0xFF; + DSP1.output [4] = (Op0AC&0xFF); + DSP1.output [5] = (Op0AC>>8)&0xFF; + DSP1.output [6] = (Op0AD&0xFF); + DSP1.output [7] = (Op0AD>>8)&0xFF; + } + if(DSP1.command==0x1f) + { + if((DSP1.out_index%2)!=0) + { + t=(uint8)DSP1ROM[DSP1.out_index>>1]; + } + else + { + t=DSP1ROM[DSP1.out_index>>1]>>8; + } + } + } + DSP1.waiting4command = TRUE; + //} + } + else + { + // Top Gear 3000 requires this value.... + // if(4==Settings.DSPVersion) + t = 0xff; + //Ballz3d requires this one: + // else t = 0x00; + } + } + else t = 0x80; + return t; +} + +void DSP2SetByte(uint8 byte, uint16 address) +{ + if ((address & 0xf000) == 0x6000 || + (address >= 0x8000 && address < 0xc000)) + { + if (DSP1.waiting4command) + { + DSP1.command = byte; + DSP1.in_index = 0; + DSP1.waiting4command = FALSE; +// DSP1.first_parameter = TRUE; +// printf("Op%02X\n",byte); + switch (byte) + { + case 0x01:DSP1.in_count=32;break; + case 0x03:DSP1.in_count=1;break; + case 0x05:DSP1.in_count=1;break; + case 0x09:DSP1.in_count=4;break; + case 0x06:DSP1.in_count=1;break; + case 0x0D:DSP1.in_count=2;break; + default: + printf("Op%02X\n",byte); + case 0x0f:DSP1.in_count=0;break; + } + } + else + { + DSP1.parameters [DSP1.in_index] = byte; +// DSP1.first_parameter = FALSE; + DSP1.in_index++; + } + + if (DSP1.in_count==DSP1.in_index) + { + //DSP1.parameters [DSP1.in_index] |= (byte << 8); + // Actually execute the command + DSP1.waiting4command = TRUE; + DSP1.out_index = 0; + switch (DSP1.command) + { + case 0x0D: + if(DSP2Op0DHasLen) + { + DSP2Op0DHasLen=false; + DSP1.out_count=DSP2Op0DOutLen; + //execute Op5 + DSP2_Op0D(); + } + else + { + DSP2Op0DInLen=DSP1.parameters[0]; + DSP2Op0DOutLen=DSP1.parameters[1]; + DSP1.in_index=0; + DSP1.in_count=(DSP2Op0DInLen+1)>>1; + DSP2Op0DHasLen=true; + if(byte) + DSP1.waiting4command=false; + } + break; + case 0x06: + if(DSP2Op06HasLen) + { + DSP2Op06HasLen=false; + DSP1.out_count=DSP2Op06Len; + //execute Op5 + DSP2_Op06(); + } + else + { + DSP2Op06Len=DSP1.parameters[0]; + DSP1.in_index=0; + DSP1.in_count=DSP2Op06Len; + DSP2Op06HasLen=true; + if(byte) + DSP1.waiting4command=false; + } + break; + case 0x01: + DSP1.out_count=32; + DSP2_Op01(); + break; + case 0x09: + // Multiply - don't yet know if this is signed or unsigned + DSP2Op09Word1 = DSP1.parameters[0] | (DSP1.parameters[1]<<8); + DSP2Op09Word2 = DSP1.parameters[2] | (DSP1.parameters[3]<<8); + DSP1.out_count=4; +#ifdef FAST_LSB_WORD_ACCESS + *(uint32 *)DSP1.output = DSP2Op09Word1 * DSP2Op09Word2; +#else + uint32 temp; + temp=DSP2Op09Word1 * DSP2Op09Word2; + DSP1.output[0]=temp&0xFF; + DSP1.output[1]=(temp>>8)&0xFF; + DSP1.output[2]=(temp>>16)&0xFF; + DSP1.output[3]=(temp>>24)&0xFF; +#endif + break; + case 0x05: + if(DSP2Op05HasLen) + { + DSP2Op05HasLen=false; + DSP1.out_count=DSP2Op05Len; + //execute Op5 + DSP2_Op05(); + } + else + { + DSP2Op05Len=DSP1.parameters[0]; + DSP1.in_index=0; + DSP1.in_count=2*DSP2Op05Len; + DSP2Op05HasLen=true; + if(byte) + DSP1.waiting4command=false; + } + break; + + case 0x03: + DSP2Op05Transparent= DSP1.parameters[0]; + //DSP2Op03(); + break; + case 0x0f: + default: + break; + } + } + } +} + +uint8 DSP2GetByte(uint16 address) +{ + uint8 t; + if ((address & 0xf000) == 0x6000 || + (address >= 0x8000 && address < 0xc000)) + { + if (DSP1.out_count) + { + t = (uint8) DSP1.output [DSP1.out_index]; + DSP1.out_index++; + if(DSP1.out_count==DSP1.out_index) + DSP1.out_count=0; + } + else + { + t = 0xff; + } + } + else t = 0x80; + return t; +} + +bool DSP4_init=FALSE; + +/* +extern uint8 dsp4_byte; +extern uint16 dsp4_address; +void InitDSP4(); +void DSP4_SetByte(); +void DSP4_GetByte(); +*/ + +void DSP4SetByte(uint8 byte, uint16 address) +{ + if (!DSP4_init) + { + InitDSP4(); + DSP4_init=TRUE; + } + if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) + { + dsp4_byte=byte; + dsp4_address=address; + DSP4_SetByte(); + } +} + +uint8 DSP4GetByte(uint16 address) +{ + if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) + { + dsp4_address=address; + DSP4_GetByte(); + return dsp4_byte; + } + return 0x80; +} diff --git a/source/snes9x/dsp1.h b/source/snes9x/dsp1.h new file mode 100644 index 0000000..9d04f0f --- /dev/null +++ b/source/snes9x/dsp1.h @@ -0,0 +1,185 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _DSP1_H_ +#define _DSP1_H_ + +extern void (*SetDSP)(uint8, uint16); +extern uint8 (*GetDSP)(uint16); + +void DSP1SetByte(uint8 byte, uint16 address); +uint8 DSP1GetByte(uint16 address); + +void DSP2SetByte(uint8 byte, uint16 address); +uint8 DSP2GetByte(uint16 address); + +void DSP3SetByte(uint8 byte, uint16 address); +uint8 DSP3GetByte(uint16 address); +void DSP3_Reset(); + +void DSP4SetByte(uint8 byte, uint16 address); +uint8 DSP4GetByte(uint16 address); + +struct SDSP1 { + uint8 version; + bool8 waiting4command; + bool8 first_parameter; + uint8 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters [512]; + uint8 output [512]; +}; + +START_EXTERN_C +void S9xResetDSP1 (); +uint8 S9xGetDSP (uint16 Address); +void S9xSetDSP (uint8 Byte, uint16 Address); +END_EXTERN_C + +extern struct SDSP1 DSP1; + +#endif diff --git a/source/snes9x/dsp1emu.c.inc b/source/snes9x/dsp1emu.c.inc new file mode 100644 index 0000000..d8377aa --- /dev/null +++ b/source/snes9x/dsp1emu.c.inc @@ -0,0 +1,1215 @@ +/* +Copyright (C) 1997-2006 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach ) + +http://www.zsnes.com +http://sourceforge.net/projects/zsnes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +//#define __ZSNES__ + +#if (defined __ZSNES__ && __UNIXSDL__) +#include "../gblhdr.h" +#else + +#include +#include +#include +#endif +//#define DebugDSP1 + +#ifdef DebugDSP1 + +FILE * LogFile = NULL; + +void Log_Message (char *Message, ...) +{ + char Msg[400]; + va_list ap; + + va_start(ap,Message); + vsprintf(Msg,Message,ap ); + va_end(ap); + + strcat(Msg,"\r\n\0"); + fwrite(Msg,strlen(Msg),1,LogFile); + fflush (LogFile); +} + +void Start_Log (void) +{ + char LogFileName[255]; +// [4/15/2001] char *p; + + strcpy(LogFileName,"dsp1emu.log\0"); + + LogFile = fopen(LogFileName,"wb"); +} + +void Stop_Log (void) +{ + if (LogFile) + { + fclose(LogFile); + LogFile = NULL; + } +} + +#endif + +const unsigned short 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 * +\***************************************************************************/ + +void InitDSP(void) +{ +#ifdef DebugDSP1 + Start_Log(); +#endif +} + +short Op00Multiplicand; +short Op00Multiplier; +short Op00Result; + +void DSPOp00() +{ + Op00Result= Op00Multiplicand * Op00Multiplier >> 15; + + #ifdef DebugDSP1 + Log_Message("OP00 MULT %d*%d/32768=%d",Op00Multiplicand,Op00Multiplier,Op00Result); + #endif +} + +short Op20Multiplicand; +short Op20Multiplier; +short Op20Result; + +void DSPOp20() +{ + Op20Result= Op20Multiplicand * Op20Multiplier >> 15; + Op20Result++; + + #ifdef DebugDSP1 + Log_Message("OP20 MULT %d*%d/32768=%d",Op20Multiplicand,Op20Multiplier,Op20Result); + #endif +} + +signed short Op10Coefficient; +signed short Op10Exponent; +signed short Op10CoefficientR; +signed short Op10ExponentR; + +void DSP1_Inverse(short Coefficient, short Exponent, short *iCoefficient, short *iExponent) +{ + // Step One: Division by Zero + if (Coefficient == 0x0000) + { + *iCoefficient = 0x7fff; + *iExponent = 0x002f; + } + else + { + short 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 + short 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() +{ + DSP1_Inverse(Op10Coefficient, Op10Exponent, &Op10CoefficientR, &Op10ExponentR); + #ifdef DebugDSP1 + Log_Message("OP10 INV %d*2^%d = %d*2^%d", Op10Coefficient, Op10Exponent, Op10CoefficientR, Op10ExponentR); + #endif +} + +short Op04Angle; +short Op04Radius; +short Op04Sin; +short Op04Cos; + +const short 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 short 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}; + +short DSP1_Sin(short Angle) +{ + int 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 (short) S; +} + +short DSP1_Cos(short Angle) +{ + int 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 (short) S; +} + +void DSP1_Normalize(short m, short *Coefficient, short *Exponent) +{ + short i = 0x4000; + short 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(int Product, short *Coefficient, short *Exponent) +{ + short n = Product & 0x7fff; + short m = Product >> 15; + short i = 0x4000; + short 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; +} + +short DSP1_Truncate(short C, short 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() +{ + Op04Sin = DSP1_Sin(Op04Angle) * Op04Radius >> 15; + Op04Cos = DSP1_Cos(Op04Angle) * Op04Radius >> 15; +} + +short Op0CA; +short Op0CX1; +short Op0CY1; +short Op0CX2; +short Op0CY2; + +void DSPOp0C() +{ + Op0CX2 = (Op0CY1 * DSP1_Sin(Op0CA) >> 15) + (Op0CX1 * DSP1_Cos(Op0CA) >> 15); + Op0CY2 = (Op0CY1 * DSP1_Cos(Op0CA) >> 15) - (Op0CX1 * DSP1_Sin(Op0CA) >> 15); +} + +short CentreX; +short CentreY; +short VOffset; + +short VPlane_C; +short VPlane_E; + +// Azimuth and Zenith angles +short SinAas; +short CosAas; +short SinAzs; +short CosAzs; + +// Clipped Zenith angle +short SinAZS; +short CosAZS; +short SecAZS_C1; +short SecAZS_E1; +short SecAZS_C2; +short SecAZS_E2; + +short Nx, Ny, Nz; +short Gx, Gy, Gz; +short C_Les, E_Les, G_Les; + +const short MaxAZS_Exp[16] = { + 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca, + 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4 +}; + +void DSP1_Parameter(short Fx, short Fy, short Fz, short Lfe, short Les, short Aas, short Azs, short *Vof, short *Vva, short *Cx, short *Cy) +{ + short CSec, C, E, MaxAZS, Aux; + short LfeNx, LfeNy, LfeNz; + short LesNx, LesNy, LesNz; + short CentreZ; + + // Copy Zenith angle for clipping + short 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(short Vs, short *An, short *Bn, short *Cn, short *Dn) +{ + short 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; +} + +short Op02FX; +short Op02FY; +short Op02FZ; +short Op02LFE; +short Op02LES; +short Op02AAS; +short Op02AZS; +short Op02VOF; +short Op02VVA; +short Op02CX; +short Op02CY; + +void DSPOp02() +{ + DSP1_Parameter(Op02FX, Op02FY, Op02FZ, Op02LFE, Op02LES, Op02AAS, Op02AZS, &Op02VOF, &Op02VVA, &Op02CX, &Op02CY); +} + +short Op0AVS; +short Op0AA; +short Op0AB; +short Op0AC; +short Op0AD; + +void DSPOp0A() +{ + DSP1_Raster(Op0AVS, &Op0AA, &Op0AB, &Op0AC, &Op0AD); + Op0AVS++; +} + + +short DSP1_ShiftR(short C, short E) +{ + return (C * DSP1ROM[0x0031 + E] >> 15); +} + +void DSP1_Project(short X, short Y, short Z, short *H, short *V, short *M) +{ + int aux, aux4; + short E, E2, E3, E4, E5, refE, E6, E7; + short C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26; + short Px, Py, Pz; + + E4=E3=E2=E=E5=0; + + DSP1_NormalizeDouble((int)X-Gx, &Px, &E4); + DSP1_NormalizeDouble((int)Y-Gy, &Py, &E); + DSP1_NormalizeDouble((int)Z-Gz, &Pz, &E3); + Px>>=1; E4--; // to avoid overflows when calculating the scalar products + Py>>=1; E--; + Pz>>=1; E3--; + + refE = (E>15); + C8=- (Py*Ny>>15); + C9=- (Pz*Nz>>15); + C12=C11+C8+C9; // this cannot overflow! + + aux4=C12; // de-normalization with 32-bits 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 = ((unsigned short)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 +} + +short Op06X; +short Op06Y; +short Op06Z; +short Op06H; +short Op06V; +short Op06M; + +void DSPOp06() +{ + DSP1_Project(Op06X, Op06Y, Op06Z, &Op06H, &Op06V, &Op06M); +} + + +short matrixC[3][3]; +short matrixB[3][3]; +short matrixA[3][3]; + +short Op01m; +short Op01Zr; +short Op01Xr; +short Op01Yr; +short Op11m; +short Op11Zr; +short Op11Xr; +short Op11Yr; +short Op21m; +short Op21Zr; +short Op21Xr; +short Op21Yr; + +void DSPOp01() +{ + short SinAz = DSP1_Sin(Op01Zr); + short CosAz = DSP1_Cos(Op01Zr); + short SinAy = DSP1_Sin(Op01Yr); + short CosAy = DSP1_Cos(Op01Yr); + short SinAx = DSP1_Sin(Op01Xr); + short 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() +{ + short SinAz = DSP1_Sin(Op11Zr); + short CosAz = DSP1_Cos(Op11Zr); + short SinAy = DSP1_Sin(Op11Yr); + short CosAy = DSP1_Cos(Op11Yr); + short SinAx = DSP1_Sin(Op11Xr); + short 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() +{ + short SinAz = DSP1_Sin(Op21Zr); + short CosAz = DSP1_Cos(Op21Zr); + short SinAy = DSP1_Sin(Op21Yr); + short CosAy = DSP1_Cos(Op21Yr); + short SinAx = DSP1_Sin(Op21Xr); + short 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; +} + +short Op0DX; +short Op0DY; +short Op0DZ; +short Op0DF; +short Op0DL; +short Op0DU; +short Op1DX; +short Op1DY; +short Op1DZ; +short Op1DF; +short Op1DL; +short Op1DU; +short Op2DX; +short Op2DY; +short Op2DZ; +short Op2DF; +short Op2DL; +short Op2DU; + +void DSPOp0D() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP0D X: %d Y: %d Z: %d / F: %d L: %d U: %d",Op0DX,Op0DY,Op0DZ,Op0DF,Op0DL,Op0DU); + #endif +} + +void DSPOp1D() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP1D X: %d Y: %d Z: %d / F: %d L: %d U: %d",Op1DX,Op1DY,Op1DZ,Op1DF,Op1DL,Op1DU); + #endif +} + +void DSPOp2D() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP2D X: %d Y: %d Z: %d / F: %d L: %d U: %d",Op2DX,Op2DY,Op2DZ,Op2DF,Op2DL,Op2DU); + #endif +} + +short Op03F; +short Op03L; +short Op03U; +short Op03X; +short Op03Y; +short Op03Z; +short Op13F; +short Op13L; +short Op13U; +short Op13X; +short Op13Y; +short Op13Z; +short Op23F; +short Op23L; +short Op23U; +short Op23X; +short Op23Y; +short Op23Z; + +void DSPOp03() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP03 F: %d L: %d U: %d / X: %d Y: %d Z: %d",Op03F,Op03L,Op03U,Op03X,Op03Y,Op03Z); + #endif +} + +void DSPOp13() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP13 F: %d L: %d U: %d / X: %d Y: %d Z: %d",Op13F,Op13L,Op13U,Op13X,Op13Y,Op13Z); + #endif +} + +void DSPOp23() +{ + 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); + + #ifdef DebugDSP1 + Log_Message("OP23 F: %d L: %d U: %d / X: %d Y: %d Z: %d",Op23F,Op23L,Op23U,Op23X,Op23Y,Op23Z); + #endif +} + +short Op14Zr; +short Op14Xr; +short Op14Yr; +short Op14U; +short Op14F; +short Op14L; +short Op14Zrr; +short Op14Xrr; +short Op14Yrr; + +void DSPOp14() +{ + short 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(short H, short V, short *X, short *Y) +{ + short 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; +} + +short Op0EH; +short Op0EV; +short Op0EX; +short Op0EY; + +void DSPOp0E() +{ + DSP1_Target(Op0EH, Op0EV, &Op0EX, &Op0EY); +} + +short Op0BX; +short Op0BY; +short Op0BZ; +short Op0BS; +short Op1BX; +short Op1BY; +short Op1BZ; +short Op1BS; +short Op2BX; +short Op2BY; +short Op2BZ; +short Op2BS; + +void DSPOp0B() +{ + Op0BS = (Op0BX * matrixA[0][0] + Op0BY * matrixA[0][1] + Op0BZ * matrixA[0][2]) >> 15; + + #ifdef DebugDSP1 + Log_Message("OP0B"); + #endif +} + +void DSPOp1B() +{ + Op1BS = (Op1BX * matrixB[0][0] + Op1BY * matrixB[0][1] + Op1BZ * matrixB[0][2]) >> 15; + + #ifdef DebugDSP1 + Log_Message("OP1B X: %d Y: %d Z: %d S: %d",Op1BX,Op1BY,Op1BZ,Op1BS); + Log_Message(" MX: %d MY: %d MZ: %d Scale: %d",(short)(matrixB[0][0]*100),(short)(matrixB[0][1]*100),(short)(matrixB[0][2]*100),(short)(sc2*100)); + #endif +} + +void DSPOp2B() +{ + Op2BS = (Op2BX * matrixC[0][0] + Op2BY * matrixC[0][1] + Op2BZ * matrixC[0][2]) >> 15; + + #ifdef DebugDSP1 + Log_Message("OP2B"); + #endif +} + +short Op08X,Op08Y,Op08Z,Op08Ll,Op08Lh; + +void DSPOp08() +{ + int Op08Size = (Op08X * Op08X + Op08Y * Op08Y + Op08Z * Op08Z) << 1; + Op08Ll = Op08Size & 0xffff; + Op08Lh = (Op08Size >> 16) & 0xffff; + + #ifdef DebugDSP1 + Log_Message("OP08 %d,%d,%d",Op08X,Op08Y,Op08Z); + Log_Message("OP08 ((Op08X^2)+(Op08Y^2)+(Op08X^2))=%x",Op08Size ); + #endif +} + +short Op18X,Op18Y,Op18Z,Op18R,Op18D; + +void DSPOp18() +{ + Op18D = (Op18X * Op18X + Op18Y * Op18Y + Op18Z * Op18Z - Op18R * Op18R) >> 15; + + #ifdef DebugDSP1 + Log_Message("Op18 X: %d Y: %d Z: %d R: %D DIFF %d",Op18X,Op18Y,Op38Z,Op18D); + #endif +} + +short Op38X,Op38Y,Op38Z,Op38R,Op38D; + +void DSPOp38() +{ + Op38D = (Op38X * Op38X + Op38Y * Op38Y + Op38Z * Op38Z - Op38R * Op38R) >> 15; + Op38D++; + + #ifdef DebugDSP1 + Log_Message("OP38 X: %d Y: %d Z: %d R: %D DIFF %d",Op38X,Op38Y,Op38Z,Op38D); + #endif +} + +short Op28X; +short Op28Y; +short Op28Z; +short Op28R; + +void DSPOp28() +{ + int Radius = Op28X * Op28X + Op28Y * Op28Y + Op28Z * Op28Z; + + if (Radius == 0) Op28R = 0; + else + { + short 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); + } + + #ifdef DebugDSP1 + Log_Message("OP28 X:%d Y:%d Z:%d",Op28X,Op28Y,Op28Z); + Log_Message("OP28 Vector Length %d",Op28R); + #endif +} + +short Op1CX,Op1CY,Op1CZ; +short Op1CXBR,Op1CYBR,Op1CZBR,Op1CXAR,Op1CYAR,Op1CZAR; +short Op1CX1; +short Op1CY1; +short Op1CZ1; +short Op1CX2; +short Op1CY2; +short Op1CZ2; + +void DSPOp1C() +{ + // 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; + + #ifdef DebugDSP1 + Log_Message("OP1C Apply Matrix CX:%d CY:%d CZ",Op1CXAR,Op1CYAR,Op1CZAR); + #endif +} + +unsigned short Op0FRamsize; +unsigned short Op0FPass; + +void DSPOp0F() +{ + Op0FPass = 0x0000; + + #ifdef DebugDSP1 + Log_Message("OP0F RAM Test Pass:%d", Op0FPass); + #endif +} + +short Op2FUnknown; +short Op2FSize; + +void DSPOp2F() +{ + Op2FSize=0x100; +} diff --git a/source/snes9x/dsp2emu.c.inc b/source/snes9x/dsp2emu.c.inc new file mode 100644 index 0000000..869ed81 --- /dev/null +++ b/source/snes9x/dsp2emu.c.inc @@ -0,0 +1,397 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + + +uint16 DSP2Op09Word1=0; +uint16 DSP2Op09Word2=0; +bool DSP2Op05HasLen=false; +int DSP2Op05Len=0; +bool DSP2Op06HasLen=false; +int DSP2Op06Len=0; +uint8 DSP2Op05Transparent=0; + +void DSP2_Op05 () +{ + uint8 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. + + int n; + unsigned char c1; + unsigned char c2; + unsigned char *p1 = DSP1.parameters; + unsigned char *p2 = &DSP1.parameters[DSP2Op05Len]; + unsigned char *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 () +{ + // Op01 size is always 32 bytes input and output. + // The hardware does strange things if you vary the size. + + int j; + unsigned char c0, c1, c2, c3; + unsigned char *p1 = DSP1.parameters; + unsigned char *p2a = DSP1.output; + unsigned char *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; + } + return; +} + +void DSP2_Op06 () +{ + // Input: + // size + // bitmap + + int 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; +int DSP2Op0DOutLen=0; +int DSP2Op0DInLen=0; + +#ifndef DSP2_BIT_ACCURRATE_CODE + +// Scale bitmap based on input length out output length + +void DSP2_Op0D() +{ + // Overload's algorithm - use this unless doing hardware testing + + // One note: the HW can do odd byte scaling but since we divide + // by two to get the count of bytes this won't work well for + // odd byte scaling (in any of the current algorithm implementations). + // So far I haven't seen Dungeon Master use it. + // If it does we can adjust the parameters and code to work with it + + int i; + int pixel_offset; + uint8 pixelarray[512]; + + for(i=0; i>1] >> 4; + else + pixelarray[i] = DSP1.parameters[pixel_offset>>1] & 0x0f; + } + + for ( i=0; i < DSP2Op0DOutLen; i++ ) + DSP1.output[i] = ( pixelarray[i<<1] << 4 ) | pixelarray[(i<<1)+1]; +} + +#else + +void DSP2_Op0D() +{ + // Bit accurate hardware algorithm - uses fixed point math + // This should match the DSP2 Op0D output exactly + // I wouldn't recommend using this unless you're doing hardware debug. + // In some situations it has small visual artifacts that + // are not readily apparent on a TV screen but show up clearly + // on a monitor. Use Overload's scaling instead. + // This is for hardware verification testing. + // + // One note: the HW can do odd byte scaling but since we divide + // by two to get the count of bytes this won't work well for + // odd byte scaling (in any of the current algorithm implementations). + // So far I haven't seen Dungeon Master use it. + // If it does we can adjust the parameters and code to work with it + + + uint32 multiplier; // Any size int >= 32-bits + uint32 pixloc; // match size of multiplier + int i, j; + uint8 pixelarray[512]; + + if (DSP2Op0DInLen <= DSP2Op0DOutLen) + multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1 + else + multiplier = (DSP2Op0DInLen << 17) / ((DSP2Op0DOutLen<<1) + 1); + + pixloc = 0; + for ( i=0; i < DSP2Op0DOutLen * 2; i++ ) + { + j = pixloc >> 16; + + if ( j & 1 ) + pixelarray[i] = DSP1.parameters[j>>1] & 0x0f; + else + pixelarray[i] = (DSP1.parameters[j>>1] & 0xf0) >> 4; + + pixloc += multiplier; + } + + for ( i=0; i < DSP2Op0DOutLen; i++ ) + DSP1.output[i] = ( pixelarray[i<<1] << 4 ) | pixelarray[(i<<1)+1]; +} + +#endif + +#if 0 // Probably no reason to use this code - it's not quite bit accurate and it doesn't look as good as Overload's algorithm + +void DSP2_Op0D() +{ + // Float implementation of Neviksti's algorithm + // This is the right algorithm to match the DSP2 bits but the precision + // of the PC float does not match the precision of the fixed point math + // on the DSP2 causing occasional one off data mismatches (which should + // be no problem because its just a one pixel difference in a scaled image + // to be displayed). + + float multiplier; + float pixloc; + int i, j; + uint8 pixelarray[512]; + + if (DSP2Op0DInLen <= DSP2Op0DOutLen) + multiplier = (float) 1.0; + else + multiplier = (float) ((DSP2Op0DInLen * 2.0) / (DSP2Op0DOutLen * 2.0 + 1.0)); + + pixloc = 0.0; + for ( i=0; i < DSP2Op0DOutLen * 2; i++ ) + { + // j = (int)(i * multiplier); + j = (int) pixloc; + + if ( j & 1 ) + pixelarray[i] = DSP1.parameters[j>>1] & 0x0f; + else + pixelarray[i] = (DSP1.parameters[j>>1] & 0xf0) >> 4; + + pixloc += multiplier; // use an add in the loop instead of multiply to increase loop speed + } + + for ( i=0; i < DSP2Op0DOutLen; i++ ) + DSP1.output[i] = ( pixelarray[i<<1] << 4 ) | pixelarray[(i<<1)+1]; +} + +#endif + diff --git a/source/snes9x/dsp3emu.c.inc b/source/snes9x/dsp3emu.c.inc new file mode 100644 index 0000000..7b120b9 --- /dev/null +++ b/source/snes9x/dsp3emu.c.inc @@ -0,0 +1,1285 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef __cplusplus +//C++ in C +typedef unsigned char bool; +#define true 1 +#define false 0 +#endif + +uint16 DSP3_DataROM[1024] = { + 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, + 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, + 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, + 0x0000, 0x000f, 0x0400, 0x0200, 0x0140, 0x0400, 0x0200, 0x0040, + 0x007d, 0x007e, 0x007e, 0x007b, 0x007c, 0x007d, 0x007b, 0x007c, + 0x0002, 0x0020, 0x0030, 0x0000, 0x000d, 0x0019, 0x0026, 0x0032, + 0x003e, 0x004a, 0x0056, 0x0062, 0x006d, 0x0079, 0x0084, 0x008e, + 0x0098, 0x00a2, 0x00ac, 0x00b5, 0x00be, 0x00c6, 0x00ce, 0x00d5, + 0x00dc, 0x00e2, 0x00e7, 0x00ec, 0x00f1, 0x00f5, 0x00f8, 0x00fb, + 0x00fd, 0x00ff, 0x0100, 0x0100, 0x0100, 0x00ff, 0x00fd, 0x00fb, + 0x00f8, 0x00f5, 0x00f1, 0x00ed, 0x00e7, 0x00e2, 0x00dc, 0x00d5, + 0x00ce, 0x00c6, 0x00be, 0x00b5, 0x00ac, 0x00a2, 0x0099, 0x008e, + 0x0084, 0x0079, 0x006e, 0x0062, 0x0056, 0x004a, 0x003e, 0x0032, + 0x0026, 0x0019, 0x000d, 0x0000, 0xfff3, 0xffe7, 0xffdb, 0xffce, + 0xffc2, 0xffb6, 0xffaa, 0xff9e, 0xff93, 0xff87, 0xff7d, 0xff72, + 0xff68, 0xff5e, 0xff54, 0xff4b, 0xff42, 0xff3a, 0xff32, 0xff2b, + 0xff25, 0xff1e, 0xff19, 0xff14, 0xff0f, 0xff0b, 0xff08, 0xff05, + 0xff03, 0xff01, 0xff00, 0xff00, 0xff00, 0xff01, 0xff03, 0xff05, + 0xff08, 0xff0b, 0xff0f, 0xff13, 0xff18, 0xff1e, 0xff24, 0xff2b, + 0xff32, 0xff3a, 0xff42, 0xff4b, 0xff54, 0xff5d, 0xff67, 0xff72, + 0xff7c, 0xff87, 0xff92, 0xff9e, 0xffa9, 0xffb5, 0xffc2, 0xffce, + 0xffda, 0xffe7, 0xfff3, 0x002b, 0x007f, 0x0020, 0x00ff, 0xff00, + 0xffbe, 0x0000, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0x0045, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc5, 0x0003, 0x0004, 0x0005, 0x0047, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, + 0x0009, 0x004a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x004e, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0053, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, + 0x0059, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0060, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, + 0x002b, 0x002c, 0x0068, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0071, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, + 0x003e, 0x003f, 0x0040, 0x0041, 0x007b, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, + 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0050, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x005d, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, + 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x006b, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0044, 0x0000, 0x0000, + 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, + 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0054, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0065, + 0xffbe, 0x0000, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffc1, 0x0001, 0x0002, 0xfead, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc5, 0x0003, 0x0004, 0x0005, 0xfeaf, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffca, 0x0006, 0x0007, 0x0008, + 0x0009, 0xfeb2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffd0, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0xfeb6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd7, 0x000f, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0xfebb, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffdf, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, + 0xfec1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffe8, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0xfec8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xfff2, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, + 0x002b, 0x002c, 0xfed0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfffd, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0xfed9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffc7, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, + 0x003e, 0x003f, 0x0040, 0x0041, 0xfee3, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffd4, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0xfeac, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffe2, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, + 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0xfeb8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfff1, 0x0019, 0x001a, 0x001b, + 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0xfec5, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffcb, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, + 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0xfed3, 0x0000, 0x0000, 0x0000, 0xffdc, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, + 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0xfeac, 0x0000, 0x0000, + 0xffee, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, + 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, + 0x001f, 0x0020, 0xfebc, 0x0000, 0xffee, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, + 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0xfecd, + 0x0154, 0x0218, 0x0110, 0x00b0, 0x00cc, 0x00b0, 0x0088, 0x00b0, + 0x0044, 0x00b0, 0x0000, 0x00b0, 0x00fe, 0xff07, 0x0002, 0x00ff, + 0x00f8, 0x0007, 0x00fe, 0x00ee, 0x07ff, 0x0200, 0x00ef, 0xf800, + 0x0700, 0x00ee, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, + 0xffff, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, + 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0001, + 0x0001, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, + 0xffff, 0x0001, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0xffff, + 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0044, 0x0088, 0x00cc, + 0x0110, 0x0154, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +void (*SetDSP3)(); +void DSP3_Command(); + +uint16 DSP3_DR; +uint16 DSP3_SR; +uint16 DSP3_MemoryIndex; + +void DSP3_Reset() +{ + DSP3_DR = 0x0080; + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_Command; +} + +void DSP3_MemorySize() +{ + DSP3_DR = 0x0300; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_TestMemory() +{ + DSP3_DR = 0x0000; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_DumpDataROM() +{ + DSP3_DR = DSP3_DataROM[DSP3_MemoryIndex++]; + if (DSP3_MemoryIndex == 1024) + SetDSP3 = &DSP3_Reset; +} + +void DSP3_MemoryDump() +{ + DSP3_MemoryIndex = 0; + SetDSP3 = &DSP3_DumpDataROM; + DSP3_DumpDataROM(); +} + +int16 DSP3_WinLo; +int16 DSP3_WinHi; + +void DSP3_OP06() +{ + DSP3_WinLo = (uint8)(DSP3_DR); + DSP3_WinHi = (uint8)(DSP3_DR >> 8); + DSP3_Reset(); +} + +void DSP3_OP03() +{ + int16 Lo = (uint8)(DSP3_DR); + int16 Hi = (uint8)(DSP3_DR >> 8); + int16 Ofs = (DSP3_WinLo * Hi << 1) + (Lo << 1); + DSP3_DR = Ofs >> 1; + SetDSP3 = &DSP3_Reset; +} + +int16 DSP3_AddLo; +int16 DSP3_AddHi; + +void DSP3_OP07_B() +{ + int16 Ofs = (DSP3_WinLo * DSP3_AddHi << 1) + (DSP3_AddLo << 1); + DSP3_DR = Ofs >> 1; + SetDSP3 = &DSP3_Reset; +} + +void DSP3_OP07_A() +{ + int16 Lo = (uint8)(DSP3_DR); + int16 Hi = (uint8)(DSP3_DR >> 8); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + if (DSP3_AddLo < 0) + DSP3_AddLo += DSP3_WinLo; + else + if (DSP3_AddLo >= DSP3_WinLo) + DSP3_AddLo -= DSP3_WinLo; + + if (DSP3_AddHi < 0) + DSP3_AddHi += DSP3_WinHi; + else + if (DSP3_AddHi >= DSP3_WinHi) + DSP3_AddHi -= DSP3_WinHi; + + DSP3_DR = DSP3_AddLo | (DSP3_AddHi << 8) | ((DSP3_AddHi >> 8) & 0xff); + SetDSP3 = &DSP3_OP07_B; +} + +void DSP3_OP07() +{ + uint32 dataOfs = ((DSP3_DR << 1) + 0x03b2) & 0x03ff; + + DSP3_AddHi = DSP3_DataROM[dataOfs]; + DSP3_AddLo = DSP3_DataROM[dataOfs + 1]; + + SetDSP3 = &DSP3_OP07_A; + DSP3_SR = 0x0080; +} + +uint16 DSP3_Codewords; +uint16 DSP3_Outwords; +uint16 DSP3_Symbol; +uint16 DSP3_BitCount; +uint16 DSP3_Index; +uint16 DSP3_Codes[512]; +uint16 DSP3_BitsLeft; +uint16 DSP3_ReqBits; +uint16 DSP3_ReqData; +uint16 DSP3_BitCommand; +uint8 DSP3_BaseLength; +uint16 DSP3_BaseCodes; +uint16 DSP3_BaseCode; +uint8 DSP3_CodeLengths[8]; +uint16 DSP3_CodeOffsets[8]; +uint16 DSP3_LZCode; +uint8 DSP3_LZLength; + +uint16 DSP3_X; +uint16 DSP3_Y; + +void DSP3_Coordinate() +{ + DSP3_Index++; + + switch (DSP3_Index) + { + case 3: + { + if (DSP3_DR == 0xffff) + DSP3_Reset(); + break; + } + case 4: + { + DSP3_X = DSP3_DR; + break; + } + case 5: + { + DSP3_Y = DSP3_DR; + DSP3_DR = 1; + break; + } + case 6: + { + DSP3_DR = DSP3_X; + break; + } + case 7: + { + DSP3_DR = DSP3_Y; + DSP3_Index = 0; + break; + } + } +} + +uint8 DSP3_Bitmap[8]; +uint8 DSP3_Bitplane[8]; +uint16 DSP3_BMIndex; +uint16 DSP3_BPIndex; +uint16 DSP3_Count; + +void DSP3_Convert_A() +{ + if (DSP3_BMIndex < 8) + { + DSP3_Bitmap[DSP3_BMIndex++] = (uint8) (DSP3_DR); + DSP3_Bitmap[DSP3_BMIndex++] = (uint8) (DSP3_DR >> 8); + + if (DSP3_BMIndex == 8) + { + short i, j; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + { + DSP3_Bitplane[j] <<= 1; + DSP3_Bitplane[j] |= (DSP3_Bitmap[i] >> j) & 1; + } + + DSP3_BPIndex = 0; + DSP3_Count--; + } + } + + if (DSP3_BMIndex == 8) + { + if (DSP3_BPIndex == 8) + { + if (!DSP3_Count) DSP3_Reset(); + DSP3_BMIndex = 0; + } + else + { + DSP3_DR = DSP3_Bitplane[DSP3_BPIndex++]; + DSP3_DR |= DSP3_Bitplane[DSP3_BPIndex++] << 8; + } + } +} + +void DSP3_Convert() +{ + DSP3_Count = DSP3_DR; + DSP3_BMIndex = 0; + SetDSP3 = &DSP3_Convert_A; +} + +bool DSP3_GetBits(uint8 Count) +{ + if (!DSP3_BitsLeft) + { + DSP3_BitsLeft = Count; + DSP3_ReqBits = 0; + } + + do { + if (!DSP3_BitCount) + { + DSP3_SR = 0xC0; + return false; + } + + DSP3_ReqBits <<= 1; + if (DSP3_ReqData & 0x8000) DSP3_ReqBits++; + DSP3_ReqData <<= 1; + + DSP3_BitCount--; + DSP3_BitsLeft--; + + } while (DSP3_BitsLeft); + + return true; +} + +void DSP3_Decode_Data() +{ + if (!DSP3_BitCount) + { + if (DSP3_SR & 0x40) + { + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + } + else + { + DSP3_SR = 0xC0; + return; + } + } + + if (DSP3_LZCode == 1) + { + if (!DSP3_GetBits(1)) + return; + + if (DSP3_ReqBits) + DSP3_LZLength = 12; + else + DSP3_LZLength = 8; + + DSP3_LZCode++; + } + + if (DSP3_LZCode == 2) + { + if (!DSP3_GetBits(DSP3_LZLength)) + return; + + DSP3_LZCode = 0; + DSP3_Outwords--; + if (!DSP3_Outwords) SetDSP3 = &DSP3_Reset; + + DSP3_SR = 0x80; + DSP3_DR = DSP3_ReqBits; + return; + } + + if (DSP3_BaseCode == 0xffff) + { + if (!DSP3_GetBits(DSP3_BaseLength)) + return; + + DSP3_BaseCode = DSP3_ReqBits; + } + + if (!DSP3_GetBits(DSP3_CodeLengths[DSP3_BaseCode])) + return; + + DSP3_Symbol = DSP3_Codes[DSP3_CodeOffsets[DSP3_BaseCode] + DSP3_ReqBits]; + DSP3_BaseCode = 0xffff; + + if (DSP3_Symbol & 0xff00) + { + DSP3_Symbol += 0x7f02; + DSP3_LZCode++; + } + else + { + DSP3_Outwords--; + if (!DSP3_Outwords) + SetDSP3 = &DSP3_Reset; + } + + DSP3_SR = 0x80; + DSP3_DR = DSP3_Symbol; +} + +void DSP3_Decode_Tree() +{ + if (!DSP3_BitCount) + { + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + } + + if (!DSP3_BaseCodes) + { + DSP3_GetBits(1); + if (DSP3_ReqBits) + { + DSP3_BaseLength = 3; + DSP3_BaseCodes = 8; + } + else + { + DSP3_BaseLength = 2; + DSP3_BaseCodes = 4; + } + } + + while (DSP3_BaseCodes) + { + if (!DSP3_GetBits(3)) + return; + + DSP3_ReqBits++; + + DSP3_CodeLengths[DSP3_Index] = (uint8) DSP3_ReqBits; + DSP3_CodeOffsets[DSP3_Index] = DSP3_Symbol; + DSP3_Index++; + + DSP3_Symbol += 1 << DSP3_ReqBits; + DSP3_BaseCodes--; + } + + DSP3_BaseCode = 0xffff; + DSP3_LZCode = 0; + + SetDSP3 = &DSP3_Decode_Data; + if (DSP3_BitCount) DSP3_Decode_Data(); +} + +void DSP3_Decode_Symbols() +{ + DSP3_ReqData = DSP3_DR; + DSP3_BitCount += 16; + + do { + + if (DSP3_BitCommand == 0xffff) + { + if (!DSP3_GetBits(2)) return; + DSP3_BitCommand = DSP3_ReqBits; + } + + switch (DSP3_BitCommand) + { + case 0: + { + if (!DSP3_GetBits(9)) return; + DSP3_Symbol = DSP3_ReqBits; + break; + } + case 1: + { + DSP3_Symbol++; + break; + } + case 2: + { + if (!DSP3_GetBits(1)) return; + DSP3_Symbol += 2 + DSP3_ReqBits; + break; + } + case 3: + { + if (!DSP3_GetBits(4)) return; + DSP3_Symbol += 4 + DSP3_ReqBits; + break; + } + } + + DSP3_BitCommand = 0xffff; + + DSP3_Codes[DSP3_Index++] = DSP3_Symbol; + DSP3_Codewords--; + + } while (DSP3_Codewords); + + DSP3_Index = 0; + DSP3_Symbol = 0; + DSP3_BaseCodes = 0; + + SetDSP3 = &DSP3_Decode_Tree; + if (DSP3_BitCount) DSP3_Decode_Tree(); +} + +void DSP3_Decode_A() +{ + DSP3_Outwords = DSP3_DR; + SetDSP3 = &DSP3_Decode_Symbols; + DSP3_BitCount = 0; + DSP3_BitsLeft = 0; + DSP3_Symbol = 0; + DSP3_Index = 0; + DSP3_BitCommand = 0xffff; + DSP3_SR = 0xC0; +} + +void DSP3_Decode() +{ + DSP3_Codewords = DSP3_DR; + SetDSP3 = &DSP3_Decode_A; +} + + +// Opcodes 1E/3E bit-perfect to 'dsp3-intro' log +// src: adapted from SD Gundam X/G-Next + +int16 op3e_x; +int16 op3e_y; + +int16 op1e_terrain[0x2000]; +int16 op1e_cost[0x2000]; +int16 op1e_weight[0x2000]; + +int16 op1e_cell; +int16 op1e_turn; +int16 op1e_search; + +int16 op1e_x; +int16 op1e_y; + +int16 op1e_min_radius; +int16 op1e_max_radius; + +int16 op1e_max_search_radius; +int16 op1e_max_path_radius; + +int16 op1e_lcv_radius; +int16 op1e_lcv_steps; +int16 op1e_lcv_turns; + +void DSP3_OP3E() +{ + op3e_x = (uint8)(DSP3_DR & 0x00ff); + op3e_y = (uint8)((DSP3_DR & 0xff00)>>8); + + DSP3_OP03(); + + op1e_terrain[ DSP3_DR ] = 0x00; + op1e_cost[ DSP3_DR ] = 0xff; + op1e_weight[ DSP3_DR ] = 0; + + op1e_max_search_radius = 0; + op1e_max_path_radius = 0; +} + +void DSP3_OP1E_A(); +void DSP3_OP1E_A1(); +void DSP3_OP1E_A2(); +void DSP3_OP1E_A3(); + +void DSP3_OP1E_B(); +void DSP3_OP1E_B1(); +void DSP3_OP1E_B2(); + +void DSP3_OP1E_C(); +void DSP3_OP1E_C1(); +void DSP3_OP1E_C2(); + +void DSP3_OP1E_D( int16, int16 *, int16 * ); +void DSP3_OP1E_D1( int16 move, int16 *lo, int16 *hi ); + +void DSP3_OP1E() +{ + int lcv; + + op1e_min_radius = (uint8)(DSP3_DR & 0x00ff); + op1e_max_radius = (uint8)((DSP3_DR & 0xff00)>>8); + + if( op1e_min_radius == 0 ) + op1e_min_radius++; + + if( op1e_max_search_radius >= op1e_min_radius ) + op1e_min_radius = op1e_max_search_radius+1; + + if( op1e_max_radius > op1e_max_search_radius ) + op1e_max_search_radius = op1e_max_radius; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_lcv_turns = 6; + op1e_turn = 0; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + + DSP3_OP1E_A(); +} + +void DSP3_OP1E_A() +{ + int lcv; + + if( op1e_lcv_steps == 0 ) { + op1e_lcv_radius++; + + op1e_lcv_steps = op1e_lcv_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_lcv_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_radius > op1e_max_radius ) { + op1e_turn++; + op1e_lcv_turns--; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_turns == 0 ) { + DSP3_DR = 0xffff; + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_B; + return; + } + + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_A1; +} + +void DSP3_OP1E_A1() +{ + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_A2; +} + +void DSP3_OP1E_A2() +{ + op1e_terrain[ op1e_cell ] = (uint8)(DSP3_DR & 0x00ff); + + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_A3; +} + +void DSP3_OP1E_A3() +{ + op1e_cost[ op1e_cell ] = (uint8)(DSP3_DR & 0x00ff); + + if( op1e_lcv_radius == 1 ) { + if( op1e_terrain[ op1e_cell ] & 1 ) { + op1e_weight[ op1e_cell ] = 0xff; + } else { + op1e_weight[ op1e_cell ] = op1e_cost[ op1e_cell ]; + } + } + else { + op1e_weight[ op1e_cell ] = 0xff; + } + + DSP3_OP1E_D( (int16)(op1e_turn+2), &op1e_x, &op1e_y ); + op1e_lcv_steps--; + + DSP3_SR = 0x0080; + DSP3_OP1E_A(); +} + + +void DSP3_OP1E_B() +{ + op1e_x = op3e_x; + op1e_y = op3e_y; + op1e_lcv_radius = 1; + + op1e_search = 0; + + DSP3_OP1E_B1(); + + SetDSP3 = &DSP3_OP1E_C; +} + + +void DSP3_OP1E_B1() +{ + while( op1e_lcv_radius < op1e_max_radius ) { + op1e_y--; + + op1e_lcv_turns = 6; + op1e_turn = 5; + + while( op1e_lcv_turns ) { + op1e_lcv_steps = op1e_lcv_radius; + + while( op1e_lcv_steps ) { + DSP3_OP1E_D1( op1e_turn, &op1e_x, &op1e_y ); + + if( 0 <= op1e_y && op1e_y < DSP3_WinHi && + 0 <= op1e_x && op1e_x < DSP3_WinLo ) { + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + if( op1e_cost[ op1e_cell ] < 0x80 && + op1e_terrain[ op1e_cell ] < 0x40 ) { + DSP3_OP1E_B2(); + } // end cell perimeter + } + + op1e_lcv_steps--; + } // end search line + + op1e_turn--; + if( op1e_turn == 0 ) op1e_turn = 6; + + op1e_lcv_turns--; + } // end circle search + + op1e_lcv_radius++; + } // end radius search +} + + +void DSP3_OP1E_B2() +{ + int16 cell; + int16 path; + int16 x,y; + int16 lcv_turns; + + path = 0xff; + lcv_turns = 6; + + while( lcv_turns ) { + x = op1e_x; + y = op1e_y; + + DSP3_OP1E_D1( lcv_turns, &x, &y ); + + DSP3_DR = (uint8)(x) | ((uint8)(y)<<8); + DSP3_OP03(); + + cell = DSP3_DR; + + if( 0 <= y && y < DSP3_WinHi && + 0 <= x && x < DSP3_WinLo ) { + + if( op1e_terrain[ cell ] < 0x80 || op1e_weight[ cell ] == 0 ) { + if( op1e_weight[ cell ] < path ) { + path = op1e_weight[ cell ]; + } + } + } // end step travel + + lcv_turns--; + } // end while turns + + if( path != 0xff ) { + op1e_weight[ op1e_cell ] = path + op1e_cost[ op1e_cell ]; + } +} + + +void DSP3_OP1E_C() +{ + int lcv; + + op1e_min_radius = (uint8)(DSP3_DR & 0x00ff); + op1e_max_radius = (uint8)((DSP3_DR & 0xff00)>>8); + + if( op1e_min_radius == 0 ) + op1e_min_radius++; + + if( op1e_max_path_radius >= op1e_min_radius ) + op1e_min_radius = op1e_max_path_radius+1; + + if( op1e_max_radius > op1e_max_path_radius ) + op1e_max_path_radius = op1e_max_radius; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_lcv_turns = 6; + op1e_turn = 0; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + + DSP3_OP1E_C1(); +} + + +void DSP3_OP1E_C1() +{ + int lcv; + + if( op1e_lcv_steps == 0 ) { + op1e_lcv_radius++; + + op1e_lcv_steps = op1e_lcv_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_lcv_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_radius > op1e_max_radius ) { + op1e_turn++; + op1e_lcv_turns--; + + op1e_lcv_radius = op1e_min_radius; + op1e_lcv_steps = op1e_min_radius; + + op1e_x = op3e_x; + op1e_y = op3e_y; + + for( lcv = 0; lcv < op1e_min_radius; lcv++ ) + DSP3_OP1E_D( op1e_turn, &op1e_x, &op1e_y ); + } + + if( op1e_lcv_turns == 0 ) { + DSP3_DR = 0xffff; + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_Reset; + return; + } + + DSP3_DR = (uint8)(op1e_x) | ((uint8)(op1e_y)<<8); + DSP3_OP03(); + + op1e_cell = DSP3_DR; + + DSP3_SR = 0x0080; + SetDSP3 = &DSP3_OP1E_C2; +} + + +void DSP3_OP1E_C2() +{ + DSP3_DR = op1e_weight[ op1e_cell ]; + + DSP3_OP1E_D( (int16)(op1e_turn+2), &op1e_x, &op1e_y ); + op1e_lcv_steps--; + + DSP3_SR = 0x0084; + SetDSP3 = &DSP3_OP1E_C1; +} + + +void DSP3_OP1E_D( int16 move, int16 *lo, int16 *hi ) +{ + uint32 dataOfs = ((move << 1) + 0x03b2) & 0x03ff; + int16 Lo; + int16 Hi; + + DSP3_AddHi = DSP3_DataROM[dataOfs]; + DSP3_AddLo = DSP3_DataROM[dataOfs + 1]; + + Lo = (uint8)(*lo); + Hi = (uint8)(*hi); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + if (DSP3_AddLo < 0) + DSP3_AddLo += DSP3_WinLo; + else + if (DSP3_AddLo >= DSP3_WinLo) + DSP3_AddLo -= DSP3_WinLo; + + if (DSP3_AddHi < 0) + DSP3_AddHi += DSP3_WinHi; + else + if (DSP3_AddHi >= DSP3_WinHi) + DSP3_AddHi -= DSP3_WinHi; + + *lo = DSP3_AddLo; + *hi = DSP3_AddHi; +} + + +void DSP3_OP1E_D1( int16 move, int16 *lo, int16 *hi ) +{ +#ifndef NGC + uint32 dataOfs = ((move << 1) + 0x03b2) & 0x03ff; +#endif + int16 Lo; + int16 Hi; + + const unsigned short HiAdd[] = { + 0x00, 0xFF, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0xFF, 0x00 + }; + const unsigned short LoAdd[] = { + 0x00, 0x00, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x00 + }; + + if( (*lo) & 1 ) + DSP3_AddHi = HiAdd[ move + 8 ]; + else + DSP3_AddHi = HiAdd[ move + 0 ]; + DSP3_AddLo = LoAdd[ move ]; + + Lo = (uint8)(*lo); + Hi = (uint8)(*hi); + + if (Lo & 1) Hi += (DSP3_AddLo & 1); + + DSP3_AddLo += Lo; + DSP3_AddHi += Hi; + + *lo = DSP3_AddLo; + *hi = DSP3_AddHi; +} + + +void DSP3_OP10() +{ + if( DSP3_DR == 0xffff ) { + DSP3_Reset(); + } else { + // absorb 2 bytes + DSP3_DR = DSP3_DR; + } +} + + +void DSP3_OP0C_A() +{ + // absorb 2 bytes + + DSP3_DR = 0; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP0C() +{ + // absorb 2 bytes + + DSP3_DR = 0; + //SetDSP3 = &DSP3_OP0C_A; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP1C_C() +{ + // return 2 bytes + DSP3_DR = 0; + SetDSP3 = &DSP3_Reset; +} + + +void DSP3_OP1C_B() +{ + // absorb 2 bytes + + // return 2 bytes + DSP3_DR = 0; + SetDSP3 = &DSP3_OP1C_C; +} + + +void DSP3_OP1C_A() +{ + // absorb 2 bytes + + SetDSP3 = &DSP3_OP1C_B; +} + + +void DSP3_OP1C() +{ + // absorb 2 bytes + + SetDSP3 = &DSP3_OP1C_A; +} + + +void DSP3_Command() +{ + if (DSP3_DR < 0x40) + { + switch (DSP3_DR) + { + case 0x02: SetDSP3 = &DSP3_Coordinate; break; + case 0x03: SetDSP3 = &DSP3_OP03; break; + case 0x06: SetDSP3 = &DSP3_OP06; break; + case 0x07: SetDSP3 = &DSP3_OP07; return; + case 0x0c: SetDSP3 = &DSP3_OP0C; break; + case 0x0f: SetDSP3 = &DSP3_TestMemory; break; + case 0x10: SetDSP3 = &DSP3_OP10; break; + case 0x18: SetDSP3 = &DSP3_Convert; break; + case 0x1c: SetDSP3 = &DSP3_OP1C; break; + case 0x1e: SetDSP3 = &DSP3_OP1E; break; + case 0x1f: SetDSP3 = &DSP3_MemoryDump; break; + case 0x38: SetDSP3 = &DSP3_Decode; break; + case 0x3e: SetDSP3 = &DSP3_OP3E; break; + default: + return; + } + DSP3_SR = 0x0080; + DSP3_Index = 0; + } +} + +void DSP3SetByte(uint8 byte, uint16 address) +{ + if ((address & 0xC000) == 0x8000) + { + if (DSP3_SR & 0x04) + { + DSP3_DR = (DSP3_DR & 0xff00) + byte; + (*SetDSP3)(); + } + else + { + DSP3_SR ^= 0x10; + + if (DSP3_SR & 0x10) + DSP3_DR = (DSP3_DR & 0xff00) + byte; + else + { + DSP3_DR = (DSP3_DR & 0x00ff) + (byte << 8); + (*SetDSP3)(); + } + } + } +} + +uint8 DSP3GetByte(uint16 address) +{ + if ((address & 0xC000) == 0x8000) + { + uint8 byte; + + if (DSP3_SR & 0x04) + { + byte = (uint8) DSP3_DR; + (*SetDSP3)(); + } + else + { + DSP3_SR ^= 0x10; + + if (DSP3_SR & 0x10) + byte = (uint8) (DSP3_DR); + else + { + byte = (uint8) (DSP3_DR >> 8); + (*SetDSP3)(); + } + } + + return byte; + } + + return (uint8) DSP3_SR; +} diff --git a/source/snes9x/dsp4emu.c.inc b/source/snes9x/dsp4emu.c.inc new file mode 100644 index 0000000..29a1696 --- /dev/null +++ b/source/snes9x/dsp4emu.c.inc @@ -0,0 +1,2377 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include + + + +/* +Due recognition and credit are given on Overload's DSP website. +Thank those contributors for their hard work on this chip. + + +Fixed-point math reminder: + +[sign, integer, fraction] +1.15.00 * 1.15.00 = 2.30.00 -> 1.30.00 (DSP) -> 1.31.00 (LSB is '0') +1.15.00 * 1.00.15 = 2.15.15 -> 1.15.15 (DSP) -> 1.15.16 (LSB is '0') +*/ + +typedef struct +{ + bool8 waiting4command; + bool8 half_command; + uint16 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters[512]; + uint8 output[512]; +} SDSP4; + +SDSP4 DSP4; + +//Todo: get all of this into a struct for easy save stating + +// op control +int8 DSP4_Logic; // controls op flow + + +// projection format +int16 lcv; // loop-control variable +int16 distance; // z-position into virtual world +int16 raster; // current raster line +int16 segments; // number of raster lines drawn + +// 1.15.16 or 1.15.0 [sign, integer, fraction] +int32 world_x; // line of x-projection in world +int32 world_y; // line of y-projection in world +int32 world_dx; // projection line x-delta +int32 world_dy; // projection line y-delta +int16 world_ddx; // x-delta increment +int16 world_ddy; // y-delta increment +int32 world_xenv; // world x-shaping factor +int16 world_yofs; // world y-vertical scroll + +int16 view_x1; // current viewer-x +int16 view_y1; // current viewer-y +int16 view_x2; // future viewer-x +int16 view_y2; // future viewer-y +int16 view_dx; // view x-delta factor +int16 view_dy; // view y-delta factor +int16 view_xofs1; // current viewer x-vertical scroll +int16 view_yofs1; // current viewer y-vertical scroll +int16 view_xofs2; // future viewer x-vertical scroll +int16 view_yofs2; // future viewer y-vertical scroll +int16 view_yofsenv; // y-scroll shaping factor +int16 view_turnoff_x; // road turnoff data +int16 view_turnoff_dx; // road turnoff delta factor + + +// drawing area + +int16 viewport_cx; // x-center of viewport window +int16 viewport_cy; // y-center of render window +int16 viewport_left; // x-left of viewport +int16 viewport_right; // x-right of viewport +int16 viewport_top; // y-top of viewport +int16 viewport_bottom; // y-bottom of viewport + + +// sprite structure + +int16 sprite_x; // projected x-pos of sprite +int16 sprite_y; // projected y-pos of sprite +int16 sprite_attr; // obj attributes +bool8 sprite_size; // sprite size: 8x8 or 16x16 +int16 sprite_clipy; // visible line to clip pixels off +int16 sprite_count; + + +// generic projection variables designed for +// two solid polygons + two polygon sides + +int16 poly_clipLf[2][2]; // left clip boundary +int16 poly_clipRt[2][2]; // right clip boundary +int16 poly_ptr[2][2]; // HDMA structure pointers +int16 poly_raster[2][2]; // current raster line below horizon +int16 poly_top[2][2]; // top clip boundary +int16 poly_bottom[2][2]; // bottom clip boundary +int16 poly_cx[2][2]; // center for left/right points +int16 poly_start[2]; // current projection points +int16 poly_plane[2]; // previous z-plane distance + + +// OAM +int16 OAM_attr[16]; // OAM (size,MSB) data +int16 OAM_index; // index into OAM table +int16 OAM_bits; // offset into OAM table + +int16 OAM_RowMax; // maximum number of tiles per 8 aligned pixels (row) +int16 OAM_Row[32]; // current number of tiles per row + +////////////////////////////////////////////////////////////// + +// input protocol + +static int16 DSP4_READ_WORD() +{ + int16 out; + + out = READ_WORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 2; + + return out; +} + +static int32 DSP4_READ_DWORD() +{ + int32 out; + + out = READ_DWORD(DSP4.parameters + DSP4.in_index); + DSP4.in_index += 4; + + return out; +} + + +////////////////////////////////////////////////////////////// + +// output protocol + +#define DSP4_CLEAR_OUT() \ +{ DSP4.out_count = 0; DSP4.out_index = 0; } + +#define DSP4_WRITE_BYTE( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count++; } + +#define DSP4_WRITE_WORD( d ) \ +{ WRITE_WORD( DSP4.output + DSP4.out_count, ( d ) ); DSP4.out_count += 2; } + +#ifndef MSB_FIRST +#define DSP4_WRITE_16_WORD( d ) \ +{ memcpy(DSP4.output + DSP4.out_count, ( d ), 32); DSP4.out_count += 32; } +#else +#define DSP4_WRITE_16_WORD( d ) \ +{ for (int p = 0; p < 16; p++) DSP4_WRITE_WORD((d)[p]); } +#endif + +#ifdef PRINT_OP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +#ifdef DEBUG_DSP +#define DSP4_WRITE_DEBUG( x, d ) \ + WRITE_WORD( nop + x, d ); +#endif + +////////////////////////////////////////////////////////////// + +// used to wait for dsp i/o + +#define DSP4_WAIT( x ) \ + DSP4.in_index = 0; DSP4_Logic = x; return; + +////////////////////////////////////////////////////////////// + +// 1.7.8 -> 1.15.16 +#define SEX78( a ) ( ( (int32) ( (int16) (a) ) ) << 8 ) + +// 1.15.0 -> 1.15.16 +#define SEX16( a ) ( ( (int32) ( (int16) (a) ) ) << 16 ) + +#ifdef PRINT_OP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +#ifdef DEBUG_DSP +#define U16( a ) ( (uint16) ( a ) ) +#endif + +////////////////////////////////////////////////////////////// + +// Attention: This lookup table is not verified +const uint16 div_lut[64] = { 0x0000, 0x8000, 0x4000, 0x2aaa, 0x2000, 0x1999, 0x1555, 0x1249, 0x1000, 0x0e38, + 0x0ccc, 0x0ba2, 0x0aaa, 0x09d8, 0x0924, 0x0888, 0x0800, 0x0787, 0x071c, 0x06bc, + 0x0666, 0x0618, 0x05d1, 0x0590, 0x0555, 0x051e, 0x04ec, 0x04bd, 0x0492, 0x0469, + 0x0444, 0x0421, 0x0400, 0x03e0, 0x03c3, 0x03a8, 0x038e, 0x0375, 0x035e, 0x0348, + 0x0333, 0x031f, 0x030c, 0x02fa, 0x02e8, 0x02d8, 0x02c8, 0x02b9, 0x02aa, 0x029c, + 0x028f, 0x0282, 0x0276, 0x026a, 0x025e, 0x0253, 0x0249, 0x023e, 0x0234, 0x022b, + 0x0222, 0x0219, 0x0210, 0x0208, }; + +int16 DSP4_Inverse(int16 value) +{ + // saturate bounds + if (value < 0) + { + value = 0; + } + if (value > 63) + { + value = 63; + } + + return div_lut[value]; +} + +////////////////////////////////////////////////////////////// + +// Prototype +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop); + +////////////////////////////////////////////////////////////// + +// OP00 +void DSP4_Multiply(int16 Multiplicand, int16 Multiplier, int32 *Product) +{ + *Product = (Multiplicand * Multiplier << 1) >> 1; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP01() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + world_y = DSP4_READ_DWORD(); + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_top[0][0] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + world_x = DSP4_READ_DWORD(); + poly_cx[0][0] = DSP4_READ_WORD(); + poly_ptr[0][0] = DSP4_READ_WORD(); + world_yofs = DSP4_READ_WORD(); + world_dy = DSP4_READ_DWORD(); + world_dx = DSP4_READ_DWORD(); + distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + world_xenv = DSP4_READ_DWORD(); + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting raster line + view_x1 = (world_x + world_xenv) >> 16; + view_y1 = world_y >> 16; + view_xofs1 = world_x >> 16; + view_yofs1 = world_yofs; + view_turnoff_x = 0; + view_turnoff_dx = 0; + + // first raster line + poly_raster[0][0] = poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + view_x2 = ( ( ( world_x + world_xenv ) >> 16 ) * distance >> 15 ) + ( view_turnoff_x * distance >> 15 ); + view_y2 = (world_y >> 16) * distance >> 15; + view_xofs2 = view_x2; + view_yofs2 = (world_yofs * distance >> 15) + poly_bottom[0][0] - view_y2; + + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((world_x + world_xenv) >> 16); + DSP4_WRITE_WORD(view_x2); + DSP4_WRITE_WORD(world_y >> 16); + DSP4_WRITE_WORD(view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of raster lines used + segments = poly_raster[0][0] - view_y2; + + // prevent overdraw + if (view_y2 >= poly_raster[0][0]) + segments = 0; + else + poly_raster[0][0] = view_y2; + + // don't draw outside the window + if (view_y2 < poly_top[0][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y1 >= poly_top[0][0]) + segments = view_y1 - poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (view_xofs2 - view_xofs1) * DSP4_Inverse(segments) << 1; + py_dy = (view_yofs2 - view_yofs1) * DSP4_Inverse(segments) << 1; + + // starting step values + x_scroll = SEX16(poly_cx[0][0] + view_xofs1); + y_scroll = SEX16(-viewport_bottom + view_yofs1 + view_yofsenv + poly_cx[1][0] - world_yofs); + + // SR = 0x80 + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(poly_ptr[0][0]); + DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); + DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); + + + // update memory address + poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last raster line drawn + view_x1 = view_x2; + view_y1 = view_y2; + view_xofs1 = view_xofs2; + view_yofs1 = view_yofs2; + + // add deltas for projection lines + world_dx += SEX78(world_ddx); + world_dy += SEX78(world_ddy); + + // update projection lines + world_x += (world_dx + world_xenv); + world_y += world_dy; + + // update road turnoff position + view_turnoff_x += view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for termination + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + break; + + // road turnoff + if( (uint16) distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + distance = DSP4_READ_WORD(); + view_turnoff_x = DSP4_READ_WORD(); + view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + view_x1 += ( view_turnoff_x * distance >> 15 ); + view_xofs1 += ( view_turnoff_x * distance >> 15 ); + + // update stepping values + view_turnoff_x += view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(1) + } + + // already have 2 bytes read + DSP4.in_count = 6; + DSP4_WAIT(3) resume3 : + + // inspect inputs + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP03() +{ + OAM_RowMax = 33; + memset(OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + + +void DSP4_OP05() +{ + OAM_index = 0; + OAM_bits = 0; + memset(OAM_attr, 0, 32); + sprite_count = 0; +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP06() +{ + DSP4_CLEAR_OUT(); + DSP4_WRITE_16_WORD(OAM_attr); +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP07() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + world_y = DSP4_READ_DWORD(); + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_top[0][0] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + world_x = DSP4_READ_DWORD(); + poly_cx[0][0] = DSP4_READ_WORD(); + poly_ptr[0][0] = DSP4_READ_WORD(); + world_yofs = DSP4_READ_WORD(); + distance = DSP4_READ_WORD(); + view_y2 = DSP4_READ_WORD(); + view_dy = DSP4_READ_WORD() * distance >> 15; + view_x2 = DSP4_READ_WORD(); + view_dx = DSP4_READ_WORD() * distance >> 15; + view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting raster line + view_x1 = world_x >> 16; + view_y1 = world_y >> 16; + view_xofs1 = view_x1; + view_yofs1 = world_yofs; + + // first raster line + poly_raster[0][0] = poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + view_x2 += view_dx; + view_y2 += view_dy; + + // vertical scroll calculation + view_xofs2 = view_x2; + view_yofs2 = (world_yofs * distance >> 15) + poly_bottom[0][0] - view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(view_x2); + DSP4_WRITE_WORD(view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of raster lines used + segments = view_y1 - view_y2; + + // prevent overdraw + if (view_y2 >= poly_raster[0][0]) + segments = 0; + else + poly_raster[0][0] = view_y2; + + // don't draw outside the window + if (view_y2 < poly_top[0][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y1 >= poly_top[0][0]) + segments = view_y1 - poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (view_xofs2 - view_xofs1) * DSP4_Inverse(segments) << 1; + py_dy = (view_yofs2 - view_yofs1) * DSP4_Inverse(segments) << 1; + + // starting step values + x_scroll = SEX16(poly_cx[0][0] + view_xofs1); + y_scroll = SEX16(-viewport_bottom + view_yofs1 + view_yofsenv + poly_cx[1][0] - world_yofs); + + // SR = 0x80 + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(poly_ptr[0][0]); + DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); + DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); + + // update memory address + poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last raster line drawn + view_x1 = view_x2; + view_y1 = view_y2; + view_xofs1 = view_xofs2; + view_yofs1 = view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // check for opcode termination + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(2) resume2 : + + // inspect inputs + view_y2 = DSP4_READ_WORD(); + view_dy = DSP4_READ_WORD() * distance >> 15; + view_x2 = DSP4_READ_WORD(); + view_dx = DSP4_READ_WORD() * distance >> 15; + view_yofsenv = DSP4_READ_WORD(); + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP08() +{ + int16 win_left, win_right; + int16 view_x[2], view_y[2]; + int16 envelope[2][2]; + + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs for two polygons + + // clip values + poly_clipRt[0][0] = DSP4_READ_WORD(); + poly_clipRt[0][1] = DSP4_READ_WORD(); + poly_clipRt[1][0] = DSP4_READ_WORD(); + poly_clipRt[1][1] = DSP4_READ_WORD(); + + poly_clipLf[0][0] = DSP4_READ_WORD(); + poly_clipLf[0][1] = DSP4_READ_WORD(); + poly_clipLf[1][0] = DSP4_READ_WORD(); + poly_clipLf[1][1] = DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A6, $00A6, $00A6, $00A6) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // unknown (constant) (ex. 1P/2P = $00A5, $00A5, $00A7, $00A7) + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // polygon centering (left,right) + poly_cx[0][0] = DSP4_READ_WORD(); + poly_cx[0][1] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + poly_cx[1][1] = DSP4_READ_WORD(); + + // HDMA pointer locations + poly_ptr[0][0] = DSP4_READ_WORD(); + poly_ptr[0][1] = DSP4_READ_WORD(); + poly_ptr[1][0] = DSP4_READ_WORD(); + poly_ptr[1][1] = DSP4_READ_WORD(); + + // starting raster line below the horizon + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_bottom[0][1] = DSP4_READ_WORD(); + poly_bottom[1][0] = DSP4_READ_WORD(); + poly_bottom[1][1] = DSP4_READ_WORD(); + + // top boundary line to clip + poly_top[0][0] = DSP4_READ_WORD(); + poly_top[0][1] = DSP4_READ_WORD(); + poly_top[1][0] = DSP4_READ_WORD(); + poly_top[1][1] = DSP4_READ_WORD(); + + // unknown + // (ex. 1P = $2FC8, $0034, $FF5C, $0035) + // + // (ex. 2P = $3178, $0034, $FFCC, $0035) + // (ex. 2P = $2FC8, $0034, $FFCC, $0035) + + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + DSP4_READ_WORD(); + + // look at guidelines for both polygon shapes + distance = DSP4_READ_WORD(); + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + // starting base values to project from + poly_start[0] = view_x[0]; + poly_start[1] = view_x[1]; + + // starting raster lines to begin drawing + poly_raster[0][0] = view_y[0]; + poly_raster[0][1] = view_y[0]; + poly_raster[1][0] = view_y[1]; + poly_raster[1][1] = view_y[1]; + + // starting distances + poly_plane[0] = distance; + poly_plane[1] = distance; + + // SR = 0x00 + + // re-center coordinates + win_left = poly_cx[0][0] - view_x[0] + envelope[0][0]; + win_right = poly_cx[0][1] - view_x[0] + envelope[0][1]; + + // saturate offscreen data for polygon #1 + if (win_left < poly_clipLf[0][0]) + { + win_left = poly_clipLf[0][0]; + } + if (win_left > poly_clipRt[0][0]) + { + win_left = poly_clipRt[0][0]; + } + if (win_right < poly_clipLf[0][1]) + { + win_right = poly_clipLf[0][1]; + } + if (win_right > poly_clipRt[0][1]) + { + win_right = poly_clipRt[0][1]; + } + + // SR = 0x80 + + // initial output for polygon #1 + DSP4_CLEAR_OUT(); + DSP4_WRITE_BYTE(win_left & 0xff); + DSP4_WRITE_BYTE(win_right & 0xff); + + + do + { + int16 polygon; + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // terminate op + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 16; + + DSP4_WAIT(2) resume2 : + + // look at guidelines for both polygon shapes + view_x[0] = DSP4_READ_WORD(); + view_y[0] = DSP4_READ_WORD(); + view_x[1] = DSP4_READ_WORD(); + view_y[1] = DSP4_READ_WORD(); + + // envelope shaping guidelines (one frame only) + envelope[0][0] = DSP4_READ_WORD(); + envelope[0][1] = DSP4_READ_WORD(); + envelope[1][0] = DSP4_READ_WORD(); + envelope[1][1] = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // projection begins + + // init + DSP4_CLEAR_OUT(); + + + ////////////////////////////////////////////// + // solid polygon renderer - 2 shapes + + for (polygon = 0; polygon < 2; polygon++) + { + int32 left_inc, right_inc; + int16 x1_final, x2_final; + int16 env[2][2]; + int16 poly; + + // SR = 0x00 + + // # raster lines to draw + segments = poly_raster[polygon][0] - view_y[polygon]; + + // prevent overdraw + if (segments > 0) + { + // bump drawing cursor + poly_raster[polygon][0] = view_y[polygon]; + poly_raster[polygon][1] = view_y[polygon]; + } + else + segments = 0; + + // don't draw outside the window + if (view_y[polygon] < poly_top[polygon][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y[polygon] >= poly_top[polygon][0]) + segments = view_y[polygon] - poly_top[polygon][0]; + } + + // SR = 0x80 + + // tell user how many raster structures to read in + DSP4_WRITE_WORD(segments); + + // normal parameters + poly = polygon; + + ///////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 win_left, win_right; + + // road turnoff selection + if( (uint16) envelope[ polygon ][ 0 ] == (uint16) 0xc001 ) + poly = 1; + else if( envelope[ polygon ][ 1 ] == 0x3fff ) + poly = 1; + + /////////////////////////////////////////////// + // left side of polygon + + // perspective correction on additional shaping parameters + env[0][0] = envelope[polygon][0] * poly_plane[poly] >> 15; + env[0][1] = envelope[polygon][0] * distance >> 15; + + // project new shapes (left side) + x1_final = view_x[poly] + env[0][0]; + x2_final = poly_start[poly] + env[0][1]; + + // interpolate between projected points with shaping + left_inc = (x2_final - x1_final) * DSP4_Inverse(segments) << 1; + if (segments == 1) + left_inc = -left_inc; + + /////////////////////////////////////////////// + // right side of polygon + + // perspective correction on additional shaping parameters + env[1][0] = envelope[polygon][1] * poly_plane[poly] >> 15;; + env[1][1] = envelope[polygon][1] * distance >> 15; + + // project new shapes (right side) + x1_final = view_x[poly] + env[1][0]; + x2_final = poly_start[poly] + env[1][1]; + + + // interpolate between projected points with shaping + right_inc = (x2_final - x1_final) * DSP4_Inverse(segments) << 1; + if (segments == 1) + right_inc = -right_inc; + + /////////////////////////////////////////////// + // update each point on the line + + win_left = SEX16(poly_cx[polygon][0] - poly_start[poly] + env[0][0]); + win_right = SEX16(poly_cx[polygon][1] - poly_start[poly] + env[1][0]); + + // update distance drawn into world + poly_plane[polygon] = distance; + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + int16 x_left, x_right; + + // project new coordinates + win_left += left_inc; + win_right += right_inc; + + // grab integer portion, drop fraction (no rounding) + x_left = win_left >> 16; + x_right = win_right >> 16; + + // saturate offscreen data + if (x_left < poly_clipLf[polygon][0]) + x_left = poly_clipLf[polygon][0]; + if (x_left > poly_clipRt[polygon][0]) + x_left = poly_clipRt[polygon][0]; + if (x_right < poly_clipLf[polygon][1]) + x_right = poly_clipLf[polygon][1]; + if (x_right > poly_clipRt[polygon][1]) + x_right = poly_clipRt[polygon][1]; + + // 1. HDMA memory pointer + // 2. Left window position ($2126/$2128) + // 3. Right window position ($2127/$2129) + + DSP4_WRITE_WORD(poly_ptr[polygon][0]); + DSP4_WRITE_BYTE(x_left & 0xff); + DSP4_WRITE_BYTE(x_right & 0xff); + + + // update memory pointers + poly_ptr[polygon][0] -= 4; + poly_ptr[polygon][1] -= 4; + } // end rasterize line + } + + //////////////////////////////////////////////// + // Post-update + + // new projection spot to continue rasterizing from + poly_start[polygon] = view_x[poly]; + } // end polygon rasterizer + } + while (1); + + // unknown output + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(0); + + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP09() +{ + 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; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // grab screen information + viewport_cx = DSP4_READ_WORD(); + viewport_cy = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + viewport_left = DSP4_READ_WORD(); + viewport_right = DSP4_READ_WORD(); + viewport_top = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + + // starting raster line below the horizon + poly_bottom[0][0] = viewport_bottom - viewport_cy; + poly_raster[0][0] = 0x100; + + do + { + //////////////////////////////////////////////////// + // check for new sprites + + DSP4.in_count = 4; + DSP4_WAIT(1) resume1 : + + //////////////////////////////////////////////// + // raster overdraw check + + raster = DSP4_READ_WORD(); + + // continue updating the raster line where overdraw begins + if (raster < poly_raster[0][0]) + { + sprite_clipy = viewport_bottom - (poly_bottom[0][0] - raster); + poly_raster[0][0] = raster; + } + + ///////////////////////////////////////////////// + // identify sprite + + // op termination + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + goto terminate; + + + // no sprite + if (distance == 0x0000) + { + continue; + } + + //////////////////////////////////////////////////// + // process projection information + + // vehicle sprite + if ((uint16) distance == 0x9000) + { + int16 car_left, car_right, car_back; + int16 impact_left, impact_back; + int16 world_spx, world_spy; + int16 view_spx, view_spy; + uint16 energy; + + // we already have 4 bytes we want + DSP4.in_count = 14; + DSP4_WAIT(2) resume2 : + + // filter inputs + energy = DSP4_READ_WORD(); + impact_back = DSP4_READ_WORD(); + car_back = DSP4_READ_WORD(); + impact_left = DSP4_READ_WORD(); + car_left = DSP4_READ_WORD(); + distance = DSP4_READ_WORD(); + car_right = DSP4_READ_WORD(); + + // calculate car's world (x,y) values + world_spx = car_right - car_left; + world_spy = car_back; + + // add in collision vector [needs bit-twiddling] + world_spx -= energy * (impact_left - car_left) >> 16; + world_spy -= energy * (car_back - impact_back) >> 16; + + // perspective correction for world (x,y) + view_spx = world_spx * distance >> 15; + view_spy = world_spy * distance >> 15; + + // convert to screen values + sprite_x = viewport_cx + view_spx; + sprite_y = viewport_bottom - (poly_bottom[0][0] - view_spy); + + // make the car's (x)-coordinate available + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(world_spx); + + // grab a few remaining vehicle values + DSP4.in_count = 4; + DSP4_WAIT(3) resume3 : + + // add vertical lift factor + sprite_y += DSP4_READ_WORD(); + } + // terrain sprite + else + { + int16 world_spx, world_spy; + int16 view_spx, view_spy; + + // we already have 4 bytes we want + DSP4.in_count = 10; + DSP4_WAIT(4) resume4 : + + // sort loop inputs + poly_cx[0][0] = DSP4_READ_WORD(); + poly_raster[0][1] = DSP4_READ_WORD(); + world_spx = DSP4_READ_WORD(); + world_spy = DSP4_READ_WORD(); + + // compute base raster line from the bottom + segments = poly_bottom[0][0] - raster; + + // perspective correction for world (x,y) + view_spx = world_spx * distance >> 15; + view_spy = world_spy * distance >> 15; + + // convert to screen values + sprite_x = viewport_cx + view_spx - poly_cx[0][0]; + sprite_y = viewport_bottom - segments + view_spy; + } + + // default sprite size: 16x16 + sprite_size = 1; + sprite_attr = DSP4_READ_WORD(); + + //////////////////////////////////////////////////// + // convert tile data to SNES OAM format + + do + { + uint16 header; + + int16 sp_x, sp_y, sp_attr, sp_dattr; + int16 sp_dx, sp_dy; + int16 pixels; + + bool8 draw; + + DSP4.in_count = 2; + DSP4_WAIT(5) resume5 : + + draw = TRUE; + + // opcode termination + raster = DSP4_READ_WORD(); + if (raster == -0x8000) + goto terminate; + + // stop code + if (raster == 0x0000 && !sprite_size) + break; + + // toggle sprite size + if (raster == 0x0000) + { + sprite_size = !sprite_size; + continue; + } + + // check for valid sprite header + header = raster; + header >>= 8; + if (header != 0x20 && + header != 0x2e && //This is for attractor sprite + header != 0x40 && + header != 0x60 && + header != 0xa0 && + header != 0xc0 && + header != 0xe0) + break; + + // read in rest of sprite data + DSP4.in_count = 4; + DSP4_WAIT(6) resume6 : + + draw = TRUE; + + ///////////////////////////////////// + // process tile data + + // sprite deltas + sp_dattr = raster; + sp_dy = DSP4_READ_WORD(); + sp_dx = DSP4_READ_WORD(); + + // update coordinates to screen space + sp_x = sprite_x + sp_dx; + sp_y = sprite_y + sp_dy; + + // update sprite nametable/attribute information + sp_attr = sprite_attr + sp_dattr; + + // allow partially visibile tiles + pixels = sprite_size ? 15 : 7; + + DSP4_CLEAR_OUT(); + + // transparent tile to clip off parts of a sprite (overdraw) + if (sprite_clipy - pixels <= sp_y && + sp_y <= sprite_clipy && + sp_x >= viewport_left - pixels && + sp_x <= viewport_right && + sprite_clipy >= viewport_top - pixels && + sprite_clipy <= viewport_bottom) + { + DSP4_OP0B(&draw, sp_x, sprite_clipy, 0x00EE, sprite_size, 0); + } + + + // normal sprite tile + if (sp_x >= viewport_left - pixels && + sp_x <= viewport_right && + sp_y >= viewport_top - pixels && + sp_y <= viewport_bottom && + sp_y <= sprite_clipy) + { + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, sprite_size, 0); + } + + + // no following OAM data + DSP4_OP0B(&draw, 0, 0x0100, 0, 0, 1); + } + while (1); + } + while (1); + + terminate : DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +const uint16 OP0A_Values[16] = { 0x0000, 0x0030, 0x0060, 0x0090, 0x00c0, 0x00f0, 0x0120, 0x0150, 0xfe80, + 0xfeb0, 0xfee0, 0xff10, 0xff40, 0xff70, 0xffa0, 0xffd0 }; + +void DSP4_OP0A(int16 n2, int16 *o1, int16 *o2, int16 *o3, int16 *o4) +{ + *o4 = OP0A_Values[(n2 & 0x000f)]; + *o3 = OP0A_Values[(n2 & 0x00f0) >> 4]; + *o2 = OP0A_Values[(n2 & 0x0f00) >> 8]; + *o1 = OP0A_Values[(n2 & 0xf000) >> 12]; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0B(bool8 *draw, int16 sp_x, int16 sp_y, int16 sp_attr, bool8 size, bool8 stop) +{ + int16 Row1, Row2; + + // SR = 0x00 + + // align to nearest 8-pixel row + Row1 = (sp_y >> 3) & 0x1f; + Row2 = (Row1 + 1) & 0x1f; + + // check boundaries + if (!((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb))) + { + *draw = 0; + } + if (size) + { + if (OAM_Row[Row1] + 1 >= OAM_RowMax) + *draw = 0; + if (OAM_Row[Row2] + 1 >= OAM_RowMax) + *draw = 0; + } + else + { + if (OAM_Row[Row1] >= OAM_RowMax) + { + *draw = 0; + } + } + + // emulator fail-safe (unknown if this really exists) + if (sprite_count >= 128) + { + *draw = 0; + } + + // SR = 0x80 + + if (*draw) + { + // Row tiles + if (size) + { + OAM_Row[Row1] += 2; + OAM_Row[Row2] += 2; + } + else + { + OAM_Row[Row1]++; + } + + // yield OAM output + DSP4_WRITE_WORD(1); + + // pack OAM data: x,y,name,attr + DSP4_WRITE_BYTE(sp_x & 0xff); + DSP4_WRITE_BYTE(sp_y & 0xff); + DSP4_WRITE_WORD(sp_attr); + + sprite_count++; + + // OAM: size,msb data + // save post-oam table data for future retrieval + OAM_attr[OAM_index] |= ((sp_x <0 || sp_x> 255) << OAM_bits); + OAM_bits++; + + OAM_attr[OAM_index] |= (size << OAM_bits); + OAM_bits++; + + // move to next byte in buffer + if (OAM_bits == 16) + { + OAM_bits = 0; + OAM_index++; + } + } + else if (stop) + { + // yield no OAM output + DSP4_WRITE_WORD(0); + } +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP0D() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + world_y = DSP4_READ_DWORD(); + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_top[0][0] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + world_x = DSP4_READ_DWORD(); + poly_cx[0][0] = DSP4_READ_WORD(); + poly_ptr[0][0] = DSP4_READ_WORD(); + world_yofs = DSP4_READ_WORD(); + world_dy = DSP4_READ_DWORD(); + world_dx = DSP4_READ_DWORD(); + distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + world_xenv = SEX78(DSP4_READ_WORD()); + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting raster line + view_x1 = (world_x + world_xenv) >> 16; + view_y1 = world_y >> 16; + view_xofs1 = world_x >> 16; + view_yofs1 = world_yofs; + + // first raster line + poly_raster[0][0] = poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + view_x2 = ( ( ( world_x + world_xenv ) >> 16 ) * distance >> 15 ) + ( view_turnoff_x * distance >> 15 ); + view_y2 = (world_y >> 16) * distance >> 15; + view_xofs2 = view_x2; + view_yofs2 = (world_yofs * distance >> 15) + poly_bottom[0][0] - view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the current + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((world_x + world_xenv) >> 16); + DSP4_WRITE_WORD(view_x2); + DSP4_WRITE_WORD(world_y >> 16); + DSP4_WRITE_WORD(view_y2); + + ////////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of raster lines used + segments = view_y1 - view_y2; + + // prevent overdraw + if (view_y2 >= poly_raster[0][0]) + segments = 0; + else + poly_raster[0][0] = view_y2; + + // don't draw outside the window + if (view_y2 < poly_top[0][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y1 >= poly_top[0][0]) + segments = view_y1 - poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(segments); + + ////////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (view_xofs2 - view_xofs1) * DSP4_Inverse(segments) << 1; + py_dy = (view_yofs2 - view_yofs1) * DSP4_Inverse(segments) << 1; + + // starting step values + x_scroll = SEX16(poly_cx[0][0] + view_xofs1); + y_scroll = SEX16(-viewport_bottom + view_yofs1 + view_yofsenv + poly_cx[1][0] - world_yofs); + + // SR = 0x80 + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + // 1. HDMA memory pointer (bg1) + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(poly_ptr[0][0]); + DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); + DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); + + + // update memory address + poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last raster line drawn + view_x1 = view_x2; + view_y1 = view_y2; + view_xofs1 = view_xofs2; + view_yofs1 = view_yofs2; + + // add deltas for projection lines + world_dx += SEX78(world_ddx); + world_dy += SEX78(world_ddy); + + // update projection lines + world_x += (world_dx + world_xenv); + world_y += world_dy; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(1) resume1 : + + // inspect input + distance = DSP4_READ_WORD(); + + // terminate op + if (distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(2) resume2: + + // inspect inputs + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + world_xenv = 0; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP0E() +{ + OAM_RowMax = 16; + memset(OAM_Row, 0, 64); +} + + +////////////////////////////////////////////////////////////// + +void DSP4_OP0F() +{ + 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; + } + + //////////////////////////////////////////////////// + // process initial inputs + + // sort inputs + DSP4_READ_WORD(); // 0x0000 + world_y = DSP4_READ_DWORD(); + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_top[0][0] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + world_x = DSP4_READ_DWORD(); + poly_cx[0][0] = DSP4_READ_WORD(); + poly_ptr[0][0] = DSP4_READ_WORD(); + world_yofs = DSP4_READ_WORD(); + world_dy = DSP4_READ_DWORD(); + world_dx = DSP4_READ_DWORD(); + distance = DSP4_READ_WORD(); + DSP4_READ_WORD(); // 0x0000 + world_xenv = DSP4_READ_DWORD(); + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting raster line + view_x1 = (world_x + world_xenv) >> 16; + view_y1 = world_y >> 16; + view_xofs1 = world_x >> 16; + view_yofs1 = world_yofs; + view_turnoff_x = 0; + view_turnoff_dx = 0; + + // first raster line + poly_raster[0][0] = poly_bottom[0][0]; + + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // perspective projection of world (x,y,scroll) points + // based on the current projection lines + view_x2 = ((world_x + world_xenv) >> 16) * distance >> 15; + view_y2 = (world_y >> 16) * distance >> 15; + view_xofs2 = view_x2; + view_yofs2 = (world_yofs * distance >> 15) + poly_bottom[0][0] - view_y2; + + // 1. World x-location before transformation + // 2. Viewer x-position at the next + // 3. World y-location before perspective projection + // 4. Viewer y-position below the horizon + // 5. Number of raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD((world_x + world_xenv) >> 16); + DSP4_WRITE_WORD(view_x2); + DSP4_WRITE_WORD(world_y >> 16); + DSP4_WRITE_WORD(view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of raster lines used + segments = poly_raster[0][0] - view_y2; + + // prevent overdraw + if (view_y2 >= poly_raster[0][0]) + segments = 0; + else + poly_raster[0][0] = view_y2; + + // don't draw outside the window + if (view_y2 < poly_top[0][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y1 >= poly_top[0][0]) + segments = view_y1 - poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + for (lcv = 0; lcv < 4; lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (view_xofs2 - view_xofs1) * DSP4_Inverse(segments) << 1; + py_dy = (view_yofs2 - view_yofs1) * DSP4_Inverse(segments) << 1; + + + // starting step values + x_scroll = SEX16(poly_cx[0][0] + view_xofs1); + y_scroll = SEX16(-viewport_bottom + view_yofs1 + view_yofsenv + poly_cx[1][0] - world_yofs); + + // SR = 0x80 + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + // 1. HDMA memory pointer + // 2. vertical scroll offset ($210E) + // 3. horizontal scroll offset ($210D) + + DSP4_WRITE_WORD(poly_ptr[0][0]); + DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); + DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); + + // update memory address + poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + //////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last raster line drawn + view_x1 = view_x2; + view_y1 = view_y2; + view_xofs1 = view_xofs2; + view_yofs1 = view_yofs2; + + // add deltas for projection lines + world_dx += SEX78(world_ddx); + world_dy += SEX78(world_ddy); + + // update projection lines + world_x += (world_dx + world_xenv); + world_y += world_dy; + + // update road turnoff position + view_turnoff_x += view_turnoff_dx; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2: + + // check for termination + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + break; + + // road splice + if( (uint16) distance == 0x8001 ) + { + DSP4.in_count = 6; + DSP4_WAIT(3) resume3: + + distance = DSP4_READ_WORD(); + view_turnoff_x = DSP4_READ_WORD(); + view_turnoff_dx = DSP4_READ_WORD(); + + // factor in new changes + view_x1 += ( view_turnoff_x * distance >> 15 ); + view_xofs1 += ( view_turnoff_x * distance >> 15 ); + + // update stepping values + view_turnoff_x += view_turnoff_dx; + + DSP4.in_count = 2; + DSP4_WAIT(2) + } + + // already have 2 bytes in queue + DSP4.in_count = 6; + DSP4_WAIT(4) resume4 : + + // inspect inputs + world_ddy = DSP4_READ_WORD(); + world_ddx = DSP4_READ_WORD(); + view_yofsenv = DSP4_READ_WORD(); + + // no envelope here + world_xenv = 0; + } + while (1); + + // terminate op + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + + +void DSP4_OP10() +{ + DSP4.waiting4command = FALSE; + + // op flow control + switch (DSP4_Logic) + { + case 1: + goto resume1; break; + case 2: + goto resume2; break; + case 3: + goto resume3; break; + } + + //////////////////////////////////////////////////// + // sort inputs + + DSP4_READ_WORD(); // 0x0000 + world_y = DSP4_READ_DWORD(); + poly_bottom[0][0] = DSP4_READ_WORD(); + poly_top[0][0] = DSP4_READ_WORD(); + poly_cx[1][0] = DSP4_READ_WORD(); + viewport_bottom = DSP4_READ_WORD(); + world_x = DSP4_READ_DWORD(); + poly_cx[0][0] = DSP4_READ_WORD(); + poly_ptr[0][0] = DSP4_READ_WORD(); + world_yofs = DSP4_READ_WORD(); + distance = DSP4_READ_WORD(); + view_y2 = DSP4_READ_WORD(); + view_dy = DSP4_READ_WORD() * distance >> 15; + view_x2 = DSP4_READ_WORD(); + view_dx = DSP4_READ_WORD() * distance >> 15; + view_yofsenv = DSP4_READ_WORD(); + + // initial (x,y,offset) at starting raster line + view_x1 = world_x >> 16; + view_y1 = world_y >> 16; + view_xofs1 = view_x1; + view_yofs1 = world_yofs; + + // first raster line + poly_raster[0][0] = poly_bottom[0][0]; + + do + { + //////////////////////////////////////////////////// + // process one iteration of projection + + // add shaping + view_x2 += view_dx; + view_y2 += view_dy; + + // vertical scroll calculation + view_xofs2 = view_x2; + view_yofs2 = (world_yofs * distance >> 15) + poly_bottom[0][0] - view_y2; + + // 1. Viewer x-position at the next + // 2. Viewer y-position below the horizon + // 3. Number of raster lines drawn in this iteration + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(view_x2); + DSP4_WRITE_WORD(view_y2); + + ////////////////////////////////////////////////////// + + // SR = 0x00 + + // determine # of raster lines used + segments = view_y1 - view_y2; + + // prevent overdraw + if (view_y2 >= poly_raster[0][0]) + segments = 0; + else + poly_raster[0][0] = view_y2; + + // don't draw outside the window + if (view_y2 < poly_top[0][0]) + { + segments = 0; + + // flush remaining raster lines + if (view_y1 >= poly_top[0][0]) + segments = view_y1 - poly_top[0][0]; + } + + // SR = 0x80 + + DSP4_WRITE_WORD(segments); + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + for (lcv = 0; lcv < 4; lcv++) + { + // grab inputs + DSP4.in_count = 4; + DSP4_WAIT(1); + resume1 : + for (;;) + { + int16 distance; + int16 color, red, green, blue; + + distance = DSP4_READ_WORD(); + color = DSP4_READ_WORD(); + + // U1+B5+G5+R5 + red = color & 0x1f; + green = (color >> 5) & 0x1f; + blue = (color >> 10) & 0x1f; + + // dynamic lighting + red = (red * distance >> 15) & 0x1f; + green = (green * distance >> 15) & 0x1f; + blue = (blue * distance >> 15) & 0x1f; + color = red | (green << 5) | (blue << 10); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(color); + break; + } + } + } + + ////////////////////////////////////////////////////// + + // scan next command if no SR check needed + if (segments) + { + int32 px_dx, py_dy; + int32 x_scroll, y_scroll; + + // SR = 0x00 + + // linear interpolation (lerp) between projected points + px_dx = (view_xofs2 - view_xofs1) * DSP4_Inverse(segments) << 1; + py_dy = (view_yofs2 - view_yofs1) * DSP4_Inverse(segments) << 1; + + // starting step values + x_scroll = SEX16(poly_cx[0][0] + view_xofs1); + y_scroll = SEX16(-viewport_bottom + view_yofs1 + view_yofsenv + poly_cx[1][0] - world_yofs); + + // SR = 0x80 + + // rasterize line + for (lcv = 0; lcv < segments; lcv++) + { + // 1. HDMA memory pointer (bg2) + // 2. vertical scroll offset ($2110) + // 3. horizontal scroll offset ($210F) + + DSP4_WRITE_WORD(poly_ptr[0][0]); + DSP4_WRITE_WORD((y_scroll + 0x8000) >> 16); + DSP4_WRITE_WORD((x_scroll + 0x8000) >> 16); + + // update memory address + poly_ptr[0][0] -= 4; + + // update screen values + x_scroll += px_dx; + y_scroll += py_dy; + } + } + + ///////////////////////////////////////////////////// + // Post-update + + // update new viewer (x,y,scroll) to last raster line drawn + view_x1 = view_x2; + view_y1 = view_y2; + view_xofs1 = view_xofs2; + view_yofs1 = view_yofs2; + + //////////////////////////////////////////////////// + // command check + + // scan next command + DSP4.in_count = 2; + DSP4_WAIT(2) resume2 : + + // check for opcode termination + distance = DSP4_READ_WORD(); + if (distance == -0x8000) + break; + + // already have 2 bytes in queue + DSP4.in_count = 10; + DSP4_WAIT(3) resume3 : + + + // inspect inputs + view_y2 = DSP4_READ_WORD(); + view_dy = DSP4_READ_WORD() * distance >> 15; + view_x2 = DSP4_READ_WORD(); + view_dx = DSP4_READ_WORD() * distance >> 15; + } + while (1); + + DSP4.waiting4command = TRUE; +} + +////////////////////////////////////////////////////////////// + +void DSP4_OP11(int16 A, int16 B, int16 C, int16 D, int16 *M) +{ + // 0x155 = 341 = Horizontal Width of the Screen + *M = ((A * 0x0155 >> 2) & 0xf000) | + ((B * 0x0155 >> 6) & 0x0f00) | + ((C * 0x0155 >> 10) & 0x00f0) | + ((D * 0x0155 >> 14) & 0x000f); +} + + + + + +///////////////////////////////////////////////////////////// +//Processing Code +///////////////////////////////////////////////////////////// +uint8 dsp4_byte; +uint16 dsp4_address; + +void InitDSP4() +{ + memset(&DSP4, 0, sizeof(DSP4)); + DSP4.waiting4command = TRUE; +} + +void DSP4_SetByte() +{ + // clear pending read + if (DSP4.out_index < DSP4.out_count) + { + DSP4.out_index++; + return; + } + + if (DSP4.waiting4command) + { + if (DSP4.half_command) + { + DSP4.command |= (dsp4_byte << 8); + DSP4.in_index = 0; + DSP4.waiting4command = FALSE; + DSP4.half_command = FALSE; + DSP4.out_count = 0; + DSP4.out_index = 0; + + DSP4_Logic = 0; + + + switch (DSP4.command) + { + case 0x0000: + DSP4.in_count = 4; break; + case 0x0001: + DSP4.in_count = 44; break; + case 0x0003: + DSP4.in_count = 0; break; + case 0x0005: + DSP4.in_count = 0; break; + case 0x0006: + DSP4.in_count = 0; break; + case 0x0007: + DSP4.in_count = 34; break; + case 0x0008: + DSP4.in_count = 90; break; + case 0x0009: + DSP4.in_count = 14; break; + case 0x000a: + DSP4.in_count = 6; break; + case 0x000b: + DSP4.in_count = 6; break; + case 0x000d: + DSP4.in_count = 42; break; + case 0x000e: + DSP4.in_count = 0; break; + case 0x000f: + DSP4.in_count = 46; break; + case 0x0010: + DSP4.in_count = 36; break; + case 0x0011: + DSP4.in_count = 8; break; + default: + DSP4.waiting4command = TRUE; + break; + } + } + else + { + DSP4.command = dsp4_byte; + DSP4.half_command = TRUE; + } + } + else + { + DSP4.parameters[DSP4.in_index] = dsp4_byte; + DSP4.in_index++; + } + + if (!DSP4.waiting4command && DSP4.in_count == DSP4.in_index) + { + // Actually execute the command + DSP4.waiting4command = TRUE; + DSP4.out_index = 0; + DSP4.in_index = 0; + + switch (DSP4.command) + { + // 16-bit multiplication + case 0x0000: + { + int16 multiplier, multiplicand; + int32 product; + + multiplier = DSP4_READ_WORD(); + multiplicand = DSP4_READ_WORD(); + + DSP4_Multiply(multiplicand, multiplier, &product); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(product); + DSP4_WRITE_WORD(product >> 16); + } + break; + + // single-player track projection + case 0x0001: + DSP4_OP01(); break; + + // single-player selection + case 0x0003: + DSP4_OP03(); break; + + // clear OAM + case 0x0005: + DSP4_OP05(); break; + + // transfer OAM + case 0x0006: + DSP4_OP06(); break; + + // single-player track turnoff projection + case 0x0007: + DSP4_OP07(); break; + + // solid polygon projection + case 0x0008: + DSP4_OP08(); break; + + // sprite projection + case 0x0009: + DSP4_OP09(); break; + + // unknown + case 0x000A: + { + //int16 in1a = DSP4_READ_WORD(); + int16 in2a = DSP4_READ_WORD(); + //int16 in3a = DSP4_READ_WORD(); + int16 out1a, out2a, out3a, out4a; + + DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(out1a); + DSP4_WRITE_WORD(out2a); + DSP4_WRITE_WORD(out3a); + DSP4_WRITE_WORD(out4a); + } + break; + + // set OAM + case 0x000B: + { + int16 sp_x = DSP4_READ_WORD(); + int16 sp_y = DSP4_READ_WORD(); + int16 sp_attr = DSP4_READ_WORD(); + bool8 draw = 1; + + DSP4_CLEAR_OUT(); + + DSP4_OP0B(&draw, sp_x, sp_y, sp_attr, 0, 1); + } + break; + + // multi-player track projection + case 0x000D: + DSP4_OP0D(); break; + + // multi-player selection + case 0x000E: + DSP4_OP0E(); break; + + // single-player track projection with lighting + case 0x000F: + DSP4_OP0F(); break; + + // single-player track turnoff projection with lighting + case 0x0010: + DSP4_OP10(); break; + + // unknown: horizontal mapping command + case 0x0011: + { + int16 a, b, c, d, m; + + + d = DSP4_READ_WORD(); + c = DSP4_READ_WORD(); + b = DSP4_READ_WORD(); + a = DSP4_READ_WORD(); + + DSP4_OP11(a, b, c, d, &m); + + DSP4_CLEAR_OUT(); + DSP4_WRITE_WORD(m); + + break; + } + + default: + break; + } + } +} + +void DSP4_GetByte() +{ + if (DSP4.out_count) + { + dsp4_byte = (uint8) DSP4.output[DSP4.out_index&0x1FF]; + DSP4.out_index++; + if (DSP4.out_count == DSP4.out_index) + DSP4.out_count = 0; + } + else + { + dsp4_byte = 0xff; + } +} diff --git a/source/snes9x/font.h b/source/snes9x/font.h new file mode 100644 index 0000000..ad54c3f --- /dev/null +++ b/source/snes9x/font.h @@ -0,0 +1,284 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +static char *font[] = { +" . . . . .. . . ", +" .#. .#.#. . . ... .#. . . .##. .#. .#. . . . . ", +" .#. .#.#. .#.#. .###. .#..#. .#. .#. .#. .#. .#.#. .#. .#. ", +" .#. .#.#. .#####. .#.#. ..#. .#.#. .#. .#. .#. .#. ..#.. .... .#. ", +" .#. . . .#.#. .###. .#.. .#. . .#. .#. .###. .#####. .. .####. .. .#. ", +" . .#####. .#.#. .#..#. .#.#. .#. .#. .#. ..#.. .##. .... .##. .#. ", +" .#. .#.#. .###. . .#. .#.#. .#. .#. .#.#. .#. .#. .##. . ", +" . . . ... . . . . . . . . .#. .. ", +" . ", +" . . .. .... . .... .. .... .. .. . ", +" .#. .#. .##. .####. .#. .####. .##. .####. .##. .##. .. .. . . .#. ", +".#.#. .##. .#..#. ...#. .##. .#... .#.. ...#. .#..#. .#..#. .##. .##. .#. .... .#. .#.#. ", +".#.#. .#. . .#. .##. .#.#. .###. .###. .#. .##. .#..#. .##. .##. .#. .####. .#. ..#. ", +".#.#. .#. .#. ...#. .####. ...#. .#..#. .#. .#..#. .###. .. .. .#. .... .#. .#. ", +".#.#. .#. .#.. .#..#. ..#. .#..#. .#..#. .#. .#..#. ..#. .##. .##. .#. .####. .#. . ", +" .#. .###. .####. .##. .#. .##. .##. .#. .##. .##. .##. .#. .#. .... .#. .#. ", +" . ... .... .. . .. .. . .. .. .. .#. . . . ", +" . ", +" .. .. ... .. ... .... .... .. . . ... . . . . . . . . .. ", +" .##. .##. .###. .##. .###. .####. .####. .##. .#..#. .###. .#. .#..#. .#. .#. .#. .#. .#. .##. ", +".#..#. .#..#. .#..#. .#..#. .#..#. .#... .#... .#..#. .#..#. .#. .#. .#.#. .#. .##.##. .##..#. .#..#. ", +".#.##. .#..#. .###. .#. . .#..#. .###. .###. .#... .####. .#. .#. .##. .#. .#.#.#. .#.#.#. .#..#. ", +".#.##. .####. .#..#. .#. . .#..#. .#.. .#.. .#.##. .#..#. .#. . .#. .##. .#. .#...#. .#.#.#. .#..#. ", +".#... .#..#. .#..#. .#..#. .#..#. .#... .#. .#..#. .#..#. .#. .#..#. .#.#. .#... .#. .#. .#..##. .#..#. ", +" .##. .#..#. .###. .##. .###. .####. .#. .###. .#..#. .###. .##. .#..#. .####. .#. .#. .#. .#. .##. ", +" .. . . ... .. ... .... . ... . . ... .. . . .... . . . . .. ", +" ", +" ... .. ... .. ... . . . . . . . . . . .... ... ... . ", +".###. .##. .###. .##. .###. .#. .#. .#. .#. .#. .#. .#..#. .#.#. .####. .###. . .###. .#. ", +".#..#. .#..#. .#..#. .#..#. .#. .#. .#. .#. .#. .#...#. .#..#. .#.#. ...#. .#.. .#. ..#. .#.#. ", +".#..#. .#..#. .#..#. .#.. .#. .#. .#. .#. .#. .#.#.#. .##. .#.#. .#. .#. .#. .#. . . ", +".###. .#..#. .###. ..#. .#. .#. .#. .#. .#. .#.#.#. .#..#. .#. .#. .#. .#. .#. ", +".#.. .##.#. .#.#. .#..#. .#. .#...#. .#.#. .##.##. .#..#. .#. .#... .#.. .#. ..#. .... ", +".#. .##. .#..#. .##. .#. .###. .#. .#. .#. .#..#. .#. .####. .###. . .###. .####. ", +" . ..#. . . .. . ... . . . . . . .... ... ... .... ", +" . ", +" .. . . . . . . . .. ", +".##. .#. .#. .#. .#. .#. .#. .#. .##. ", +" .#. ... .#.. .. ..#. .. .#.#. ... .#.. .. . .#.. .#. .. .. ... .. ", +" .#. .###. .###. .##. .###. .##. .#.. .###. .###. .##. .#. .#.#. .#. .##.##. .###. .##. ", +" . .#..#. .#..#. .#.. .#..#. .#.##. .###. .#..#. .#..#. .#. .#. .##. .#. .#.#.#. .#..#. .#..#. ", +" .#.##. .#..#. .#.. .#..#. .##.. .#. .##. .#..#. .#. ..#. .#.#. .#. .#...#. .#..#. .#..#. ", +" .#.#. .###. .##. .###. .##. .#. .#... .#..#. .###. .#.#. .#..#. .###. .#. .#. .#..#. .##. ", +" . . ... .. ... .. . .###. . . ... .#. . . ... . . . . .. ", +" ... . ", +" . . . . . . ", +" .#. .#. .#. .#. .#.#. ", +" ... ... ... ... .#. . . . . . . . . . . .... .#. .#. .#. .#.#. ", +".###. .###. .###. .###. .###. .#..#. .#.#. .#...#. .#..#. .#..#. .####. .##. .#. .##. . . ", +".#..#. .#..#. .#..#. .##.. .#. .#..#. .#.#. .#.#.#. .##. .#..#. ..#. .#. .#. .#. ", +".#..#. .#..#. .#. . ..##. .#.. .#..#. .#.#. .#.#.#. .##. .#.#. .#.. .#. .#. .#. ", +".###. .###. .#. .###. .##. .###. .#. .#.#. .#..#. .#. .####. .#. .#. .#. ", +".#.. ..#. . ... .. ... . . . . . .#. .... . . . ", +" . . . ", + +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", + +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", + +//2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 +" .. ..... ", +" .##. .#####. ... . . . . .. ", +" .#. . .. ....#. .###. .#. .#. .#. .#.. .##. . . . ", +" .#. .#. .##. .#####. .#. .#. .###. ... .###. .###. .. .#. .#.#.#. ", +" . .#. .#. . .##. ....#. .#. .##. .#.#. .###. .#. .##.#. .##. .##. .#.#.#. ", +" .#. . .#. .#. .. ...#. .#. .#. ..#. .#. .##. .#.. ..#. .#. ...#. ", +" .#.#. .##. .#. .###. .#. .#. .#. .###. .#. .#. .####. .##. .##. ", +" .#. .. .#. ... . . . ... . . .... .. .. ", +" . . ", +//2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 +" .... . . ... . . . .... . . . .. . ..... . . . ", +" .####. .#. ..#.. .###. ...#. ..#.. ..#.. .####. .#... .... .#.#. .##..#. .#####. .#... .#. .#. ", +" .... ...#. .#. .#####. .#. .#####. .#####. .#####. .#..#. .####. .####. .#####. .. .#. ....#. .#####. .#. .#. ", +".####. .##. .## .#...#. .#. ...#. ..#.#. ..#.. .# .#. .#..#. ...#. .#.#. .##..#. .#. .#..#. .#..#. ", +" .... .#. .#.# . .#. .#. .##. .#..#. .#####. .#. .#. . .#. .#. ..#. .. .#. .#. .#.#. . .#. ", +" .#. .#. ..#. ..#.. .#.#. .#..#. ..#.. . .#. .#. ...#. .#. ...#. .#.#. .#... ...#. ", +" .#. .#. .##. .#####. .#..#. .#..#. .#. .#. .#. .####. .#. .###. .#. .#. .###. .###. ", +" . . .. ..... . . . . . . . .... . ... . . ... ... ", +" ", +//2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 +" .... .. . . . ... . . ... .... . . . ..... . . ", +" .####. ..##. .#.#.#. .###. .#. ..#.. .###. .####. ..#.. .#. . . .#. .. .#####. .#. ..#.. ..... ", +" .#..#. .###. .#.#.#. ..... .#. .#####. ... ...#. .#####. .#. .#.#. .#..##. ....#. .#.#. .#####. .#####. ", +" .####. ..#. .#.#.#. .#####. .##. ..#.. .#.#. ....#. .#. .#.#. .###.. .#. .#..#. ..#.. .#. ", +".#...#. .####. . ..#. ..#.. .#.#. .#. .#. .###. .#. .#. .#. .#.. .#. . .#. .#.#.#. .#.#. ", +" . .#. ..#. ...#. .#. .#.. ..#. ..... .#.#. .#.#.#. .#. .#. .#. .#.... ..#. .#. .#.#.#. .#. ", +" .#. .##. .###. .#. .#. .##. .#####. .#. .#. ..#.. .#. .#. .#. .####. .##. .#. ..#.. .#. ", +" . .. ... . . .. ..... . . . . . . .... .. . . . ", +" ", +//2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678/2345678 +" .. . . ... . .... .... . . . . . ..... . . . . ", +" .##. .#. .#. .###. .#... ... .####. .####. .#..#. .#.#. .#. ..... .#####. ....#. .#.#. .#. ", +" ..#. .#. . .#. .#. .#.##. .###. ...#. ..... .#..#. .#.#. .#. .#####. .#...#. .###.#. .#.#. .#.#. ", +" .##. .#. . .#.#. .#####. .##.#. .#. .###. .#####. .#..#. .#.#. .#. . .#...#. . .#. ....#. . . .#. ", +" ..#. .#..#. .##. ..#.. .#.#. ..#. ..#. ....#. . .#. .#.#. .#..#. .#...#. .#. .#. . ", +" .##. .####. ..#.#. .#.. .#. ...#. ...#. ..#. ..#. .#.#. .#.#. .#####. ..#. ...#. ", +" ..#. ...#. .##. . .###. .#. .#####. .####. .##. .##. .#..##. .##. .#...#. .##. .###. ", +" . . .. ... . ..... .... .. ... . .. .. . . .. ... ", +" ", + +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", + +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; + +static int font_width = 8; +static int font_height = 9; + diff --git a/source/snes9x/fxdbg.cpp b/source/snes9x/fxdbg.cpp new file mode 100644 index 0000000..d7b0d4c --- /dev/null +++ b/source/snes9x/fxdbg.cpp @@ -0,0 +1,464 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "fxemu.h" +#include "fxinst.h" +#include +#include + +extern const char *fx_apvMnemonicTable[]; +extern struct FxRegs_s GSU; + + +/* + When printing a line from the pipe, it could look like this: + + 01:8006 f4 fb 86 iwt r4,#$86fb + + The values are: + program bank: 01 + adress: 8006 + values at memory address 8006: f4 fb 86 + instruction in the pipe: iwt r4,#$86fb + + Note! If the instruction has more than one byte (like in 'iwt') + and the instruction is in a delay slot, the second and third + byte displayed will not be the same as those used. + Since the instrction is in a delay slot, the first byte + of the instruction will be taken from the pipe at the address + after the branch instruction, and the next one or two bytes + will be taken from the address that the branch points to. + This is a bit complicated, but I've taken this into account, + in this debug function. (See the diffrence of how the values + vPipe1 and vPipe2 are read, compared to the values vByte1 and + vByte2) + + */ +void FxPipeString(char * pvString) +{ + char *p; + uint32 vOpcode = (GSU.vStatusReg & 0x300) | ((uint32)PIPE); + const char *m = fx_apvMnemonicTable[vOpcode]; + uint8 vPipe1,vPipe2,vByte1,vByte2; + uint8 vPipeBank = GSU.vPipeAdr >> 16; + + /* The next two bytes after the pipe's address */ + vPipe1 = GSU.apvRomBank[vPipeBank][USEX16(GSU.vPipeAdr+1)]; + vPipe2 = GSU.apvRomBank[vPipeBank][USEX16(GSU.vPipeAdr+2)]; + + /* The actual next two bytes to be read */ + vByte1 = PRGBANK(USEX16(R15)); + vByte2 = PRGBANK(USEX16(R15+1)); + + /* Print ROM address of the pipe */ + sprintf(pvString, "%02x:%04x %02x ", + USEX8(vPipeBank), USEX16(GSU.vPipeAdr), USEX8(PIPE)); + p = &pvString[strlen(pvString)]; + + /* Check if it's a branch instruction */ + if( PIPE >= 0x05 && PIPE <= 0x0f ) + { + sprintf(&pvString[11], "%02x ", USEX8(vPipe1)); +#ifdef BRANCH_DELAY_RELATIVE + sprintf(p, m, USEX16(R15 + SEX8(vByte1) + 1 ) ); +#else + sprintf(p, m, USEX16(R15 + SEX8(vByte1) - 1 ) ); +#endif + } + /* Check for 'move' instruction */ + else if( PIPE >= 0x10 && PIPE <= 0x1f && TF(B) ) + sprintf(p, "move r%d,r%d", USEX8(PIPE & 0x0f), (uint32)(GSU.pvSreg - GSU.avReg)); + /* Check for 'ibt', 'lms' or 'sms' */ + else if( PIPE >= 0xa0 && PIPE <= 0xaf ) + { + sprintf(&pvString[11], "%02x ", USEX8(vPipe1)); + if( (GSU.vStatusReg & 0x300) == 0x100 || (GSU.vStatusReg & 0x300) == 0x200 ) + sprintf(p, m, USEX16(vByte1) << 1 ); + else + sprintf(p, m, USEX16(vByte1) ); + } + /* Check for 'moves' */ + else if( PIPE >= 0xb0 && PIPE <= 0xbf && TF(B) ) + sprintf(p, "moves r%d,r%d", (uint32)(GSU.pvDreg - GSU.avReg), USEX8(PIPE & 0x0f)); + /* Check for 'iwt', 'lm' or 'sm' */ + else if( PIPE >= 0xf0 ) + { + sprintf(&pvString[11], "%02x %02x ", USEX8(vPipe1), USEX8(vPipe2)); + sprintf(p, m, USEX8(vByte1) | (USEX16(vByte2)<<8) ); + } + /* Normal instruction */ + else + strcpy(p, m); +} + +const char *fx_apvMnemonicTable[] = +{ + /* + * ALT0 Table + */ + /* 00 - 0f */ + "stop", "nop", "cache", "lsr", "rol", "bra $%04x","blt $%04x","bge $%04x", + "bne $%04x","beq $%04x","bpl $%04x","bmi $%04x","bcc $%04x","bcs $%04x","bvc $%04x","bvs $%04x", + /* 10 - 1f */ + "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", + "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", + /* 20 - 2f */ + "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", + "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", + /* 30 - 3f */ + "stw (r0)","stw (r1)","stw (r2)", "stw (r3)", "stw (r4)", "stw (r5)", "stw (r6)", "stw (r7)", + "stw (r8)","stw (r9)","stw (r10)","stw (r11)","loop", "alt1", "alt2", "alt3", + /* 40 - 4f */ + "ldw (r0)","ldw (r1)","ldw (r2)", "ldw (r3)", "ldw (r4)", "ldw (r5)", "ldw (r6)", "ldw (r7)", + "ldw (r8)","ldw (r9)","ldw (r10)","ldw (r11)","plot", "swap", "color", "not", + /* 50 - 5f */ + "add r0", "add r1", "add r2", "add r3", "add r4", "add r5", "add r6", "add r7", + "add r8", "add r9", "add r10", "add r11", "add r12", "add r13", "add r14", "add r15", + /* 60 - 6f */ + "sub r0", "sub r1", "sub r2", "sub r3", "sub r4", "sub r5", "sub r6", "sub r7", + "sub r8", "sub r9", "sub r10", "sub r11", "sub r12", "sub r13", "sub r14", "sub r15", + /* 70 - 7f */ + "merge", "and r1", "and r2", "and r3", "and r4", "and r5", "and r6", "and r7", + "and r8", "and r9", "and r10", "and r11", "and r12", "and r13", "and r14", "and r15", + /* 80 - 8f */ + "mult r0", "mult r1", "mult r2", "mult r3", "mult r4", "mult r5", "mult r6", "mult r7", + "mult r8", "mult r9", "mult r10", "mult r11", "mult r12", "mult r13", "mult r14", "mult r15", + /* 90 - 9f */ + "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "asr", "ror", + "jmp (r8)","jmp (r9)","jmp (r10)","jmp (r11)","jmp (r12)","jmp (r13)","lob", "fmult", + /* a0 - af */ + "ibt r0,#$%02x", "ibt r1,#$%02x", "ibt r2,#$%02x", "ibt r3,#$%02x", + "ibt r4,#$%02x", "ibt r5,#$%02x", "ibt r6,#$%02x", "ibt r7,#$%02x", + "ibt r8,#$%02x", "ibt r9,#$%02x", "ibt r10,#$%02x", "ibt r11,#$%02x", + "ibt r12,#$%02x", "ibt r13,#$%02x", "ibt r14,#$%02x", "ibt r15,#$%02x", + /* b0 - bf */ + "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", + "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", + /* c0 - cf */ + "hib", "or r1", "or r2", "or r3", "or r4", "or r5", "or r6", "or r7", + "or r8", "or r9", "or r10", "or r11", "or r12", "or r13", "or r14", "or r15", + /* d0 - df */ + "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", + "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "getc", + /* e0 - ef */ + "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", + "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getb", + /* f0 - ff */ + "iwt r0,#$%04x", "iwt r1,#$%04x", "iwt r2,#$%04x", "iwt r3,#$%04x", + "iwt r4,#$%04x", "iwt r5,#$%04x", "iwt r6,#$%04x", "iwt r7,#$%04x", + "iwt r8,#$%04x", "iwt r9,#$%04x", "iwt r10,#$%04x", "iwt r11,#$%04x", + "iwt r12,#$%04x", "iwt r13,#$%04x", "iwt r14,#$%04x", "iwt r15,#$%04x", + + /* + * ALT1 Table + */ + + /* 00 - 0f */ + "stop", "nop", "cache", "lsr", "rol", "bra $%04x","blt $%04x","bge $%04x", + "bne $%04x","beq $%04x","bpl $%04x","bmi $%04x","bcc $%04x","bcs $%04x","bvc $%04x","bvs $%04x", + /* 10 - 1f */ + "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", + "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", + /* 20 - 2f */ + "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", + "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", + /* 30 - 3f */ + "stb (r0)","stb (r1)","stb (r2)", "stb (r3)", "stb (r4)", "stb (r5)", "stb (r6)", "stb (r7)", + "stb (r8)","stb (r9)","stb (r10)","stb (r11)","loop", "alt1", "alt2", "alt3", + /* 40 - 4f */ + "ldb (r0)","ldb (r1)","ldb (r2)", "ldb (r3)", "ldb (r4)", "ldb (r5)", "ldb (r6)", "ldb (r7)", + "ldb (r8)","ldb (r9)","ldb (r10)","ldb (r11)","rpix", "swap", "cmode", "not", + /* 50 - 5f */ + "adc r0", "adc r1", "adc r2", "adc r3", "adc r4", "adc r5", "adc r6", "adc r7", + "adc r8", "adc r9", "adc r10", "adc r11", "adc r12", "adc r13", "adc r14", "adc r15", + /* 60 - 6f */ + "sbc r0", "sbc r1", "sbc r2", "sbc r3", "sbc r4", "sbc r5", "sbc r6", "sbc r7", + "sbc r8", "sbc r9", "sbc r10", "sbc r11", "sbc r12", "sbc r13", "sbc r14", "sbc r15", + /* 70 - 7f */ + "merge", "bic r1", "bic r2", "bic r3", "bic r4", "bic r5", "bic r6", "bic r7", + "bic r8", "bic r9", "bic r10", "bic r11", "bic r12", "bic r13", "bic r14", "bic r15", + /* 80 - 8f */ + "umult r0","umult r1","umult r2", "umult r3", "umult r4", "umult r5", "umult r6", "umult r7", + "umult r8","umult r9","umult r10","umult r11","umult r12","umult r13","umult r14","umult r15", + /* 90 - 9f */ + "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "div2", "ror", + "ljmp (r8)","ljmp (r9)","ljmp (r10)","ljmp (r11)", "ljmp (r12)", "ljmp (r13)", "lob", "lmult", + /* a0 - af */ + "lms r0,($%04x)", "lms r1,($%04x)", "lms r2,($%04x)", "lms r3,($%04x)", + "lms r4,($%04x)", "lms r5,($%04x)", "lms r6,($%04x)", "lms r7,($%04x)", + "lms r8,($%04x)", "lms r9,($%04x)", "lms r10,($%04x)", "lms r11,($%04x)", + "lms r12,($%04x)", "lms r13,($%04x)", "lms r14,($%04x)", "lms r15,($%04x)", + /* b0 - bf */ + "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", + "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", + /* c0 - cf */ + "hib", "xor r1", "xor r2", "xor r3", "xor r4", "xor r5", "xor r6", "xor r7", + "xor r8", "xor r9", "xor r10", "xor r11", "xor r12", "xor r13", "xor r14", "xor r15", + /* d0 - df */ + "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", + "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "getc", + /* e0 - ef */ + "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", + "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbh", + /* f0 - ff */ + "lm r0,($%04x)", "lm r1,($%04x)", "lm r2,($%04x)", "lm r3,($%04x)", + "lm r4,($%04x)", "lm r5,($%04x)", "lm r6,($%04x)", "lm r7,($%04x)", + "lm r8,($%04x)", "lm r9,($%04x)", "lm r10,($%04x)", "lm r11,($%04x)", + "lm r12,($%04x)", "lm r13,($%04x)", "lm r14,($%04x)", "lm r15,($%04x)", + + /* + * ALT2 Table + */ + + /* 00 - 0f */ + "stop", "nop", "cache", "lsr", "rol", "bra $%04x","blt $%04x","bge $%04x", + "bne $%04x","beq $%04x","bpl $%04x","bmi $%04x","bcc $%04x","bcs $%04x","bvc $%04x","bvs $%04x", + /* 10 - 1f */ + "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", + "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", + /* 20 - 2f */ + "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", + "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", + /* 30 - 3f */ + "stw (r0)","stw (r1)","stw (r2)", "stw (r3)", "stw (r4)", "stw (r5)", "stw (r6)", "stw (r7)", + "stw (r8)","stw (r9)","stw (r10)","stw (r11)","loop", "alt1", "alt2", "alt3", + /* 40 - 4f */ + "ldw (r0)","ldw (r1)","ldw (r2)", "ldw (r3)", "ldw (r4)", "ldw (r5)", "ldw (r6)", "ldw (r7)", + "ldw (r8)","ldw (r9)","ldw (r10)","ldw (r11)","plot", "swap", "color", "not", + /* 50 - 5f */ + "add #0", "add #1", "add #2", "add #3", "add #4", "add #5", "add #6", "add #7", + "add #8", "add #9", "add #10", "add #11", "add #12", "add #13", "add #14", "add #15", + /* 60 - 6f */ + "sub #0", "sub #1", "sub #2", "sub #3", "sub #4", "sub #5", "sub #6", "sub #7", + "sub #8", "sub #9", "sub #10", "sub #11", "sub #12", "sub #13", "sub #14", "sub #15", + /* 70 - 7f */ + "merge", "and #1", "and #2", "and #3", "and #4", "and #5", "and #6", "and #7", + "and #8", "and #9", "and #10", "and #11", "and #12", "and #13", "and #14", "and #15", + /* 80 - 8f */ + "mult #0", "mult #1", "mult #2", "mult #3", "mult #4", "mult #5", "mult #6", "mult #7", + "mult #8", "mult #9", "mult #10", "mult #11", "mult #12", "mult #13", "mult #14", "mult #15", + /* 90 - 9f */ + "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "asr", "ror", + "jmp (r8)","jmp (r9)","jmp (r10)","jmp (r11)","jmp (r12)","jmp (r13)","lob", "fmult", + /* a0 - af */ + "sms ($%04x),r0", "sms ($%04x),r1", "sms ($%04x),r2", "sms ($%04x),r3", + "sms ($%04x),r4", "sms ($%04x),r5", "sms ($%04x),r6", "sms ($%04x),r7", + "sms ($%04x),r8", "sms ($%04x),r9", "sms ($%04x),r10", "sms ($%04x),r11", + "sms ($%04x),r12", "sms ($%04x),r13", "sms ($%04x),r14", "sms ($%04x),r15", + /* b0 - bf */ + "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", + "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", + /* c0 - cf */ + "hib", "or #1", "or #2", "or #3", "or #4", "or #5", "or #6", "or #7", + "or #8", "or #9", "or #10", "or #11", "or #12", "or #13", "or #14", "or #15", + /* d0 - df */ + "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", + "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "ramb", + /* e0 - ef */ + "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", + "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbl", + /* f0 - ff */ + "sm ($%04x),r0", "sm ($%04x),r1", "sm ($%04x),r2", "sm ($%04x),r3", + "sm ($%04x),r4", "sm ($%04x),r5", "sm ($%04x),r6", "sm ($%04x),r7", + "sm ($%04x),r8", "sm ($%04x),r9", "sm ($%04x),r10", "sm ($%04x),r11", + "sm ($%04x),r12", "sm ($%04x),r13", "sm ($%04x),r14", "sm ($%04x),r15", + + /* + * ALT3 Table + */ + + /* 00 - 0f */ + "stop", "nop", "cache", "lsr", "rol", "bra $%04x","blt $%04x","bge $%04x", + "bne $%04x","beq $%04x","bpl $%04x","bmi $%04x","bcc $%04x","bcs $%04x","bvc $%04x","bvs $%04x", + /* 10 - 1f */ + "to r0", "to r1", "to r2", "to r3", "to r4", "to r5", "to r6", "to r7", + "to r8", "to r9", "to r10", "to r11", "to r12", "to r13", "to r14", "to r15", + /* 20 - 2f */ + "with r0", "with r1", "with r2", "with r3", "with r4", "with r5", "with r6", "with r7", + "with r8", "with r9", "with r10", "with r11", "with r12", "with r13", "with r14", "with r15", + /* 30 - 3f */ + "stb (r0)","stb (r1)","stb (r2)", "stb (r3)", "stb (r4)", "stb (r5)", "stb (r6)", "stb (r7)", + "stb (r8)","stb (r9)","stb (r10)","stb (r11)","loop", "alt1", "alt2", "alt3", + /* 40 - 4f */ + "ldb (r0)","ldb (r1)","ldb (r2)", "ldb (r3)", "ldb (r4)", "ldb (r5)", "ldb (r6)", "ldb (r7)", + "ldb (r8)","ldb (r9)","ldb (r10)","ldb (r11)","rpix", "swap", "cmode", "not", + /* 50 - 5f */ + "adc #0", "adc #1", "adc #2", "adc #3", "adc #4", "adc #5", "adc #6", "adc #7", + "adc #8", "adc #9", "adc #10", "adc #11", "adc #12", "adc #13", "adc #14", "adc #15", + /* 60 - 6f */ + "cmp r0", "cmp r1", "cmp r2", "cmp r3", "cmp r4", "cmp r5", "cmp r6", "cmp r7", + "cmp r8", "cmp r9", "cmp r10", "cmp r11", "cmp r12", "cmp r13", "cmp r14", "cmp r15", + /* 70 - 7f */ + "merge", "bic #1", "bic #2", "bic #3", "bic #4", "bic #5", "bic #6", "bic #7", + "bic #8", "bic #9", "bic #10", "bic #11", "bic #12", "bic #13", "bic #14", "bic #15", + /* 80 - 8f */ + "umult #0","umult #1","umult #2", "umult #3", "umult #4", "umult #5", "umult #6", "umult #7", + "umult #8","umult #9","umult #10","umult #11","umult #12","umult #13","umult #14","umult #15", + /* 90 - 9f */ + "sbk", "link #1", "link #2", "link #3", "link #4", "sex", "div2", "ror", + "ljmp (r8)","ljmp (r9)","ljmp (r10)","ljmp (r11)", "ljmp (r12)", "ljmp (r13)", "lob", "lmult", + /* a0 - af */ + "lms r0,($%04x)", "lms r1,($%04x)", "lms r2,($%04x)", "lms r3,($%04x)", + "lms r4,($%04x)", "lms r5,($%04x)", "lms r6,($%04x)", "lms r7,($%04x)", + "lms r8,($%04x)", "lms r9,($%04x)", "lms r10,($%04x)", "lms r11,($%04x)", + "lms r12,($%04x)", "lms r13,($%04x)", "lms r14,($%04x)", "lms r15,($%04x)", + /* b0 - bf */ + "from r0", "from r1", "from r2", "from r3", "from r4", "from r5", "from r6", "from r7", + "from r8", "from r9", "from r10", "from r11", "from r12", "from r13", "from r14", "from r15", + /* c0 - cf */ + "hib", "xor #1", "xor #2", "xor #3", "xor #4", "xor #5", "xor #6", "xor #7", + "xor #8", "xor #9", "xor #10", "xor #11", "xor #12", "xor #13", "xor #14", "xor #15", + /* d0 - df */ + "inc r0", "inc r1", "inc r2", "inc r3", "inc r4", "inc r5", "inc r6", "inc r7", + "inc r8", "inc r9", "inc r10", "inc r11", "inc r12", "inc r13", "inc r14", "romb", + /* e0 - ef */ + "dec r0", "dec r1", "dec r2", "dec r3", "dec r4", "dec r5", "dec r6", "dec r7", + "dec r8", "dec r9", "dec r10", "dec r11", "dec r12", "dec r13", "dec r14", "getbs", + /* f0 - ff */ + "lm r0,($%04x)", "lm r1,($%04x)", "lm r2,($%04x)", "lm r3,($%04x)", + "lm r4,($%04x)", "lm r5,($%04x)", "lm r6,($%04x)", "lm r7,($%04x)", + "lm r8,($%04x)", "lm r9,($%04x)", "lm r10,($%04x)", "lm r11,($%04x)", + "lm r12,($%04x)", "lm r13,($%04x)", "lm r14,($%04x)", "lm r15,($%04x)", +}; + diff --git a/source/snes9x/fxemu.cpp b/source/snes9x/fxemu.cpp new file mode 100644 index 0000000..d2b15d1 --- /dev/null +++ b/source/snes9x/fxemu.cpp @@ -0,0 +1,783 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "fxemu.h" +#include "fxinst.h" +#include +#include +#include + +/* The FxChip Emulator's internal variables */ +struct FxRegs_s GSU = FxRegs_s_null; + +uint32 (**fx_ppfFunctionTable)(uint32) = 0; +void (**fx_ppfPlotTable)() = 0; +void (**fx_ppfOpcodeTable)() = 0; + +#if 0 +void fx_setCache() +{ + uint32 c; + GSU.bCacheActive = TRUE; + GSU.pvRegisters[0x3e] &= 0xf0; + c = (uint32)GSU.pvRegisters[0x3e]; + c |= ((uint32)GSU.pvRegisters[0x3f])<<8; + if(c == GSU.vCacheBaseReg) + return; + GSU.vCacheBaseReg = c; + GSU.vCacheFlags = 0; + if(c < (0x10000-512)) + { + uint8 const* t = &ROM(c); + memcpy(GSU.pvCache,t,512); + } + else + { + uint8 const* t1; + uint8 const* t2; + uint32 i = 0x10000 - c; + t1 = &ROM(c); + t2 = &ROM(0); + memcpy(GSU.pvCache,t1,i); + memcpy(&GSU.pvCache[i],t2,512-i); + } +} +#endif + +void FxCacheWriteAccess(uint16 vAddress) +{ +#if 0 + if(!GSU.bCacheActive) + { + uint8 v = GSU.pvCache[GSU.pvCache[vAddress&0x1ff]; + fx_setCache(); + GSU.pvCache[GSU.pvCache[vAddress&0x1ff] = v; + } +#endif + if((vAddress & 0x00f) == 0x00f) + GSU.vCacheFlags |= 1 << ((vAddress&0x1f0) >> 4); +} + +void FxFlushCache() +{ + GSU.vCacheFlags = 0; + GSU.vCacheBaseReg = 0; + GSU.bCacheActive = FALSE; +// GSU.vPipe = 0x1; +} + +static void fx_backupCache() +{ +#if 0 + uint32 i; + uint32 v = GSU.vCacheFlags; + uint32 c = USEX16(GSU.vCacheBaseReg); + if(v) + for(i=0; i<32; i++) + { + if(v&1) + { + if(c < (0x10000-16)) + { + uint8 * t = &GSU.pvPrgBank[c]; + memcpy(&GSU.avCacheBackup[i<<4],t,16); + memcpy(t,&GSU.pvCache[i<<4],16); + } + else + { + uint8 * t1; + uint8 * t2; + uint32 a = 0x10000 - c; + t1 = &GSU.pvPrgBank[c]; + t2 = &GSU.pvPrgBank[0]; + memcpy(&GSU.avCacheBackup[i<<4],t1,a); + memcpy(t1,&GSU.pvCache[i<<4],a); + memcpy(&GSU.avCacheBackup[(i<<4)+a],t2,16-a); + memcpy(t2,&GSU.pvCache[(i<<4)+a],16-a); + } + } + c = USEX16(c+16); + v >>= 1; + } +#endif +} + +static void fx_restoreCache() +{ +#if 0 + uint32 i; + uint32 v = GSU.vCacheFlags; + uint32 c = USEX16(GSU.vCacheBaseReg); + if(v) + for(i=0; i<32; i++) + { + if(v&1) + { + if(c < (0x10000-16)) + { + uint8 * t = &GSU.pvPrgBank[c]; + memcpy(t,&GSU.avCacheBackup[i<<4],16); + memcpy(&GSU.pvCache[i<<4],t,16); + } + else + { + uint8 * t1; + uint8 * t2; + uint32 a = 0x10000 - c; + t1 = &GSU.pvPrgBank[c]; + t2 = &GSU.pvPrgBank[0]; + memcpy(t1,&GSU.avCacheBackup[i<<4],a); + memcpy(&GSU.pvCache[i<<4],t1,a); + memcpy(t2,&GSU.avCacheBackup[(i<<4)+a],16-a); + memcpy(&GSU.pvCache[(i<<4)+a],t2,16-a); + } + } + c = USEX16(c+16); + v >>= 1; + } +#endif +} + +void fx_flushCache() +{ + fx_restoreCache(); + GSU.vCacheFlags = 0; + GSU.bCacheActive = FALSE; +} + + +void fx_updateRamBank(uint8 Byte) +{ + // Update BankReg and Bank pointer + GSU.vRamBankReg = (uint32)Byte & (FX_RAM_BANKS-1); + GSU.pvRamBank = GSU.apvRamBank[Byte & 0x3]; +} + + +static void fx_readRegisterSpace() +{ + int i; + uint8 *p; + static uint32 avHeight[] = { 128, 160, 192, 256 }; + static uint32 avMult[] = { 16, 32, 32, 64 }; + + GSU.vErrorCode = 0; + + /* Update R0-R15 */ + p = GSU.pvRegisters; + for(i=0; i<16; i++) + { + GSU.avReg[i] = *p++; + GSU.avReg[i] += ((uint32)(*p++)) << 8; + } + + /* Update other registers */ + p = GSU.pvRegisters; + GSU.vStatusReg = (uint32)p[GSU_SFR]; + GSU.vStatusReg |= ((uint32)p[GSU_SFR+1]) << 8; + GSU.vPrgBankReg = (uint32)p[GSU_PBR]; + GSU.vRomBankReg = (uint32)p[GSU_ROMBR]; + GSU.vRamBankReg = ((uint32)p[GSU_RAMBR]) & (FX_RAM_BANKS-1); + GSU.vCacheBaseReg = (uint32)p[GSU_CBR]; + GSU.vCacheBaseReg |= ((uint32)p[GSU_CBR+1]) << 8; + + /* Update status register variables */ + GSU.vZero = !(GSU.vStatusReg & FLG_Z); + GSU.vSign = (GSU.vStatusReg & FLG_S) << 12; + GSU.vOverflow = (GSU.vStatusReg & FLG_OV) << 16; + GSU.vCarry = (GSU.vStatusReg & FLG_CY) >> 2; + + /* Set bank pointers */ + GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3]; + GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg]; + GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg]; + + /* Set screen pointers */ + GSU.pvScreenBase = &GSU.pvRam[ USEX8(p[GSU_SCBR]) << 10 ]; + i = (int)(!!(p[GSU_SCMR] & 0x04)); + i |= ((int)(!!(p[GSU_SCMR] & 0x20))) << 1; + GSU.vScreenHeight = GSU.vScreenRealHeight = avHeight[i]; + GSU.vMode = p[GSU_SCMR] & 0x03; +#if 0 + if(GSU.vMode == 2) + error illegal color depth GSU.vMode; +#endif + if(i == 3) + GSU.vScreenSize = (256/8) * (256/8) * 32; + else + GSU.vScreenSize = (GSU.vScreenHeight/8) * (256/8) * avMult[GSU.vMode]; + if (GSU.vPlotOptionReg & 0x10) + { + /* OBJ Mode (for drawing into sprites) */ + GSU.vScreenHeight = 256; + } +#if 0 + if(GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536)) + error illegal address for screen base register +#else + if(GSU.pvScreenBase + GSU.vScreenSize > GSU.pvRam + (GSU.nRamBanks * 65536)) + GSU.pvScreenBase = GSU.pvRam + (GSU.nRamBanks * 65536) - GSU.vScreenSize; +#endif + GSU.pfPlot = fx_apfPlotTable[GSU.vMode]; + GSU.pfRpix = fx_apfPlotTable[GSU.vMode + 5]; + + fx_ppfOpcodeTable[0x04c] = GSU.pfPlot; + fx_ppfOpcodeTable[0x14c] = GSU.pfRpix; + fx_ppfOpcodeTable[0x24c] = GSU.pfPlot; + fx_ppfOpcodeTable[0x34c] = GSU.pfRpix; + + fx_computeScreenPointers (); + + fx_backupCache(); +} + +void fx_dirtySCBR() +{ + GSU.vSCBRDirty = TRUE; +} + +void fx_computeScreenPointers () +{ + if (GSU.vMode != GSU.vPrevMode || + GSU.vPrevScreenHeight != GSU.vScreenHeight || + GSU.vSCBRDirty) + { + int i; + + GSU.vSCBRDirty = FALSE; + + /* Make a list of pointers to the start of each screen column */ + switch (GSU.vScreenHeight) + { + case 128: + switch (GSU.vMode) + { + case 0: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); + GSU.x[i] = i << 8; + } + break; + case 1: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); + GSU.x[i] = i << 9; + } + break; + case 2: + case 3: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); + GSU.x[i] = i << 10; + } + break; + } + break; + case 160: + switch (GSU.vMode) + { + case 0: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); + GSU.x[i] = (i << 8) + (i << 6); + } + break; + case 1: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); + GSU.x[i] = (i << 9) + (i << 7); + } + break; + case 2: + case 3: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); + GSU.x[i] = (i << 10) + (i << 8); + } + break; + } + break; + case 192: + switch (GSU.vMode) + { + case 0: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 4); + GSU.x[i] = (i << 8) + (i << 7); + } + break; + case 1: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 5); + GSU.x[i] = (i << 9) + (i << 8); + } + break; + case 2: + case 3: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + (i << 6); + GSU.x[i] = (i << 10) + (i << 9); + } + break; + } + break; + case 256: + switch (GSU.vMode) + { + case 0: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + + ((i & 0x10) << 9) + ((i & 0xf) << 8); + GSU.x[i] = ((i & 0x10) << 8) + ((i & 0xf) << 4); + } + break; + case 1: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + + ((i & 0x10) << 10) + ((i & 0xf) << 9); + GSU.x[i] = ((i & 0x10) << 9) + ((i & 0xf) << 5); + } + break; + case 2: + case 3: + for (i = 0; i < 32; i++) + { + GSU.apvScreen[i] = GSU.pvScreenBase + + ((i & 0x10) << 11) + ((i & 0xf) << 10); + GSU.x[i] = ((i & 0x10) << 10) + ((i & 0xf) << 6); + } + break; + } + break; + } + GSU.vPrevMode = GSU.vMode; + GSU.vPrevScreenHeight = GSU.vScreenHeight; + } +} + +static void fx_writeRegisterSpace() +{ + int i; + uint8 *p; + + p = GSU.pvRegisters; + for(i=0; i<16; i++) + { + *p++ = (uint8)GSU.avReg[i]; + *p++ = (uint8)(GSU.avReg[i] >> 8); + } + + /* Update status register */ + if( USEX16(GSU.vZero) == 0 ) SF(Z); + else CF(Z); + if( GSU.vSign & 0x8000 ) SF(S); + else CF(S); + if(GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000) SF(OV); + else CF(OV); + if(GSU.vCarry) SF(CY); + else CF(CY); + + p = GSU.pvRegisters; + p[GSU_SFR] = (uint8)GSU.vStatusReg; + p[GSU_SFR+1] = (uint8)(GSU.vStatusReg>>8); + p[GSU_PBR] = (uint8)GSU.vPrgBankReg; + p[GSU_ROMBR] = (uint8)GSU.vRomBankReg; + p[GSU_RAMBR] = (uint8)GSU.vRamBankReg; + p[GSU_CBR] = (uint8)GSU.vCacheBaseReg; + p[GSU_CBR+1] = (uint8)(GSU.vCacheBaseReg>>8); + + fx_restoreCache(); +} + +/* Reset the FxChip */ +void FxReset(struct FxInit_s *psFxInfo) +{ + int i; + static uint32 (**appfFunction[])(uint32) = { + &fx_apfFunctionTable[0], +#if 0 + &fx_a_apfFunctionTable[0], + &fx_r_apfFunctionTable[0], + &fx_ar_apfFunctionTable[0], +#endif + }; + static void (**appfPlot[])() = { + &fx_apfPlotTable[0], +#if 0 + &fx_a_apfPlotTable[0], + &fx_r_apfPlotTable[0], + &fx_ar_apfPlotTable[0], +#endif + }; + static void (**appfOpcode[])() = { + &fx_apfOpcodeTable[0], +#if 0 + &fx_a_apfOpcodeTable[0], + &fx_r_apfOpcodeTable[0], + &fx_ar_apfOpcodeTable[0], +#endif + }; + + /* Get function pointers for the current emulation mode */ + fx_ppfFunctionTable = appfFunction[psFxInfo->vFlags & 0x3]; + fx_ppfPlotTable = appfPlot[psFxInfo->vFlags & 0x3]; + fx_ppfOpcodeTable = appfOpcode[psFxInfo->vFlags & 0x3]; + + /* Clear all internal variables */ + memset((uint8*)&GSU,0,sizeof(struct FxRegs_s)); + + /* Set default registers */ + GSU.pvSreg = GSU.pvDreg = &R0; + + /* Set RAM and ROM pointers */ + GSU.pvRegisters = psFxInfo->pvRegisters; + GSU.nRamBanks = psFxInfo->nRamBanks; + GSU.pvRam = psFxInfo->pvRam; + GSU.nRomBanks = psFxInfo->nRomBanks; + GSU.pvRom = psFxInfo->pvRom; + GSU.vPrevScreenHeight = ~0; + GSU.vPrevMode = ~0; + + /* The GSU can't access more than 2mb (16mbits) */ + if(GSU.nRomBanks > 0x20) + GSU.nRomBanks = 0x20; + + /* Clear FxChip register space */ + memset(GSU.pvRegisters,0,0x300); + + /* Set FxChip version Number */ + GSU.pvRegisters[0x3b] = 0; + + /* Make ROM bank table */ + for(i=0; i<256; i++) + { + uint32 b = i & 0x7f; + if (b >= 0x40) + { + if (GSU.nRomBanks > 1) + b %= GSU.nRomBanks; + else + b &= 1; + + GSU.apvRomBank[i] = &GSU.pvRom[ b << 16 ]; + } + else + { + b %= GSU.nRomBanks * 2; + GSU.apvRomBank[i] = &GSU.pvRom[ (b << 16) + 0x200000]; + } + } + + /* Make RAM bank table */ + for(i=0; i<4; i++) + { + GSU.apvRamBank[i] = &GSU.pvRam[(i % GSU.nRamBanks) << 16]; + GSU.apvRomBank[0x70 + i] = GSU.apvRamBank[i]; + } + + /* Start with a nop in the pipe */ + GSU.vPipe = 0x01; + + /* Set pointer to GSU cache */ + GSU.pvCache = &GSU.pvRegisters[0x100]; + + fx_readRegisterSpace(); +} + +static uint8 fx_checkStartAddress() +{ + /* Check if we start inside the cache */ + if(GSU.bCacheActive && R15 >= GSU.vCacheBaseReg && R15 < (GSU.vCacheBaseReg+512)) + return TRUE; + + /* Check if we're in an unused area */ +#if 0 + if(GSU.vPrgBankReg < 0x40 && R15 < 0x8000) + return FALSE; +#endif + if(GSU.vPrgBankReg >= 0x60 && GSU.vPrgBankReg <= 0x6f) + return FALSE; + if(GSU.vPrgBankReg >= 0x74) + return FALSE; + + /* Check if we're in RAM and the RAN flag is not set */ + if(GSU.vPrgBankReg >= 0x70 && GSU.vPrgBankReg <= 0x73 && !(SCMR&(1<<3)) ) + return FALSE; + + /* If not, we're in ROM, so check if the RON flag is set */ + if(!(SCMR&(1<<4))) + return FALSE; + + return TRUE; +} + +/* Execute until the next stop instruction */ +int FxEmulate(uint32 nInstructions) +{ + uint32 vCount; + + /* Read registers and initialize GSU session */ + fx_readRegisterSpace(); + + /* Check if the start address is valid */ + if(!fx_checkStartAddress()) + { + CF(G); + fx_writeRegisterSpace(); +#if 0 + GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15; + return FX_ERROR_ILLEGAL_ADDRESS; +#else + return 0; +#endif + } + + /* Execute GSU session */ + CF(IRQ); + + if(GSU.bBreakPoint) + vCount = fx_ppfFunctionTable[FX_FUNCTION_RUN_TO_BREAKPOINT](nInstructions); + else + vCount = fx_ppfFunctionTable[FX_FUNCTION_RUN](nInstructions); + + /* Store GSU registers */ + fx_writeRegisterSpace(); + + /* Check for error code */ + if(GSU.vErrorCode) + return GSU.vErrorCode; + else + return vCount; +} + +/* Breakpoints */ +void FxBreakPointSet(uint32 vAddress) +{ + GSU.bBreakPoint = TRUE; + GSU.vBreakPoint = USEX16(vAddress); +} +void FxBreakPointClear() +{ + GSU.bBreakPoint = FALSE; +} + +/* Step by step execution */ +int FxStepOver(uint32 nInstructions) +{ + uint32 vCount; + fx_readRegisterSpace(); + + /* Check if the start address is valid */ + if(!fx_checkStartAddress()) + { + CF(G); +#if 0 + GSU.vIllegalAddress = (GSU.vPrgBankReg << 24) | R15; + return FX_ERROR_ILLEGAL_ADDRESS; +#else + return 0; +#endif + } + + if( PIPE >= 0xf0 ) + GSU.vStepPoint = USEX16(R15+3); + else if( (PIPE >= 0x05 && PIPE <= 0x0f) || (PIPE >= 0xa0 && PIPE <= 0xaf) ) + GSU.vStepPoint = USEX16(R15+2); + else + GSU.vStepPoint = USEX16(R15+1); + vCount = fx_ppfFunctionTable[FX_FUNCTION_STEP_OVER](nInstructions); + fx_writeRegisterSpace(); + if(GSU.vErrorCode) + return GSU.vErrorCode; + else + return vCount; +} + +/* Errors */ +int FxGetErrorCode() +{ + return GSU.vErrorCode; +} + +int FxGetIllegalAddress() +{ + return GSU.vIllegalAddress; +} + +/* Access to internal registers */ +uint32 FxGetColorRegister() +{ + return GSU.vColorReg & 0xff; +} + +uint32 FxGetPlotOptionRegister() +{ + return GSU.vPlotOptionReg & 0x1f; +} + +uint32 FxGetSourceRegisterIndex() +{ + return GSU.pvSreg - GSU.avReg; +} + +uint32 FxGetDestinationRegisterIndex() +{ + return GSU.pvDreg - GSU.avReg; +} + +uint8 FxPipe() +{ + return GSU.vPipe; +} + diff --git a/source/snes9x/fxemu.h b/source/snes9x/fxemu.h new file mode 100644 index 0000000..22f8d5a --- /dev/null +++ b/source/snes9x/fxemu.h @@ -0,0 +1,215 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _FXEMU_H_ +#define _FXEMU_H_ 1 + +#include "port.h" + +/* The FxInfo_s structure, the link between the FxEmulator and the Snes Emulator */ +struct FxInit_s +{ + uint32 vFlags; + uint8 * pvRegisters; /* 768 bytes located in the memory at address 0x3000 */ + uint32 nRamBanks; /* Number of 64kb-banks in GSU-RAM/BackupRAM (banks 0x70-0x73) */ + uint8 * pvRam; /* Pointer to GSU-RAM */ + uint32 nRomBanks; /* Number of 32kb-banks in Cart-ROM */ + uint8 * pvRom; /* Pointer to Cart-ROM */ + uint32 speedPerLine; + bool8 oneLineDone; +}; + +/* Reset the FxChip */ +extern void FxReset(struct FxInit_s *psFxInfo); + +/* Execute until the next stop instruction */ +extern int FxEmulate(uint32 nInstructions); + +/* Write access to the cache */ +extern void FxCacheWriteAccess(uint16 vAddress); +extern void FxFlushCache(); /* Callled when the G flag in SFR is set to zero */ + +/* Breakpoint */ +extern void FxBreakPointSet(uint32 vAddress); +extern void FxBreakPointClear(); + +/* Step by step execution */ +extern int FxStepOver(uint32 nInstructions); + +/* Errors */ +extern int FxGetErrorCode(); +extern int FxGetIllegalAddress(); + +/* Access to internal registers */ +extern uint32 FxGetColorRegister(); +extern uint32 FxGetPlotOptionRegister(); +extern uint32 FxGetSourceRegisterIndex(); +extern uint32 FxGetDestinationRegisterIndex(); + +/* Get string for opcode currently in the pipe */ +extern void FxPipeString(char * pvString); + +/* Get the byte currently in the pipe */ +extern uint8 FxPipe(); + +/* SCBR write seen. We need to update our cached screen pointers */ +extern void fx_dirtySCBR (void); + +/* Update RamBankReg and RAM Bank pointer */ +extern void fx_updateRamBank(uint8 Byte); + +/* Option flags */ +#define FX_FLAG_ADDRESS_CHECKING 0x01 +#define FX_FLAG_ROM_BUFFER 0x02 + +/* Return codes from FxEmulate(), FxStepInto() or FxStepOver() */ +#define FX_BREAKPOINT -1 +#define FX_ERROR_ILLEGAL_ADDRESS -2 + +/* Return the number of bytes in an opcode */ +#define OPCODE_BYTES(op) ((((op)>=0x05&&(op)<=0xf)||((op)>=0xa0&&(op)<=0xaf))?2:(((op)>=0xf0)?3:1)) + +extern void fx_computeScreenPointers (); + +#endif + diff --git a/source/snes9x/fxinst.cpp b/source/snes9x/fxinst.cpp new file mode 100644 index 0000000..76ee3e8 --- /dev/null +++ b/source/snes9x/fxinst.cpp @@ -0,0 +1,1971 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#define FX_DO_ROMBUFFER + +#include "fxemu.h" +#include "fxinst.h" +#include +#include + +extern struct FxRegs_s GSU; +int gsu_bank [512] = {0}; + +/* Set this define if you wish the plot instruction to check for y-pos limits */ +/* (I don't think it's nessecary) */ +#define CHECK_LIMITS + +/* Codes used: + * + * rn = a GSU register (r0-r15) + * #n = 4 bit immediate value + * #pp = 8 bit immediate value + * (yy) = 8 bit word address (0x0000 - 0x01fe) + * #xx = 16 bit immediate value + * (xx) = 16 bit address (0x0000 - 0xffff) + * + */ + +/* 00 - stop - stop GSU execution (and maybe generate an IRQ) */ +static void fx_stop() +{ + CF(G); + GSU.vCounter = 0; + GSU.vInstCount = GSU.vCounter; + + /* Check if we need to generate an IRQ */ + if(!(GSU.pvRegisters[GSU_CFGR] & 0x80)) + SF(IRQ); + + GSU.vPlotOptionReg = 0; + GSU.vPipe = 1; + CLRFLAGS; + R15++; +} + +/* 01 - nop - no operation */ +static void fx_nop() { CLRFLAGS; R15++; } + +extern void fx_flushCache(); + +/* 02 - cache - reintialize GSU cache */ +static void fx_cache() +{ + uint32 c = R15 & 0xfff0; + if(GSU.vCacheBaseReg != c || !GSU.bCacheActive) + { + fx_flushCache(); + GSU.vCacheBaseReg = c; + GSU.bCacheActive = TRUE; +#if 0 + if(c < (0x10000-512)) + { + uint8 const* t = &ROM(c); + memcpy(GSU.pvCache,t,512); + } + else + { + uint8 const* t1; + uint8 const* t2; + uint32 i = 0x10000 - c; + t1 = &ROM(c); + t2 = &ROM(0); + memcpy(GSU.pvCache,t1,i); + memcpy(&GSU.pvCache[i],t2,512-i); + } +#endif + } + R15++; + CLRFLAGS; +} + +/* 03 - lsr - logic shift right */ +static void fx_lsr() +{ + uint32 v; + GSU.vCarry = SREG & 1; + v = USEX16(SREG) >> 1; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 04 - rol - rotate left */ +static void fx_rol() +{ + uint32 v = USEX16((SREG << 1) + GSU.vCarry); + GSU.vCarry = (SREG >> 15) & 1; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 05 - bra - branch always */ +static void fx_bra() { uint8 v = PIPE; R15++; FETCHPIPE; R15 += SEX8(v); } + +/* Branch on condition */ +#define BRA_COND(cond) uint8 v = PIPE; R15++; FETCHPIPE; if(cond) R15 += SEX8(v); else R15++; + +#define TEST_S (GSU.vSign & 0x8000) +#define TEST_Z (USEX16(GSU.vZero) == 0) +#define TEST_OV (GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000) +#define TEST_CY (GSU.vCarry & 1) + +/* 06 - blt - branch on less than */ +static void fx_blt() { BRA_COND( (TEST_S!=0) != (TEST_OV!=0) ); } + +/* 07 - bge - branch on greater or equals */ +static void fx_bge() { BRA_COND( (TEST_S!=0) == (TEST_OV!=0)); } + +/* 08 - bne - branch on not equal */ +static void fx_bne() { BRA_COND( !TEST_Z ); } + +/* 09 - beq - branch on equal */ +static void fx_beq() { BRA_COND( TEST_Z ); } + +/* 0a - bpl - branch on plus */ +static void fx_bpl() { BRA_COND( !TEST_S ); } + +/* 0b - bmi - branch on minus */ +static void fx_bmi() { BRA_COND( TEST_S ); } + +/* 0c - bcc - branch on carry clear */ +static void fx_bcc() { BRA_COND( !TEST_CY ); } + +/* 0d - bcs - branch on carry set */ +static void fx_bcs() { BRA_COND( TEST_CY ); } + +/* 0e - bvc - branch on overflow clear */ +static void fx_bvc() { BRA_COND( !TEST_OV ); } + +/* 0f - bvs - branch on overflow set */ +static void fx_bvs() { BRA_COND( TEST_OV ); } + +/* 10-1f - to rn - set register n as destination register */ +/* 10-1f(B) - move rn - move one register to another (if B flag is set) */ +#define FX_TO(reg) \ +if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; } \ +else { GSU.pvDreg = &GSU.avReg[reg]; } R15++; +#define FX_TO_R14(reg) \ +if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; READR14; } \ +else { GSU.pvDreg = &GSU.avReg[reg]; } R15++; +#define FX_TO_R15(reg) \ +if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; } \ +else { GSU.pvDreg = &GSU.avReg[reg]; R15++; } +static void fx_to_r0() { FX_TO(0); } +static void fx_to_r1() { FX_TO(1); } +static void fx_to_r2() { FX_TO(2); } +static void fx_to_r3() { FX_TO(3); } +static void fx_to_r4() { FX_TO(4); } +static void fx_to_r5() { FX_TO(5); } +static void fx_to_r6() { FX_TO(6); } +static void fx_to_r7() { FX_TO(7); } +static void fx_to_r8() { FX_TO(8); } +static void fx_to_r9() { FX_TO(9); } +static void fx_to_r10() { FX_TO(10); } +static void fx_to_r11() { FX_TO(11); } +static void fx_to_r12() { FX_TO(12); } +static void fx_to_r13() { FX_TO(13); } +static void fx_to_r14() { FX_TO_R14(14); } +static void fx_to_r15() { FX_TO_R15(15); } + +/* 20-2f - to rn - set register n as source and destination register */ +#define FX_WITH(reg) SF(B); GSU.pvSreg = GSU.pvDreg = &GSU.avReg[reg]; R15++; +static void fx_with_r0() { FX_WITH(0); } +static void fx_with_r1() { FX_WITH(1); } +static void fx_with_r2() { FX_WITH(2); } +static void fx_with_r3() { FX_WITH(3); } +static void fx_with_r4() { FX_WITH(4); } +static void fx_with_r5() { FX_WITH(5); } +static void fx_with_r6() { FX_WITH(6); } +static void fx_with_r7() { FX_WITH(7); } +static void fx_with_r8() { FX_WITH(8); } +static void fx_with_r9() { FX_WITH(9); } +static void fx_with_r10() { FX_WITH(10); } +static void fx_with_r11() { FX_WITH(11); } +static void fx_with_r12() { FX_WITH(12); } +static void fx_with_r13() { FX_WITH(13); } +static void fx_with_r14() { FX_WITH(14); } +static void fx_with_r15() { FX_WITH(15); } + +/* 30-3b - stw (rn) - store word */ +#define FX_STW(reg) \ +GSU.vLastRamAdr = GSU.avReg[reg]; \ +RAM(GSU.avReg[reg]) = (uint8)SREG; \ +RAM(GSU.avReg[reg]^1) = (uint8)(SREG>>8); \ +CLRFLAGS; R15++ +static void fx_stw_r0() { FX_STW(0); } +static void fx_stw_r1() { FX_STW(1); } +static void fx_stw_r2() { FX_STW(2); } +static void fx_stw_r3() { FX_STW(3); } +static void fx_stw_r4() { FX_STW(4); } +static void fx_stw_r5() { FX_STW(5); } +static void fx_stw_r6() { FX_STW(6); } +static void fx_stw_r7() { FX_STW(7); } +static void fx_stw_r8() { FX_STW(8); } +static void fx_stw_r9() { FX_STW(9); } +static void fx_stw_r10() { FX_STW(10); } +static void fx_stw_r11() { FX_STW(11); } + +/* 30-3b(ALT1) - stb (rn) - store byte */ +#define FX_STB(reg) \ +GSU.vLastRamAdr = GSU.avReg[reg]; \ +RAM(GSU.avReg[reg]) = (uint8)SREG; \ +CLRFLAGS; R15++ +static void fx_stb_r0() { FX_STB(0); } +static void fx_stb_r1() { FX_STB(1); } +static void fx_stb_r2() { FX_STB(2); } +static void fx_stb_r3() { FX_STB(3); } +static void fx_stb_r4() { FX_STB(4); } +static void fx_stb_r5() { FX_STB(5); } +static void fx_stb_r6() { FX_STB(6); } +static void fx_stb_r7() { FX_STB(7); } +static void fx_stb_r8() { FX_STB(8); } +static void fx_stb_r9() { FX_STB(9); } +static void fx_stb_r10() { FX_STB(10); } +static void fx_stb_r11() { FX_STB(11); } + +/* 3c - loop - decrement loop counter, and branch on not zero */ +static void fx_loop() +{ + GSU.vSign = GSU.vZero = --R12; + if( (uint16) R12 != 0 ) + R15 = R13; + else + R15++; + + CLRFLAGS; +} + +/* 3d - alt1 - set alt1 mode */ +static void fx_alt1() { SF(ALT1); CF(B); R15++; } + +/* 3e - alt2 - set alt2 mode */ +static void fx_alt2() { SF(ALT2); CF(B); R15++; } + +/* 3f - alt3 - set alt3 mode */ +static void fx_alt3() { SF(ALT1); SF(ALT2); CF(B); R15++; } + +/* 40-4b - ldw (rn) - load word from RAM */ +#define FX_LDW(reg) uint32 v; \ +GSU.vLastRamAdr = GSU.avReg[reg]; \ +v = (uint32)RAM(GSU.avReg[reg]); \ +v |= ((uint32)RAM(GSU.avReg[reg]^1))<<8; \ +R15++; DREG = v; \ +TESTR14; \ +CLRFLAGS +static void fx_ldw_r0() { FX_LDW(0); } +static void fx_ldw_r1() { FX_LDW(1); } +static void fx_ldw_r2() { FX_LDW(2); } +static void fx_ldw_r3() { FX_LDW(3); } +static void fx_ldw_r4() { FX_LDW(4); } +static void fx_ldw_r5() { FX_LDW(5); } +static void fx_ldw_r6() { FX_LDW(6); } +static void fx_ldw_r7() { FX_LDW(7); } +static void fx_ldw_r8() { FX_LDW(8); } +static void fx_ldw_r9() { FX_LDW(9); } +static void fx_ldw_r10() { FX_LDW(10); } +static void fx_ldw_r11() { FX_LDW(11); } + +/* 40-4b(ALT1) - ldb (rn) - load byte */ +#define FX_LDB(reg) uint32 v; \ +GSU.vLastRamAdr = GSU.avReg[reg]; \ +v = (uint32)RAM(GSU.avReg[reg]); \ +R15++; DREG = v; \ +TESTR14; \ +CLRFLAGS +static void fx_ldb_r0() { FX_LDB(0); } +static void fx_ldb_r1() { FX_LDB(1); } +static void fx_ldb_r2() { FX_LDB(2); } +static void fx_ldb_r3() { FX_LDB(3); } +static void fx_ldb_r4() { FX_LDB(4); } +static void fx_ldb_r5() { FX_LDB(5); } +static void fx_ldb_r6() { FX_LDB(6); } +static void fx_ldb_r7() { FX_LDB(7); } +static void fx_ldb_r8() { FX_LDB(8); } +static void fx_ldb_r9() { FX_LDB(9); } +static void fx_ldb_r10() { FX_LDB(10); } +static void fx_ldb_r11() { FX_LDB(11); } + +/* 4c - plot - plot pixel with R1,R2 as x,y and the color register as the color */ +static void fx_plot_2bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v,c; + + R15++; + CLRFLAGS; + R1++; + +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + if(GSU.vPlotOptionReg & 0x02) + c = (x^y)&1 ? (uint8)(GSU.vColorReg>>4) : (uint8)GSU.vColorReg; + else + c = (uint8)GSU.vColorReg; + + if( !(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return; + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + if(c & 0x01) a[0] |= v; + else a[0] &= ~v; + if(c & 0x02) a[1] |= v; + else a[1] &= ~v; +} + +/* 2c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */ +static void fx_rpix_2bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v; + + R15++; + CLRFLAGS; +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + DREG = 0; + DREG |= ((uint32)((a[0] & v) != 0)) << 0; + DREG |= ((uint32)((a[1] & v) != 0)) << 1; + TESTR14; +} + +/* 4c - plot - plot pixel with R1,R2 as x,y and the color register as the color */ +static void fx_plot_4bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v,c; + + R15++; + CLRFLAGS; + R1++; + +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + if(GSU.vPlotOptionReg & 0x02) + c = (x^y)&1 ? (uint8)(GSU.vColorReg>>4) : (uint8)GSU.vColorReg; + else + c = (uint8)GSU.vColorReg; + + if( !(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return; + + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + if(c & 0x01) a[0x00] |= v; + else a[0x00] &= ~v; + if(c & 0x02) a[0x01] |= v; + else a[0x01] &= ~v; + if(c & 0x04) a[0x10] |= v; + else a[0x10] &= ~v; + if(c & 0x08) a[0x11] |= v; + else a[0x11] &= ~v; +} + +/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */ +static void fx_rpix_4bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v; + + R15++; + CLRFLAGS; + +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + DREG = 0; + DREG |= ((uint32)((a[0x00] & v) != 0)) << 0; + DREG |= ((uint32)((a[0x01] & v) != 0)) << 1; + DREG |= ((uint32)((a[0x10] & v) != 0)) << 2; + DREG |= ((uint32)((a[0x11] & v) != 0)) << 3; + TESTR14; +} + +/* 8c - plot - plot pixel with R1,R2 as x,y and the color register as the color */ +static void fx_plot_8bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v,c; + + R15++; + CLRFLAGS; + R1++; + +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + c = (uint8)GSU.vColorReg; + if( !(GSU.vPlotOptionReg & 0x10) ) + { + if( !(GSU.vPlotOptionReg & 0x01) && !(c&0xf)) return; + } + else + if( !(GSU.vPlotOptionReg & 0x01) && !c) return; + + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + if(c & 0x01) a[0x00] |= v; + else a[0x00] &= ~v; + if(c & 0x02) a[0x01] |= v; + else a[0x01] &= ~v; + if(c & 0x04) a[0x10] |= v; + else a[0x10] &= ~v; + if(c & 0x08) a[0x11] |= v; + else a[0x11] &= ~v; + if(c & 0x10) a[0x20] |= v; + else a[0x20] &= ~v; + if(c & 0x20) a[0x21] |= v; + else a[0x21] &= ~v; + if(c & 0x40) a[0x30] |= v; + else a[0x30] &= ~v; + if(c & 0x80) a[0x31] |= v; + else a[0x31] &= ~v; +} + +/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */ +static void fx_rpix_8bit() +{ + uint32 x = USEX8(R1); + uint32 y = USEX8(R2); + uint8 *a; + uint8 v; + + R15++; + CLRFLAGS; + +#ifdef CHECK_LIMITS + if(y >= GSU.vScreenHeight) return; +#endif + a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1); + v = 128 >> (x&7); + + DREG = 0; + DREG |= ((uint32)((a[0x00] & v) != 0)) << 0; + DREG |= ((uint32)((a[0x01] & v) != 0)) << 1; + DREG |= ((uint32)((a[0x10] & v) != 0)) << 2; + DREG |= ((uint32)((a[0x11] & v) != 0)) << 3; + DREG |= ((uint32)((a[0x20] & v) != 0)) << 4; + DREG |= ((uint32)((a[0x21] & v) != 0)) << 5; + DREG |= ((uint32)((a[0x30] & v) != 0)) << 6; + DREG |= ((uint32)((a[0x31] & v) != 0)) << 7; + GSU.vZero = DREG; + TESTR14; +} + +/* 4o - plot - plot pixel with R1,R2 as x,y and the color register as the color */ +static void fx_plot_obj() +{ + printf ("ERROR fx_plot_obj called\n"); +} + +/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */ +static void fx_rpix_obj() +{ + printf ("ERROR fx_rpix_obj called\n"); +} + +/* 4d - swap - swap upper and lower byte of a register */ +static void fx_swap() +{ + uint8 c = (uint8)SREG; + uint8 d = (uint8)(SREG>>8); + uint32 v = (((uint32)c)<<8)|((uint32)d); + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 4e - color - copy source register to color register */ +static void fx_color() +{ + uint8 c = (uint8)SREG; + if(GSU.vPlotOptionReg & 0x04) + c = (c&0xf0) | (c>>4); + if(GSU.vPlotOptionReg & 0x08) + { + GSU.vColorReg &= 0xf0; + GSU.vColorReg |= c & 0x0f; + } + else + GSU.vColorReg = USEX8(c); + CLRFLAGS; + R15++; +} + +/* 4e(ALT1) - cmode - set plot option register */ +static void fx_cmode() +{ + GSU.vPlotOptionReg = SREG; + + if(GSU.vPlotOptionReg & 0x10) + { + /* OBJ Mode (for drawing into sprites) */ + GSU.vScreenHeight = 256; + } + else + GSU.vScreenHeight = GSU.vScreenRealHeight; + + fx_computeScreenPointers (); + CLRFLAGS; + R15++; +} + +/* 4f - not - perform exclusive exor with 1 on all bits */ +static void fx_not() +{ + uint32 v = ~SREG; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 50-5f - add rn - add, register + register */ +#define FX_ADD(reg) \ +int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]); \ +GSU.vCarry = s >= 0x10000; \ +GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_add_r0() { FX_ADD(0); } +static void fx_add_r1() { FX_ADD(1); } +static void fx_add_r2() { FX_ADD(2); } +static void fx_add_r3() { FX_ADD(3); } +static void fx_add_r4() { FX_ADD(4); } +static void fx_add_r5() { FX_ADD(5); } +static void fx_add_r6() { FX_ADD(6); } +static void fx_add_r7() { FX_ADD(7); } +static void fx_add_r8() { FX_ADD(8); } +static void fx_add_r9() { FX_ADD(9); } +static void fx_add_r10() { FX_ADD(10); } +static void fx_add_r11() { FX_ADD(11); } +static void fx_add_r12() { FX_ADD(12); } +static void fx_add_r13() { FX_ADD(13); } +static void fx_add_r14() { FX_ADD(14); } +static void fx_add_r15() { FX_ADD(15); } + +/* 50-5f(ALT1) - adc rn - add with carry, register + register */ +#define FX_ADC(reg) \ +int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]) + SEX16(GSU.vCarry); \ +GSU.vCarry = s >= 0x10000; \ +GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_adc_r0() { FX_ADC(0); } +static void fx_adc_r1() { FX_ADC(1); } +static void fx_adc_r2() { FX_ADC(2); } +static void fx_adc_r3() { FX_ADC(3); } +static void fx_adc_r4() { FX_ADC(4); } +static void fx_adc_r5() { FX_ADC(5); } +static void fx_adc_r6() { FX_ADC(6); } +static void fx_adc_r7() { FX_ADC(7); } +static void fx_adc_r8() { FX_ADC(8); } +static void fx_adc_r9() { FX_ADC(9); } +static void fx_adc_r10() { FX_ADC(10); } +static void fx_adc_r11() { FX_ADC(11); } +static void fx_adc_r12() { FX_ADC(12); } +static void fx_adc_r13() { FX_ADC(13); } +static void fx_adc_r14() { FX_ADC(14); } +static void fx_adc_r15() { FX_ADC(15); } + +/* 50-5f(ALT2) - add #n - add, register + immediate */ +#define FX_ADD_I(imm) \ +int32 s = SUSEX16(SREG) + imm; \ +GSU.vCarry = s >= 0x10000; \ +GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_add_i0() { FX_ADD_I(0); } +static void fx_add_i1() { FX_ADD_I(1); } +static void fx_add_i2() { FX_ADD_I(2); } +static void fx_add_i3() { FX_ADD_I(3); } +static void fx_add_i4() { FX_ADD_I(4); } +static void fx_add_i5() { FX_ADD_I(5); } +static void fx_add_i6() { FX_ADD_I(6); } +static void fx_add_i7() { FX_ADD_I(7); } +static void fx_add_i8() { FX_ADD_I(8); } +static void fx_add_i9() { FX_ADD_I(9); } +static void fx_add_i10() { FX_ADD_I(10); } +static void fx_add_i11() { FX_ADD_I(11); } +static void fx_add_i12() { FX_ADD_I(12); } +static void fx_add_i13() { FX_ADD_I(13); } +static void fx_add_i14() { FX_ADD_I(14); } +static void fx_add_i15() { FX_ADD_I(15); } + +/* 50-5f(ALT3) - adc #n - add with carry, register + immediate */ +#define FX_ADC_I(imm) \ +int32 s = SUSEX16(SREG) + imm + SUSEX16(GSU.vCarry); \ +GSU.vCarry = s >= 0x10000; \ +GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_adc_i0() { FX_ADC_I(0); } +static void fx_adc_i1() { FX_ADC_I(1); } +static void fx_adc_i2() { FX_ADC_I(2); } +static void fx_adc_i3() { FX_ADC_I(3); } +static void fx_adc_i4() { FX_ADC_I(4); } +static void fx_adc_i5() { FX_ADC_I(5); } +static void fx_adc_i6() { FX_ADC_I(6); } +static void fx_adc_i7() { FX_ADC_I(7); } +static void fx_adc_i8() { FX_ADC_I(8); } +static void fx_adc_i9() { FX_ADC_I(9); } +static void fx_adc_i10() { FX_ADC_I(10); } +static void fx_adc_i11() { FX_ADC_I(11); } +static void fx_adc_i12() { FX_ADC_I(12); } +static void fx_adc_i13() { FX_ADC_I(13); } +static void fx_adc_i14() { FX_ADC_I(14); } +static void fx_adc_i15() { FX_ADC_I(15); } + +/* 60-6f - sub rn - subtract, register - register */ +#define FX_SUB(reg) \ +int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \ +GSU.vCarry = s >= 0; \ +GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_sub_r0() { FX_SUB(0); } +static void fx_sub_r1() { FX_SUB(1); } +static void fx_sub_r2() { FX_SUB(2); } +static void fx_sub_r3() { FX_SUB(3); } +static void fx_sub_r4() { FX_SUB(4); } +static void fx_sub_r5() { FX_SUB(5); } +static void fx_sub_r6() { FX_SUB(6); } +static void fx_sub_r7() { FX_SUB(7); } +static void fx_sub_r8() { FX_SUB(8); } +static void fx_sub_r9() { FX_SUB(9); } +static void fx_sub_r10() { FX_SUB(10); } +static void fx_sub_r11() { FX_SUB(11); } +static void fx_sub_r12() { FX_SUB(12); } +static void fx_sub_r13() { FX_SUB(13); } +static void fx_sub_r14() { FX_SUB(14); } +static void fx_sub_r15() { FX_SUB(15); } + +/* 60-6f(ALT1) - sbc rn - subtract with carry, register - register */ +#define FX_SBC(reg) \ +int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]) - (SUSEX16(GSU.vCarry^1)); \ +GSU.vCarry = s >= 0; \ +GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_sbc_r0() { FX_SBC(0); } +static void fx_sbc_r1() { FX_SBC(1); } +static void fx_sbc_r2() { FX_SBC(2); } +static void fx_sbc_r3() { FX_SBC(3); } +static void fx_sbc_r4() { FX_SBC(4); } +static void fx_sbc_r5() { FX_SBC(5); } +static void fx_sbc_r6() { FX_SBC(6); } +static void fx_sbc_r7() { FX_SBC(7); } +static void fx_sbc_r8() { FX_SBC(8); } +static void fx_sbc_r9() { FX_SBC(9); } +static void fx_sbc_r10() { FX_SBC(10); } +static void fx_sbc_r11() { FX_SBC(11); } +static void fx_sbc_r12() { FX_SBC(12); } +static void fx_sbc_r13() { FX_SBC(13); } +static void fx_sbc_r14() { FX_SBC(14); } +static void fx_sbc_r15() { FX_SBC(15); } + +/* 60-6f(ALT2) - sub #n - subtract, register - immediate */ +#define FX_SUB_I(imm) \ +int32 s = SUSEX16(SREG) - imm; \ +GSU.vCarry = s >= 0; \ +GSU.vOverflow = (SREG ^ imm) & (SREG ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; DREG = s; \ +TESTR14; \ +CLRFLAGS +static void fx_sub_i0() { FX_SUB_I(0); } +static void fx_sub_i1() { FX_SUB_I(1); } +static void fx_sub_i2() { FX_SUB_I(2); } +static void fx_sub_i3() { FX_SUB_I(3); } +static void fx_sub_i4() { FX_SUB_I(4); } +static void fx_sub_i5() { FX_SUB_I(5); } +static void fx_sub_i6() { FX_SUB_I(6); } +static void fx_sub_i7() { FX_SUB_I(7); } +static void fx_sub_i8() { FX_SUB_I(8); } +static void fx_sub_i9() { FX_SUB_I(9); } +static void fx_sub_i10() { FX_SUB_I(10); } +static void fx_sub_i11() { FX_SUB_I(11); } +static void fx_sub_i12() { FX_SUB_I(12); } +static void fx_sub_i13() { FX_SUB_I(13); } +static void fx_sub_i14() { FX_SUB_I(14); } +static void fx_sub_i15() { FX_SUB_I(15); } + +/* 60-6f(ALT3) - cmp rn - compare, register, register */ +#define FX_CMP(reg) \ +int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \ +GSU.vCarry = s >= 0; \ +GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \ +GSU.vSign = s; \ +GSU.vZero = s; \ +R15++; \ +CLRFLAGS; +static void fx_cmp_r0() { FX_CMP(0); } +static void fx_cmp_r1() { FX_CMP(1); } +static void fx_cmp_r2() { FX_CMP(2); } +static void fx_cmp_r3() { FX_CMP(3); } +static void fx_cmp_r4() { FX_CMP(4); } +static void fx_cmp_r5() { FX_CMP(5); } +static void fx_cmp_r6() { FX_CMP(6); } +static void fx_cmp_r7() { FX_CMP(7); } +static void fx_cmp_r8() { FX_CMP(8); } +static void fx_cmp_r9() { FX_CMP(9); } +static void fx_cmp_r10() { FX_CMP(10); } +static void fx_cmp_r11() { FX_CMP(11); } +static void fx_cmp_r12() { FX_CMP(12); } +static void fx_cmp_r13() { FX_CMP(13); } +static void fx_cmp_r14() { FX_CMP(14); } +static void fx_cmp_r15() { FX_CMP(15); } + +/* 70 - merge - R7 as upper byte, R8 as lower byte (used for texture-mapping) */ +static void fx_merge() +{ + uint32 v = (R7&0xff00) | ((R8&0xff00)>>8); + R15++; DREG = v; + GSU.vOverflow = (v & 0xc0c0) << 16; + GSU.vZero = !(v & 0xf0f0); + GSU.vSign = ((v | (v<<8)) & 0x8000); + GSU.vCarry = (v & 0xe0e0) != 0; + TESTR14; + CLRFLAGS; +} + +/* 71-7f - and rn - reister & register */ +#define FX_AND(reg) \ +uint32 v = SREG & GSU.avReg[reg]; \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_and_r1() { FX_AND(1); } +static void fx_and_r2() { FX_AND(2); } +static void fx_and_r3() { FX_AND(3); } +static void fx_and_r4() { FX_AND(4); } +static void fx_and_r5() { FX_AND(5); } +static void fx_and_r6() { FX_AND(6); } +static void fx_and_r7() { FX_AND(7); } +static void fx_and_r8() { FX_AND(8); } +static void fx_and_r9() { FX_AND(9); } +static void fx_and_r10() { FX_AND(10); } +static void fx_and_r11() { FX_AND(11); } +static void fx_and_r12() { FX_AND(12); } +static void fx_and_r13() { FX_AND(13); } +static void fx_and_r14() { FX_AND(14); } +static void fx_and_r15() { FX_AND(15); } + +/* 71-7f(ALT1) - bic rn - reister & ~register */ +#define FX_BIC(reg) \ +uint32 v = SREG & ~GSU.avReg[reg]; \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_bic_r1() { FX_BIC(1); } +static void fx_bic_r2() { FX_BIC(2); } +static void fx_bic_r3() { FX_BIC(3); } +static void fx_bic_r4() { FX_BIC(4); } +static void fx_bic_r5() { FX_BIC(5); } +static void fx_bic_r6() { FX_BIC(6); } +static void fx_bic_r7() { FX_BIC(7); } +static void fx_bic_r8() { FX_BIC(8); } +static void fx_bic_r9() { FX_BIC(9); } +static void fx_bic_r10() { FX_BIC(10); } +static void fx_bic_r11() { FX_BIC(11); } +static void fx_bic_r12() { FX_BIC(12); } +static void fx_bic_r13() { FX_BIC(13); } +static void fx_bic_r14() { FX_BIC(14); } +static void fx_bic_r15() { FX_BIC(15); } + +/* 71-7f(ALT2) - and #n - reister & immediate */ +#define FX_AND_I(imm) \ +uint32 v = SREG & imm; \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_and_i1() { FX_AND_I(1); } +static void fx_and_i2() { FX_AND_I(2); } +static void fx_and_i3() { FX_AND_I(3); } +static void fx_and_i4() { FX_AND_I(4); } +static void fx_and_i5() { FX_AND_I(5); } +static void fx_and_i6() { FX_AND_I(6); } +static void fx_and_i7() { FX_AND_I(7); } +static void fx_and_i8() { FX_AND_I(8); } +static void fx_and_i9() { FX_AND_I(9); } +static void fx_and_i10() { FX_AND_I(10); } +static void fx_and_i11() { FX_AND_I(11); } +static void fx_and_i12() { FX_AND_I(12); } +static void fx_and_i13() { FX_AND_I(13); } +static void fx_and_i14() { FX_AND_I(14); } +static void fx_and_i15() { FX_AND_I(15); } + +/* 71-7f(ALT3) - bic #n - reister & ~immediate */ +#define FX_BIC_I(imm) \ +uint32 v = SREG & ~imm; \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_bic_i1() { FX_BIC_I(1); } +static void fx_bic_i2() { FX_BIC_I(2); } +static void fx_bic_i3() { FX_BIC_I(3); } +static void fx_bic_i4() { FX_BIC_I(4); } +static void fx_bic_i5() { FX_BIC_I(5); } +static void fx_bic_i6() { FX_BIC_I(6); } +static void fx_bic_i7() { FX_BIC_I(7); } +static void fx_bic_i8() { FX_BIC_I(8); } +static void fx_bic_i9() { FX_BIC_I(9); } +static void fx_bic_i10() { FX_BIC_I(10); } +static void fx_bic_i11() { FX_BIC_I(11); } +static void fx_bic_i12() { FX_BIC_I(12); } +static void fx_bic_i13() { FX_BIC_I(13); } +static void fx_bic_i14() { FX_BIC_I(14); } +static void fx_bic_i15() { FX_BIC_I(15); } + +/* 80-8f - mult rn - 8 bit to 16 bit signed multiply, register * register */ +#define FX_MULT(reg) \ +uint32 v = (uint32)(SEX8(SREG) * SEX8(GSU.avReg[reg])); \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_mult_r0() { FX_MULT(0); } +static void fx_mult_r1() { FX_MULT(1); } +static void fx_mult_r2() { FX_MULT(2); } +static void fx_mult_r3() { FX_MULT(3); } +static void fx_mult_r4() { FX_MULT(4); } +static void fx_mult_r5() { FX_MULT(5); } +static void fx_mult_r6() { FX_MULT(6); } +static void fx_mult_r7() { FX_MULT(7); } +static void fx_mult_r8() { FX_MULT(8); } +static void fx_mult_r9() { FX_MULT(9); } +static void fx_mult_r10() { FX_MULT(10); } +static void fx_mult_r11() { FX_MULT(11); } +static void fx_mult_r12() { FX_MULT(12); } +static void fx_mult_r13() { FX_MULT(13); } +static void fx_mult_r14() { FX_MULT(14); } +static void fx_mult_r15() { FX_MULT(15); } + +/* 80-8f(ALT1) - umult rn - 8 bit to 16 bit unsigned multiply, register * register */ +#define FX_UMULT(reg) \ +uint32 v = USEX8(SREG) * USEX8(GSU.avReg[reg]); \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_umult_r0() { FX_UMULT(0); } +static void fx_umult_r1() { FX_UMULT(1); } +static void fx_umult_r2() { FX_UMULT(2); } +static void fx_umult_r3() { FX_UMULT(3); } +static void fx_umult_r4() { FX_UMULT(4); } +static void fx_umult_r5() { FX_UMULT(5); } +static void fx_umult_r6() { FX_UMULT(6); } +static void fx_umult_r7() { FX_UMULT(7); } +static void fx_umult_r8() { FX_UMULT(8); } +static void fx_umult_r9() { FX_UMULT(9); } +static void fx_umult_r10() { FX_UMULT(10); } +static void fx_umult_r11() { FX_UMULT(11); } +static void fx_umult_r12() { FX_UMULT(12); } +static void fx_umult_r13() { FX_UMULT(13); } +static void fx_umult_r14() { FX_UMULT(14); } +static void fx_umult_r15() { FX_UMULT(15); } + +/* 80-8f(ALT2) - mult #n - 8 bit to 16 bit signed multiply, register * immediate */ +#define FX_MULT_I(imm) \ +uint32 v = (uint32) (SEX8(SREG) * ((int32)imm)); \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_mult_i0() { FX_MULT_I(0); } +static void fx_mult_i1() { FX_MULT_I(1); } +static void fx_mult_i2() { FX_MULT_I(2); } +static void fx_mult_i3() { FX_MULT_I(3); } +static void fx_mult_i4() { FX_MULT_I(4); } +static void fx_mult_i5() { FX_MULT_I(5); } +static void fx_mult_i6() { FX_MULT_I(6); } +static void fx_mult_i7() { FX_MULT_I(7); } +static void fx_mult_i8() { FX_MULT_I(8); } +static void fx_mult_i9() { FX_MULT_I(9); } +static void fx_mult_i10() { FX_MULT_I(10); } +static void fx_mult_i11() { FX_MULT_I(11); } +static void fx_mult_i12() { FX_MULT_I(12); } +static void fx_mult_i13() { FX_MULT_I(13); } +static void fx_mult_i14() { FX_MULT_I(14); } +static void fx_mult_i15() { FX_MULT_I(15); } + +/* 80-8f(ALT3) - umult #n - 8 bit to 16 bit unsigned multiply, register * immediate */ +#define FX_UMULT_I(imm) \ +uint32 v = USEX8(SREG) * ((uint32)imm); \ +R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_umult_i0() { FX_UMULT_I(0); } +static void fx_umult_i1() { FX_UMULT_I(1); } +static void fx_umult_i2() { FX_UMULT_I(2); } +static void fx_umult_i3() { FX_UMULT_I(3); } +static void fx_umult_i4() { FX_UMULT_I(4); } +static void fx_umult_i5() { FX_UMULT_I(5); } +static void fx_umult_i6() { FX_UMULT_I(6); } +static void fx_umult_i7() { FX_UMULT_I(7); } +static void fx_umult_i8() { FX_UMULT_I(8); } +static void fx_umult_i9() { FX_UMULT_I(9); } +static void fx_umult_i10() { FX_UMULT_I(10); } +static void fx_umult_i11() { FX_UMULT_I(11); } +static void fx_umult_i12() { FX_UMULT_I(12); } +static void fx_umult_i13() { FX_UMULT_I(13); } +static void fx_umult_i14() { FX_UMULT_I(14); } +static void fx_umult_i15() { FX_UMULT_I(15); } + +/* 90 - sbk - store word to last accessed RAM address */ +static void fx_sbk() +{ + RAM(GSU.vLastRamAdr) = (uint8)SREG; + RAM(GSU.vLastRamAdr^1) = (uint8)(SREG>>8); + CLRFLAGS; + R15++; +} + +/* 91-94 - link #n - R11 = R15 + immediate */ +#define FX_LINK_I(lkn) R11 = R15 + lkn; CLRFLAGS; R15++ +static void fx_link_i1() { FX_LINK_I(1); } +static void fx_link_i2() { FX_LINK_I(2); } +static void fx_link_i3() { FX_LINK_I(3); } +static void fx_link_i4() { FX_LINK_I(4); } + +/* 95 - sex - sign extend 8 bit to 16 bit */ +static void fx_sex() +{ + uint32 v = (uint32)SEX8(SREG); + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 96 - asr - aritmetric shift right by one */ +static void fx_asr() +{ + uint32 v; + GSU.vCarry = SREG & 1; + v = (uint32)(SEX16(SREG)>>1); + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 96(ALT1) - div2 - aritmetric shift right by one */ +static void fx_div2() +{ + uint32 v; + int32 s = SEX16(SREG); + GSU.vCarry = s & 1; + if(s == -1) + v = 0; + else + v = (uint32)(s>>1); + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 97 - ror - rotate right by one */ +static void fx_ror() +{ + uint32 v = (USEX16(SREG)>>1) | (GSU.vCarry<<15); + GSU.vCarry = SREG & 1; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + TESTR14; + CLRFLAGS; +} + +/* 98-9d - jmp rn - jump to address of register */ +#define FX_JMP(reg) \ +R15 = GSU.avReg[reg]; \ +CLRFLAGS; +static void fx_jmp_r8() { FX_JMP(8); } +static void fx_jmp_r9() { FX_JMP(9); } +static void fx_jmp_r10() { FX_JMP(10); } +static void fx_jmp_r11() { FX_JMP(11); } +static void fx_jmp_r12() { FX_JMP(12); } +static void fx_jmp_r13() { FX_JMP(13); } + +/* 98-9d(ALT1) - ljmp rn - set program bank to source register and jump to address of register */ +#define FX_LJMP(reg) \ +GSU.vPrgBankReg = GSU.avReg[reg] & 0x7f; \ +GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg]; \ +R15 = SREG; \ +GSU.bCacheActive = FALSE; fx_cache(); R15--; +static void fx_ljmp_r8() { FX_LJMP(8); } +static void fx_ljmp_r9() { FX_LJMP(9); } +static void fx_ljmp_r10() { FX_LJMP(10); } +static void fx_ljmp_r11() { FX_LJMP(11); } +static void fx_ljmp_r12() { FX_LJMP(12); } +static void fx_ljmp_r13() { FX_LJMP(13); } + +/* 9e - lob - set upper byte to zero (keep low byte) */ +static void fx_lob() +{ + uint32 v = USEX8(SREG); + R15++; DREG = v; + GSU.vSign = v<<8; + GSU.vZero = v<<8; + TESTR14; + CLRFLAGS; +} + +/* 9f - fmult - 16 bit to 32 bit signed multiplication, upper 16 bits only */ +static void fx_fmult() +{ + uint32 v; + uint32 c = (uint32) (SEX16(SREG) * SEX16(R6)); + v = c >> 16; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + GSU.vCarry = (c >> 15) & 1; + TESTR14; + CLRFLAGS; +} + +/* 9f(ALT1) - lmult - 16 bit to 32 bit signed multiplication */ +static void fx_lmult() +{ + uint32 v; + uint32 c = (uint32) (SEX16(SREG) * SEX16(R6)); + R4 = c; + v = c >> 16; + R15++; DREG = v; + GSU.vSign = v; + GSU.vZero = v; + /* XXX R6 or R4? */ + GSU.vCarry = (R4 >> 15) & 1; /* should it be bit 15 of R4 instead? */ + TESTR14; + CLRFLAGS; +} + +/* a0-af - ibt rn,#pp - immediate byte transfer */ +#define FX_IBT(reg) \ +uint8 v = PIPE; R15++; \ +FETCHPIPE; R15++; \ +GSU.avReg[reg] = SEX8(v); \ +CLRFLAGS; +static void fx_ibt_r0() { FX_IBT(0); } +static void fx_ibt_r1() { FX_IBT(1); } +static void fx_ibt_r2() { FX_IBT(2); } +static void fx_ibt_r3() { FX_IBT(3); } +static void fx_ibt_r4() { FX_IBT(4); } +static void fx_ibt_r5() { FX_IBT(5); } +static void fx_ibt_r6() { FX_IBT(6); } +static void fx_ibt_r7() { FX_IBT(7); } +static void fx_ibt_r8() { FX_IBT(8); } +static void fx_ibt_r9() { FX_IBT(9); } +static void fx_ibt_r10() { FX_IBT(10); } +static void fx_ibt_r11() { FX_IBT(11); } +static void fx_ibt_r12() { FX_IBT(12); } +static void fx_ibt_r13() { FX_IBT(13); } +static void fx_ibt_r14() { FX_IBT(14); READR14; } +static void fx_ibt_r15() { FX_IBT(15); } + +/* a0-af(ALT1) - lms rn,(yy) - load word from RAM (short address) */ +#define FX_LMS(reg) \ +GSU.vLastRamAdr = ((uint32)PIPE) << 1; \ +R15++; FETCHPIPE; R15++; \ +GSU.avReg[reg] = (uint32)RAM(GSU.vLastRamAdr); \ +GSU.avReg[reg] |= ((uint32)RAM(GSU.vLastRamAdr+1))<<8; \ +CLRFLAGS; +static void fx_lms_r0() { FX_LMS(0); } +static void fx_lms_r1() { FX_LMS(1); } +static void fx_lms_r2() { FX_LMS(2); } +static void fx_lms_r3() { FX_LMS(3); } +static void fx_lms_r4() { FX_LMS(4); } +static void fx_lms_r5() { FX_LMS(5); } +static void fx_lms_r6() { FX_LMS(6); } +static void fx_lms_r7() { FX_LMS(7); } +static void fx_lms_r8() { FX_LMS(8); } +static void fx_lms_r9() { FX_LMS(9); } +static void fx_lms_r10() { FX_LMS(10); } +static void fx_lms_r11() { FX_LMS(11); } +static void fx_lms_r12() { FX_LMS(12); } +static void fx_lms_r13() { FX_LMS(13); } +static void fx_lms_r14() { FX_LMS(14); READR14; } +static void fx_lms_r15() { FX_LMS(15); } + +/* a0-af(ALT2) - sms (yy),rn - store word in RAM (short address) */ +/* If rn == r15, is the value of r15 before or after the extra byte is read? */ +#define FX_SMS(reg) \ +uint32 v = GSU.avReg[reg]; \ +GSU.vLastRamAdr = ((uint32)PIPE) << 1; \ +R15++; FETCHPIPE; \ +RAM(GSU.vLastRamAdr) = (uint8)v; \ +RAM(GSU.vLastRamAdr+1) = (uint8)(v>>8); \ +CLRFLAGS; R15++; +static void fx_sms_r0() { FX_SMS(0); } +static void fx_sms_r1() { FX_SMS(1); } +static void fx_sms_r2() { FX_SMS(2); } +static void fx_sms_r3() { FX_SMS(3); } +static void fx_sms_r4() { FX_SMS(4); } +static void fx_sms_r5() { FX_SMS(5); } +static void fx_sms_r6() { FX_SMS(6); } +static void fx_sms_r7() { FX_SMS(7); } +static void fx_sms_r8() { FX_SMS(8); } +static void fx_sms_r9() { FX_SMS(9); } +static void fx_sms_r10() { FX_SMS(10); } +static void fx_sms_r11() { FX_SMS(11); } +static void fx_sms_r12() { FX_SMS(12); } +static void fx_sms_r13() { FX_SMS(13); } +static void fx_sms_r14() { FX_SMS(14); } +static void fx_sms_r15() { FX_SMS(15); } + +/* b0-bf - from rn - set source register */ +/* b0-bf(B) - moves rn - move register to register, and set flags, (if B flag is set) */ +#define FX_FROM(reg) \ +if(TF(B)) { uint32 v = GSU.avReg[reg]; R15++; DREG = v; \ +GSU.vOverflow = (v&0x80) << 16; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } \ +else { GSU.pvSreg = &GSU.avReg[reg]; R15++; } +static void fx_from_r0() { FX_FROM(0); } +static void fx_from_r1() { FX_FROM(1); } +static void fx_from_r2() { FX_FROM(2); } +static void fx_from_r3() { FX_FROM(3); } +static void fx_from_r4() { FX_FROM(4); } +static void fx_from_r5() { FX_FROM(5); } +static void fx_from_r6() { FX_FROM(6); } +static void fx_from_r7() { FX_FROM(7); } +static void fx_from_r8() { FX_FROM(8); } +static void fx_from_r9() { FX_FROM(9); } +static void fx_from_r10() { FX_FROM(10); } +static void fx_from_r11() { FX_FROM(11); } +static void fx_from_r12() { FX_FROM(12); } +static void fx_from_r13() { FX_FROM(13); } +static void fx_from_r14() { FX_FROM(14); } +static void fx_from_r15() { FX_FROM(15); } + +/* c0 - hib - move high-byte to low-byte */ +static void fx_hib() +{ + uint32 v = USEX8(SREG>>8); + R15++; DREG = v; + GSU.vSign = v<<8; + GSU.vZero = v<<8; + TESTR14; + CLRFLAGS; +} + +/* c1-cf - or rn */ +#define FX_OR(reg) \ +uint32 v = SREG | GSU.avReg[reg]; R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_or_r1() { FX_OR(1); } +static void fx_or_r2() { FX_OR(2); } +static void fx_or_r3() { FX_OR(3); } +static void fx_or_r4() { FX_OR(4); } +static void fx_or_r5() { FX_OR(5); } +static void fx_or_r6() { FX_OR(6); } +static void fx_or_r7() { FX_OR(7); } +static void fx_or_r8() { FX_OR(8); } +static void fx_or_r9() { FX_OR(9); } +static void fx_or_r10() { FX_OR(10); } +static void fx_or_r11() { FX_OR(11); } +static void fx_or_r12() { FX_OR(12); } +static void fx_or_r13() { FX_OR(13); } +static void fx_or_r14() { FX_OR(14); } +static void fx_or_r15() { FX_OR(15); } + +/* c1-cf(ALT1) - xor rn */ +#define FX_XOR(reg) \ +uint32 v = SREG ^ GSU.avReg[reg]; R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_xor_r1() { FX_XOR(1); } +static void fx_xor_r2() { FX_XOR(2); } +static void fx_xor_r3() { FX_XOR(3); } +static void fx_xor_r4() { FX_XOR(4); } +static void fx_xor_r5() { FX_XOR(5); } +static void fx_xor_r6() { FX_XOR(6); } +static void fx_xor_r7() { FX_XOR(7); } +static void fx_xor_r8() { FX_XOR(8); } +static void fx_xor_r9() { FX_XOR(9); } +static void fx_xor_r10() { FX_XOR(10); } +static void fx_xor_r11() { FX_XOR(11); } +static void fx_xor_r12() { FX_XOR(12); } +static void fx_xor_r13() { FX_XOR(13); } +static void fx_xor_r14() { FX_XOR(14); } +static void fx_xor_r15() { FX_XOR(15); } + +/* c1-cf(ALT2) - or #n */ +#define FX_OR_I(imm) \ +uint32 v = SREG | imm; R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_or_i1() { FX_OR_I(1); } +static void fx_or_i2() { FX_OR_I(2); } +static void fx_or_i3() { FX_OR_I(3); } +static void fx_or_i4() { FX_OR_I(4); } +static void fx_or_i5() { FX_OR_I(5); } +static void fx_or_i6() { FX_OR_I(6); } +static void fx_or_i7() { FX_OR_I(7); } +static void fx_or_i8() { FX_OR_I(8); } +static void fx_or_i9() { FX_OR_I(9); } +static void fx_or_i10() { FX_OR_I(10); } +static void fx_or_i11() { FX_OR_I(11); } +static void fx_or_i12() { FX_OR_I(12); } +static void fx_or_i13() { FX_OR_I(13); } +static void fx_or_i14() { FX_OR_I(14); } +static void fx_or_i15() { FX_OR_I(15); } + +/* c1-cf(ALT3) - xor #n */ +#define FX_XOR_I(imm) \ +uint32 v = SREG ^ imm; R15++; DREG = v; \ +GSU.vSign = v; \ +GSU.vZero = v; \ +TESTR14; \ +CLRFLAGS; +static void fx_xor_i1() { FX_XOR_I(1); } +static void fx_xor_i2() { FX_XOR_I(2); } +static void fx_xor_i3() { FX_XOR_I(3); } +static void fx_xor_i4() { FX_XOR_I(4); } +static void fx_xor_i5() { FX_XOR_I(5); } +static void fx_xor_i6() { FX_XOR_I(6); } +static void fx_xor_i7() { FX_XOR_I(7); } +static void fx_xor_i8() { FX_XOR_I(8); } +static void fx_xor_i9() { FX_XOR_I(9); } +static void fx_xor_i10() { FX_XOR_I(10); } +static void fx_xor_i11() { FX_XOR_I(11); } +static void fx_xor_i12() { FX_XOR_I(12); } +static void fx_xor_i13() { FX_XOR_I(13); } +static void fx_xor_i14() { FX_XOR_I(14); } +static void fx_xor_i15() { FX_XOR_I(15); } + +/* d0-de - inc rn - increase by one */ +#define FX_INC(reg) \ +GSU.avReg[reg] += 1; \ +GSU.vSign = GSU.avReg[reg]; \ +GSU.vZero = GSU.avReg[reg]; \ +CLRFLAGS; R15++; +static void fx_inc_r0() { FX_INC(0); } +static void fx_inc_r1() { FX_INC(1); } +static void fx_inc_r2() { FX_INC(2); } +static void fx_inc_r3() { FX_INC(3); } +static void fx_inc_r4() { FX_INC(4); } +static void fx_inc_r5() { FX_INC(5); } +static void fx_inc_r6() { FX_INC(6); } +static void fx_inc_r7() { FX_INC(7); } +static void fx_inc_r8() { FX_INC(8); } +static void fx_inc_r9() { FX_INC(9); } +static void fx_inc_r10() { FX_INC(10); } +static void fx_inc_r11() { FX_INC(11); } +static void fx_inc_r12() { FX_INC(12); } +static void fx_inc_r13() { FX_INC(13); } +static void fx_inc_r14() { FX_INC(14); READR14; } + +/* df - getc - transfer ROM buffer to color register */ +static void fx_getc() +{ +#ifndef FX_DO_ROMBUFFER + uint8 c; + c = ROM(R14); +#else + uint8 c = GSU.vRomBuffer; +#endif + if(GSU.vPlotOptionReg & 0x04) + c = (c&0xf0) | (c>>4); + if(GSU.vPlotOptionReg & 0x08) + { + GSU.vColorReg &= 0xf0; + GSU.vColorReg |= c & 0x0f; + } + else + GSU.vColorReg = USEX8(c); + CLRFLAGS; + R15++; +} + +/* df(ALT2) - ramb - set current RAM bank */ +static void fx_ramb() +{ + GSU.vRamBankReg = SREG & (FX_RAM_BANKS-1); + GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3]; + CLRFLAGS; + R15++; +} + +/* df(ALT3) - romb - set current ROM bank */ +static void fx_romb() +{ + GSU.vRomBankReg = USEX8(SREG) & 0x7f; + GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg]; + CLRFLAGS; + R15++; +} + +/* e0-ee - dec rn - decrement by one */ +#define FX_DEC(reg) \ +GSU.avReg[reg] -= 1; \ +GSU.vSign = GSU.avReg[reg]; \ +GSU.vZero = GSU.avReg[reg]; \ +CLRFLAGS; R15++; +static void fx_dec_r0() { FX_DEC(0); } +static void fx_dec_r1() { FX_DEC(1); } +static void fx_dec_r2() { FX_DEC(2); } +static void fx_dec_r3() { FX_DEC(3); } +static void fx_dec_r4() { FX_DEC(4); } +static void fx_dec_r5() { FX_DEC(5); } +static void fx_dec_r6() { FX_DEC(6); } +static void fx_dec_r7() { FX_DEC(7); } +static void fx_dec_r8() { FX_DEC(8); } +static void fx_dec_r9() { FX_DEC(9); } +static void fx_dec_r10() { FX_DEC(10); } +static void fx_dec_r11() { FX_DEC(11); } +static void fx_dec_r12() { FX_DEC(12); } +static void fx_dec_r13() { FX_DEC(13); } +static void fx_dec_r14() { FX_DEC(14); READR14; } + +/* ef - getb - get byte from ROM at address R14 */ +static void fx_getb() +{ + uint32 v; +#ifndef FX_DO_ROMBUFFER + v = (uint32)ROM(R14); +#else + v = (uint32)GSU.vRomBuffer; +#endif + R15++; DREG = v; + TESTR14; + CLRFLAGS; +} + +/* ef(ALT1) - getbh - get high-byte from ROM at address R14 */ +static void fx_getbh() +{ + uint32 v; +#ifndef FX_DO_ROMBUFFER + uint32 c; + c = (uint32)ROM(R14); +#else + uint32 c = USEX8(GSU.vRomBuffer); +#endif + v = USEX8(SREG) | (c<<8); + R15++; DREG = v; + TESTR14; + CLRFLAGS; +} + +/* ef(ALT2) - getbl - get low-byte from ROM at address R14 */ +static void fx_getbl() +{ + uint32 v; +#ifndef FX_DO_ROMBUFFER + uint32 c; + c = (uint32)ROM(R14); +#else + uint32 c = USEX8(GSU.vRomBuffer); +#endif + v = (SREG & 0xff00) | c; + R15++; DREG = v; + TESTR14; + CLRFLAGS; +} + +/* ef(ALT3) - getbs - get sign extended byte from ROM at address R14 */ +static void fx_getbs() +{ + uint32 v; +#ifndef FX_DO_ROMBUFFER + int8 c; + c = ROM(R14); + v = SEX8(c); +#else + v = SEX8(GSU.vRomBuffer); +#endif + R15++; DREG = v; + TESTR14; + CLRFLAGS; +} + +/* f0-ff - iwt rn,#xx - immediate word transfer to register */ +#define FX_IWT(reg) \ +uint32 v = PIPE; R15++; FETCHPIPE; R15++; \ +v |= USEX8(PIPE) << 8; FETCHPIPE; R15++; \ +GSU.avReg[reg] = v; \ +CLRFLAGS; +static void fx_iwt_r0() { FX_IWT(0); } +static void fx_iwt_r1() { FX_IWT(1); } +static void fx_iwt_r2() { FX_IWT(2); } +static void fx_iwt_r3() { FX_IWT(3); } +static void fx_iwt_r4() { FX_IWT(4); } +static void fx_iwt_r5() { FX_IWT(5); } +static void fx_iwt_r6() { FX_IWT(6); } +static void fx_iwt_r7() { FX_IWT(7); } +static void fx_iwt_r8() { FX_IWT(8); } +static void fx_iwt_r9() { FX_IWT(9); } +static void fx_iwt_r10() { FX_IWT(10); } +static void fx_iwt_r11() { FX_IWT(11); } +static void fx_iwt_r12() { FX_IWT(12); } +static void fx_iwt_r13() { FX_IWT(13); } +static void fx_iwt_r14() { FX_IWT(14); READR14; } +static void fx_iwt_r15() { FX_IWT(15); } + +/* f0-ff(ALT1) - lm rn,(xx) - load word from RAM */ +#define FX_LM(reg) \ +GSU.vLastRamAdr = PIPE; R15++; FETCHPIPE; R15++; \ +GSU.vLastRamAdr |= USEX8(PIPE) << 8; FETCHPIPE; R15++; \ +GSU.avReg[reg] = RAM(GSU.vLastRamAdr); \ +GSU.avReg[reg] |= USEX8(RAM(GSU.vLastRamAdr^1)) << 8; \ +CLRFLAGS; +static void fx_lm_r0() { FX_LM(0); } +static void fx_lm_r1() { FX_LM(1); } +static void fx_lm_r2() { FX_LM(2); } +static void fx_lm_r3() { FX_LM(3); } +static void fx_lm_r4() { FX_LM(4); } +static void fx_lm_r5() { FX_LM(5); } +static void fx_lm_r6() { FX_LM(6); } +static void fx_lm_r7() { FX_LM(7); } +static void fx_lm_r8() { FX_LM(8); } +static void fx_lm_r9() { FX_LM(9); } +static void fx_lm_r10() { FX_LM(10); } +static void fx_lm_r11() { FX_LM(11); } +static void fx_lm_r12() { FX_LM(12); } +static void fx_lm_r13() { FX_LM(13); } +static void fx_lm_r14() { FX_LM(14); READR14; } +static void fx_lm_r15() { FX_LM(15); } + +/* f0-ff(ALT2) - sm (xx),rn - store word in RAM */ +/* If rn == r15, is the value of r15 before or after the extra bytes are read? */ +#define FX_SM(reg) \ +uint32 v = GSU.avReg[reg]; \ +GSU.vLastRamAdr = PIPE; R15++; FETCHPIPE; R15++; \ +GSU.vLastRamAdr |= USEX8(PIPE) << 8; FETCHPIPE; \ +RAM(GSU.vLastRamAdr) = (uint8)v; \ +RAM(GSU.vLastRamAdr^1) = (uint8)(v>>8); \ +CLRFLAGS; R15++; +static void fx_sm_r0() { FX_SM(0); } +static void fx_sm_r1() { FX_SM(1); } +static void fx_sm_r2() { FX_SM(2); } +static void fx_sm_r3() { FX_SM(3); } +static void fx_sm_r4() { FX_SM(4); } +static void fx_sm_r5() { FX_SM(5); } +static void fx_sm_r6() { FX_SM(6); } +static void fx_sm_r7() { FX_SM(7); } +static void fx_sm_r8() { FX_SM(8); } +static void fx_sm_r9() { FX_SM(9); } +static void fx_sm_r10() { FX_SM(10); } +static void fx_sm_r11() { FX_SM(11); } +static void fx_sm_r12() { FX_SM(12); } +static void fx_sm_r13() { FX_SM(13); } +static void fx_sm_r14() { FX_SM(14); } +static void fx_sm_r15() { FX_SM(15); } + +/*** GSU executions functions ***/ + +static uint32 fx_run(uint32 nInstructions) +{ + GSU.vCounter = nInstructions; + READR14; + while( TF(G) && (GSU.vCounter-- > 0) ) + FX_STEP; + /* +#ifndef FX_ADDRESS_CHECK + GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16); +#endif +*/ + return (nInstructions - GSU.vInstCount); +} + +static uint32 fx_run_to_breakpoint(uint32 nInstructions) +{ + uint32 vCounter = 0; + while(TF(G) && vCounter < nInstructions) + { + vCounter++; + FX_STEP; + if(USEX16(R15) == GSU.vBreakPoint) + { + GSU.vErrorCode = FX_BREAKPOINT; + break; + } + } + /* +#ifndef FX_ADDRESS_CHECK + GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16); +#endif +*/ + return vCounter; +} + +static uint32 fx_step_over(uint32 nInstructions) +{ + uint32 vCounter = 0; + while(TF(G) && vCounter < nInstructions) + { + vCounter++; + FX_STEP; + if(USEX16(R15) == GSU.vBreakPoint) + { + GSU.vErrorCode = FX_BREAKPOINT; + break; + } + if(USEX16(R15) == GSU.vStepPoint) + break; + } + /* +#ifndef FX_ADDRESS_CHECK + GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16); +#endif +*/ + return vCounter; +} + +#ifdef FX_FUNCTION_TABLE +uint32 (*FX_FUNCTION_TABLE[])(uint32) = +#else +uint32 (*fx_apfFunctionTable[])(uint32) = +#endif +{ + &fx_run, + &fx_run_to_breakpoint, + &fx_step_over, +}; + +/*** Special table for the different plot configurations ***/ + +#ifdef FX_PLOT_TABLE +void (*FX_PLOT_TABLE[])() = +#else +void (*fx_apfPlotTable[])() = +#endif +{ + &fx_plot_2bit, &fx_plot_4bit, &fx_plot_4bit, &fx_plot_8bit, &fx_plot_obj, + &fx_rpix_2bit, &fx_rpix_4bit, &fx_rpix_4bit, &fx_rpix_8bit, &fx_rpix_obj, +}; + +/*** Opcode table ***/ + +#ifdef FX_OPCODE_TABLE +void (*FX_OPCODE_TABLE[])() = +#else +void (*fx_apfOpcodeTable[])() = +#endif +{ + /* + * ALT0 Table + */ + /* 00 - 0f */ + &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, + &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, + /* 10 - 1f */ + &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, + &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, + /* 20 - 2f */ + &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, + &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, + /* 30 - 3f */ + &fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7, + &fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, + /* 40 - 4f */ + &fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7, + &fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit,&fx_swap, &fx_color, &fx_not, + /* 50 - 5f */ + &fx_add_r0, &fx_add_r1, &fx_add_r2, &fx_add_r3, &fx_add_r4, &fx_add_r5, &fx_add_r6, &fx_add_r7, + &fx_add_r8, &fx_add_r9, &fx_add_r10, &fx_add_r11, &fx_add_r12, &fx_add_r13, &fx_add_r14, &fx_add_r15, + /* 60 - 6f */ + &fx_sub_r0, &fx_sub_r1, &fx_sub_r2, &fx_sub_r3, &fx_sub_r4, &fx_sub_r5, &fx_sub_r6, &fx_sub_r7, + &fx_sub_r8, &fx_sub_r9, &fx_sub_r10, &fx_sub_r11, &fx_sub_r12, &fx_sub_r13, &fx_sub_r14, &fx_sub_r15, + /* 70 - 7f */ + &fx_merge, &fx_and_r1, &fx_and_r2, &fx_and_r3, &fx_and_r4, &fx_and_r5, &fx_and_r6, &fx_and_r7, + &fx_and_r8, &fx_and_r9, &fx_and_r10, &fx_and_r11, &fx_and_r12, &fx_and_r13, &fx_and_r14, &fx_and_r15, + /* 80 - 8f */ + &fx_mult_r0, &fx_mult_r1, &fx_mult_r2, &fx_mult_r3, &fx_mult_r4, &fx_mult_r5, &fx_mult_r6, &fx_mult_r7, + &fx_mult_r8, &fx_mult_r9, &fx_mult_r10, &fx_mult_r11, &fx_mult_r12, &fx_mult_r13, &fx_mult_r14, &fx_mult_r15, + /* 90 - 9f */ + &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror, + &fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult, + /* a0 - af */ + &fx_ibt_r0, &fx_ibt_r1, &fx_ibt_r2, &fx_ibt_r3, &fx_ibt_r4, &fx_ibt_r5, &fx_ibt_r6, &fx_ibt_r7, + &fx_ibt_r8, &fx_ibt_r9, &fx_ibt_r10, &fx_ibt_r11, &fx_ibt_r12, &fx_ibt_r13, &fx_ibt_r14, &fx_ibt_r15, + /* b0 - bf */ + &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, + &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, + /* c0 - cf */ + &fx_hib, &fx_or_r1, &fx_or_r2, &fx_or_r3, &fx_or_r4, &fx_or_r5, &fx_or_r6, &fx_or_r7, + &fx_or_r8, &fx_or_r9, &fx_or_r10, &fx_or_r11, &fx_or_r12, &fx_or_r13, &fx_or_r14, &fx_or_r15, + /* d0 - df */ + &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, + &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc, + /* e0 - ef */ + &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, + &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getb, + /* f0 - ff */ + &fx_iwt_r0, &fx_iwt_r1, &fx_iwt_r2, &fx_iwt_r3, &fx_iwt_r4, &fx_iwt_r5, &fx_iwt_r6, &fx_iwt_r7, + &fx_iwt_r8, &fx_iwt_r9, &fx_iwt_r10, &fx_iwt_r11, &fx_iwt_r12, &fx_iwt_r13, &fx_iwt_r14, &fx_iwt_r15, + + /* + * ALT1 Table + */ + + /* 00 - 0f */ + &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, + &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, + /* 10 - 1f */ + &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, + &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, + /* 20 - 2f */ + &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, + &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, + /* 30 - 3f */ + &fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7, + &fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, + /* 40 - 4f */ + &fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7, + &fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit,&fx_swap, &fx_cmode, &fx_not, + /* 50 - 5f */ + &fx_adc_r0, &fx_adc_r1, &fx_adc_r2, &fx_adc_r3, &fx_adc_r4, &fx_adc_r5, &fx_adc_r6, &fx_adc_r7, + &fx_adc_r8, &fx_adc_r9, &fx_adc_r10, &fx_adc_r11, &fx_adc_r12, &fx_adc_r13, &fx_adc_r14, &fx_adc_r15, + /* 60 - 6f */ + &fx_sbc_r0, &fx_sbc_r1, &fx_sbc_r2, &fx_sbc_r3, &fx_sbc_r4, &fx_sbc_r5, &fx_sbc_r6, &fx_sbc_r7, + &fx_sbc_r8, &fx_sbc_r9, &fx_sbc_r10, &fx_sbc_r11, &fx_sbc_r12, &fx_sbc_r13, &fx_sbc_r14, &fx_sbc_r15, + /* 70 - 7f */ + &fx_merge, &fx_bic_r1, &fx_bic_r2, &fx_bic_r3, &fx_bic_r4, &fx_bic_r5, &fx_bic_r6, &fx_bic_r7, + &fx_bic_r8, &fx_bic_r9, &fx_bic_r10, &fx_bic_r11, &fx_bic_r12, &fx_bic_r13, &fx_bic_r14, &fx_bic_r15, + /* 80 - 8f */ + &fx_umult_r0,&fx_umult_r1,&fx_umult_r2, &fx_umult_r3, &fx_umult_r4, &fx_umult_r5, &fx_umult_r6, &fx_umult_r7, + &fx_umult_r8,&fx_umult_r9,&fx_umult_r10,&fx_umult_r11,&fx_umult_r12,&fx_umult_r13,&fx_umult_r14,&fx_umult_r15, + /* 90 - 9f */ + &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_div2, &fx_ror, + &fx_ljmp_r8, &fx_ljmp_r9, &fx_ljmp_r10, &fx_ljmp_r11, &fx_ljmp_r12, &fx_ljmp_r13, &fx_lob, &fx_lmult, + /* a0 - af */ + &fx_lms_r0, &fx_lms_r1, &fx_lms_r2, &fx_lms_r3, &fx_lms_r4, &fx_lms_r5, &fx_lms_r6, &fx_lms_r7, + &fx_lms_r8, &fx_lms_r9, &fx_lms_r10, &fx_lms_r11, &fx_lms_r12, &fx_lms_r13, &fx_lms_r14, &fx_lms_r15, + /* b0 - bf */ + &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, + &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, + /* c0 - cf */ + &fx_hib, &fx_xor_r1, &fx_xor_r2, &fx_xor_r3, &fx_xor_r4, &fx_xor_r5, &fx_xor_r6, &fx_xor_r7, + &fx_xor_r8, &fx_xor_r9, &fx_xor_r10, &fx_xor_r11, &fx_xor_r12, &fx_xor_r13, &fx_xor_r14, &fx_xor_r15, + /* d0 - df */ + &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, + &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc, + /* e0 - ef */ + &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, + &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbh, + /* f0 - ff */ + &fx_lm_r0, &fx_lm_r1, &fx_lm_r2, &fx_lm_r3, &fx_lm_r4, &fx_lm_r5, &fx_lm_r6, &fx_lm_r7, + &fx_lm_r8, &fx_lm_r9, &fx_lm_r10, &fx_lm_r11, &fx_lm_r12, &fx_lm_r13, &fx_lm_r14, &fx_lm_r15, + + /* + * ALT2 Table + */ + + /* 00 - 0f */ + &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, + &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, + /* 10 - 1f */ + &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, + &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, + /* 20 - 2f */ + &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, + &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, + /* 30 - 3f */ + &fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7, + &fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, + /* 40 - 4f */ + &fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7, + &fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit,&fx_swap, &fx_color, &fx_not, + /* 50 - 5f */ + &fx_add_i0, &fx_add_i1, &fx_add_i2, &fx_add_i3, &fx_add_i4, &fx_add_i5, &fx_add_i6, &fx_add_i7, + &fx_add_i8, &fx_add_i9, &fx_add_i10, &fx_add_i11, &fx_add_i12, &fx_add_i13, &fx_add_i14, &fx_add_i15, + /* 60 - 6f */ + &fx_sub_i0, &fx_sub_i1, &fx_sub_i2, &fx_sub_i3, &fx_sub_i4, &fx_sub_i5, &fx_sub_i6, &fx_sub_i7, + &fx_sub_i8, &fx_sub_i9, &fx_sub_i10, &fx_sub_i11, &fx_sub_i12, &fx_sub_i13, &fx_sub_i14, &fx_sub_i15, + /* 70 - 7f */ + &fx_merge, &fx_and_i1, &fx_and_i2, &fx_and_i3, &fx_and_i4, &fx_and_i5, &fx_and_i6, &fx_and_i7, + &fx_and_i8, &fx_and_i9, &fx_and_i10, &fx_and_i11, &fx_and_i12, &fx_and_i13, &fx_and_i14, &fx_and_i15, + /* 80 - 8f */ + &fx_mult_i0, &fx_mult_i1, &fx_mult_i2, &fx_mult_i3, &fx_mult_i4, &fx_mult_i5, &fx_mult_i6, &fx_mult_i7, + &fx_mult_i8, &fx_mult_i9, &fx_mult_i10, &fx_mult_i11, &fx_mult_i12, &fx_mult_i13, &fx_mult_i14, &fx_mult_i15, + /* 90 - 9f */ + &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror, + &fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult, + /* a0 - af */ + &fx_sms_r0, &fx_sms_r1, &fx_sms_r2, &fx_sms_r3, &fx_sms_r4, &fx_sms_r5, &fx_sms_r6, &fx_sms_r7, + &fx_sms_r8, &fx_sms_r9, &fx_sms_r10, &fx_sms_r11, &fx_sms_r12, &fx_sms_r13, &fx_sms_r14, &fx_sms_r15, + /* b0 - bf */ + &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, + &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, + /* c0 - cf */ + &fx_hib, &fx_or_i1, &fx_or_i2, &fx_or_i3, &fx_or_i4, &fx_or_i5, &fx_or_i6, &fx_or_i7, + &fx_or_i8, &fx_or_i9, &fx_or_i10, &fx_or_i11, &fx_or_i12, &fx_or_i13, &fx_or_i14, &fx_or_i15, + /* d0 - df */ + &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, + &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_ramb, + /* e0 - ef */ + &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, + &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbl, + /* f0 - ff */ + &fx_sm_r0, &fx_sm_r1, &fx_sm_r2, &fx_sm_r3, &fx_sm_r4, &fx_sm_r5, &fx_sm_r6, &fx_sm_r7, + &fx_sm_r8, &fx_sm_r9, &fx_sm_r10, &fx_sm_r11, &fx_sm_r12, &fx_sm_r13, &fx_sm_r14, &fx_sm_r15, + + /* + * ALT3 Table + */ + + /* 00 - 0f */ + &fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt, + &fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs, + /* 10 - 1f */ + &fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7, + &fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15, + /* 20 - 2f */ + &fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7, + &fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15, + /* 30 - 3f */ + &fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7, + &fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3, + /* 40 - 4f */ + &fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7, + &fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit,&fx_swap, &fx_cmode, &fx_not, + /* 50 - 5f */ + &fx_adc_i0, &fx_adc_i1, &fx_adc_i2, &fx_adc_i3, &fx_adc_i4, &fx_adc_i5, &fx_adc_i6, &fx_adc_i7, + &fx_adc_i8, &fx_adc_i9, &fx_adc_i10, &fx_adc_i11, &fx_adc_i12, &fx_adc_i13, &fx_adc_i14, &fx_adc_i15, + /* 60 - 6f */ + &fx_cmp_r0, &fx_cmp_r1, &fx_cmp_r2, &fx_cmp_r3, &fx_cmp_r4, &fx_cmp_r5, &fx_cmp_r6, &fx_cmp_r7, + &fx_cmp_r8, &fx_cmp_r9, &fx_cmp_r10, &fx_cmp_r11, &fx_cmp_r12, &fx_cmp_r13, &fx_cmp_r14, &fx_cmp_r15, + /* 70 - 7f */ + &fx_merge, &fx_bic_i1, &fx_bic_i2, &fx_bic_i3, &fx_bic_i4, &fx_bic_i5, &fx_bic_i6, &fx_bic_i7, + &fx_bic_i8, &fx_bic_i9, &fx_bic_i10, &fx_bic_i11, &fx_bic_i12, &fx_bic_i13, &fx_bic_i14, &fx_bic_i15, + /* 80 - 8f */ + &fx_umult_i0,&fx_umult_i1,&fx_umult_i2, &fx_umult_i3, &fx_umult_i4, &fx_umult_i5, &fx_umult_i6, &fx_umult_i7, + &fx_umult_i8,&fx_umult_i9,&fx_umult_i10,&fx_umult_i11,&fx_umult_i12,&fx_umult_i13,&fx_umult_i14,&fx_umult_i15, + /* 90 - 9f */ + &fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_div2, &fx_ror, + &fx_ljmp_r8, &fx_ljmp_r9, &fx_ljmp_r10, &fx_ljmp_r11, &fx_ljmp_r12, &fx_ljmp_r13, &fx_lob, &fx_lmult, + /* a0 - af */ + &fx_lms_r0, &fx_lms_r1, &fx_lms_r2, &fx_lms_r3, &fx_lms_r4, &fx_lms_r5, &fx_lms_r6, &fx_lms_r7, + &fx_lms_r8, &fx_lms_r9, &fx_lms_r10, &fx_lms_r11, &fx_lms_r12, &fx_lms_r13, &fx_lms_r14, &fx_lms_r15, + /* b0 - bf */ + &fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7, + &fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15, + /* c0 - cf */ + &fx_hib, &fx_xor_i1, &fx_xor_i2, &fx_xor_i3, &fx_xor_i4, &fx_xor_i5, &fx_xor_i6, &fx_xor_i7, + &fx_xor_i8, &fx_xor_i9, &fx_xor_i10, &fx_xor_i11, &fx_xor_i12, &fx_xor_i13, &fx_xor_i14, &fx_xor_i15, + /* d0 - df */ + &fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7, + &fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_romb, + /* e0 - ef */ + &fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7, + &fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbs, + /* f0 - ff */ + &fx_lm_r0, &fx_lm_r1, &fx_lm_r2, &fx_lm_r3, &fx_lm_r4, &fx_lm_r5, &fx_lm_r6, &fx_lm_r7, + &fx_lm_r8, &fx_lm_r9, &fx_lm_r10, &fx_lm_r11, &fx_lm_r12, &fx_lm_r13, &fx_lm_r14, &fx_lm_r15, +}; + diff --git a/source/snes9x/fxinst.h b/source/snes9x/fxinst.h new file mode 100644 index 0000000..a95c552 --- /dev/null +++ b/source/snes9x/fxinst.h @@ -0,0 +1,531 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _FXINST_H_ +#define _FXINST_H_ 1 + +/* + * FxChip(GSU) register space specification + * (Register address space 3000->32ff) + * + * The 16 generic 16 bit registers: + * (Some have a special function in special circumstances) + * 3000 - R0 default source/destination register + * 3002 - R1 pixel plot X position register + * 3004 - R2 pixel plot Y position register + * 3006 - R3 + * 3008 - R4 lower 16 bit result of lmult + * 300a - R5 + * 300c - R6 multiplier for fmult and lmult + * 300e - R7 fixed point texel X position for merge + * 3010 - R8 fixed point texel Y position for merge + * 3012 - R9 + * 3014 - R10 + * 3016 - R11 return address set by link + * 3018 - R12 loop counter + * 301a - R13 loop point address + * 301c - R14 rom address for getb, getbh, getbl, getbs + * 301e - R15 program counter + * + * 3020-302f - unused + * + * Other internal registers + * 3030 - SFR status flag register (16bit) + * 3032 - unused + * 3033 - BRAMR Backup RAM register (8bit) + * 3034 - PBR program bank register (8bit) + * 3035 - unused + * 3036 - ROMBR rom bank register (8bit) + * 3037 - CFGR control flags register (8bit) + * 3038 - SCBR screen base register (8bit) + * 3039 - CLSR clock speed register (8bit) + * 303a - SCMR screen mode register (8bit) + * 303b - VCR version code register (8bit) (read only) + * 303c - RAMBR ram bank register (8bit) + * 303d - unused + * 303e - CBR cache base register (16bit) + * + * 3040-30ff - unused + * + * 3100-32ff - CACHERAM 512 bytes of GSU cache memory + * + * SFR status flag register bits: + * 0 - + * 1 Z Zero flag + * 2 CY Carry flag + * 3 S Sign flag + * 4 OV Overflow flag + * 5 G Go flag (set to 1 when the GSU is running) + * 6 R Set to 1 when reading ROM using R14 address + * 7 - + * 8 ALT1 Mode set-up flag for the next instruction + * 9 ALT2 Mode set-up flag for the next instruction + * 10 IL Immediate lower 8-bit flag + * 11 IH Immediate higher 8-bit flag + * 12 B Set to 1 when the WITH instruction is executed + * 13 - + * 14 - + * 15 IRQ Set to 1 when GSU caused an interrupt + * Set to 0 when read by 658c16 + * + * BRAMR = 0, BackupRAM is disabled + * BRAMR = 1, BackupRAM is enabled + * + * CFGR control flags register bits: + * 0 - + * 1 - + * 2 - + * 3 - + * 4 - + * 5 MS0 Multiplier speed, 0=standard, 1=high speed + * 6 - + * 7 IRQ Set to 1 when GSU interrupt request is masked + * + * CLSR clock speed register bits: + * 0 CLSR clock speed, 0 = 10.7Mhz, 1 = 21.4Mhz + * + * SCMR screen mode register bits: + * 0 MD0 color depth mode bit 0 + * 1 MD1 color depth mode bit 1 + * 2 HT0 screen height bit 1 + * 3 RAN RAM access control + * 4 RON ROM access control + * 5 HT1 screen height bit 2 + * 6 - + * 7 - + * + * RON = 0 SNES CPU has ROM access + * RON = 1 GSU has ROM access + * + * RAN = 0 SNES has game pak RAM access + * RAN = 1 GSU has game pak RAM access + * + * HT1 HT0 Screen height mode + * 0 0 128 pixels high + * 0 1 160 pixels high + * 1 0 192 pixels high + * 1 1 OBJ mode + * + * MD1 MD0 Color depth mode + * 0 0 4 color mode + * 0 1 16 color mode + * 1 0 not used + * 1 1 256 color mode + * + * CBR cache base register bits: + * 15-4 Specify base address for data to cache from ROM or RAM + * 3-0 Are 0 when address is read + * + * Write access to the program counter (301e) from + * the SNES-CPU will start the GSU, and it will not + * stop until it reaches a stop instruction. + * + */ + +/* Number of banks in GSU RAM */ +#define FX_RAM_BANKS 4 + +/* Emulate proper R14 ROM access (slower, but safer) */ +/* #define FX_DO_ROMBUFFER */ + +/* Address checking (definately slow) */ +/* #define FX_ADDRESS_CHECK */ + +struct FxRegs_s +{ + /* FxChip registers */ + uint32 avReg[16]; /* 16 Generic registers */ + uint32 vColorReg; /* Internal color register */ + uint32 vPlotOptionReg; /* Plot option register */ + uint32 vStatusReg; /* Status register */ + uint32 vPrgBankReg; /* Program bank index register */ + uint32 vRomBankReg; /* Rom bank index register */ + uint32 vRamBankReg; /* Ram bank index register */ + uint32 vCacheBaseReg; /* Cache base address register */ + uint32 vCacheFlags; /* Saying what parts of the cache was written to */ + uint32 vLastRamAdr; /* Last RAM address accessed */ + uint32 * pvDreg; /* Pointer to current destination register */ + uint32 * pvSreg; /* Pointer to current source register */ + uint8 vRomBuffer; /* Current byte read by R14 */ + uint8 vPipe; /* Instructionset pipe */ + uint32 vPipeAdr; /* The address of where the pipe was read from */ + + /* status register optimization stuff */ + uint32 vSign; /* v & 0x8000 */ + uint32 vZero; /* v == 0 */ + uint32 vCarry; /* a value of 1 or 0 */ + int32 vOverflow; /* (v >= 0x8000 || v < -0x8000) */ + + /* Other emulator variables */ + + int32 vErrorCode; + uint32 vIllegalAddress; + + uint8 bBreakPoint; + uint32 vBreakPoint; + uint32 vStepPoint; + + uint8 * pvRegisters; /* 768 bytes located in the memory at address 0x3000 */ + uint32 nRamBanks; /* Number of 64kb-banks in FxRam (Don't confuse it with SNES-Ram!!!) */ + uint8 * pvRam; /* Pointer to FxRam */ + uint32 nRomBanks; /* Number of 32kb-banks in Cart-ROM */ + uint8 * pvRom; /* Pointer to Cart-ROM */ + + uint32 vMode; /* Color depth/mode */ + uint32 vPrevMode; /* Previous depth */ + uint8 * pvScreenBase; + uint8 * apvScreen[32]; /* Pointer to each of the 32 screen colums */ + int x[32]; + uint32 vScreenHeight; /* 128, 160, 192 or 256 (could be overriden by cmode) */ + uint32 vScreenRealHeight; /* 128, 160, 192 or 256 */ + uint32 vPrevScreenHeight; + uint32 vScreenSize; + void (*pfPlot)(); + void (*pfRpix)(); + + uint8 * pvRamBank; /* Pointer to current RAM-bank */ + uint8 * pvRomBank; /* Pointer to current ROM-bank */ + uint8 * pvPrgBank; /* Pointer to current program ROM-bank */ + + uint8 * apvRamBank[FX_RAM_BANKS];/* Ram bank table (max 256kb) */ + uint8 * apvRomBank[256]; /* Rom bank table */ + + uint8 bCacheActive; + uint8 * pvCache; /* Pointer to the GSU cache */ + uint8 avCacheBackup[512]; /* Backup of ROM when the cache has replaced it */ + uint32 vCounter; + uint32 vInstCount; + uint32 vSCBRDirty; /* if SCBR is written, our cached screen pointers need updating */ +}; + +#define FxRegs_s_null { \ + {0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, NULL, 0, NULL, 0, NULL, 0, \ + 0, NULL, {NULL}, {0}, 0, 0, 0, 0, NULL, NULL, \ + NULL, NULL, NULL, {NULL}, {NULL}, 0, NULL, {0}, 0, 0, \ + 0, \ +} + +/* GSU registers */ +#define GSU_R0 0x000 +#define GSU_R1 0x002 +#define GSU_R2 0x004 +#define GSU_R3 0x006 +#define GSU_R4 0x008 +#define GSU_R5 0x00a +#define GSU_R6 0x00c +#define GSU_R7 0x00e +#define GSU_R8 0x010 +#define GSU_R9 0x012 +#define GSU_R10 0x014 +#define GSU_R11 0x016 +#define GSU_R12 0x018 +#define GSU_R13 0x01a +#define GSU_R14 0x01c +#define GSU_R15 0x01e +#define GSU_SFR 0x030 +#define GSU_BRAMR 0x033 +#define GSU_PBR 0x034 +#define GSU_ROMBR 0x036 +#define GSU_CFGR 0x037 +#define GSU_SCBR 0x038 +#define GSU_CLSR 0x039 +#define GSU_SCMR 0x03a +#define GSU_VCR 0x03b +#define GSU_RAMBR 0x03c +#define GSU_CBR 0x03e +#define GSU_CACHERAM 0x100 + +/* SFR flags */ +#define FLG_Z (1<<1) +#define FLG_CY (1<<2) +#define FLG_S (1<<3) +#define FLG_OV (1<<4) +#define FLG_G (1<<5) +#define FLG_R (1<<6) +#define FLG_ALT1 (1<<8) +#define FLG_ALT2 (1<<9) +#define FLG_IL (1<<10) +#define FLG_IH (1<<11) +#define FLG_B (1<<12) +#define FLG_IRQ (1<<15) + +/* Test flag */ +#define TF(a) (GSU.vStatusReg & FLG_##a ) +#define CF(a) (GSU.vStatusReg &= ~FLG_##a ) +#define SF(a) (GSU.vStatusReg |= FLG_##a ) + +/* Test and set flag if condition, clear if not */ +#define TS(a,b) GSU.vStatusReg = ( (GSU.vStatusReg & (~FLG_##a)) | ( (!!(##b)) * FLG_##a ) ) + +/* Testing ALT1 & ALT2 bits */ +#define ALT0 (!TF(ALT1)&&!TF(ALT2)) +#define ALT1 (TF(ALT1)&&!TF(ALT2)) +#define ALT2 (!TF(ALT1)&&TF(ALT2)) +#define ALT3 (TF(ALT1)&&TF(ALT2)) + +/* Sign extend from 8/16 bit to 32 bit */ +#define SEX16(a) ((int32)((int16)(a))) +#define SEX8(a) ((int32)((int8)(a))) + +/* Unsign extend from 8/16 bit to 32 bit */ +#define USEX16(a) ((uint32)((uint16)(a))) +#define USEX8(a) ((uint32)((uint8)(a))) + +#define SUSEX16(a) ((int32)((uint16)(a))) + +/* Set/Clr Sign and Zero flag */ +#define TSZ(num) TS(S, (num & 0x8000)); TS(Z, (!USEX16(num)) ) + +/* Clear flags */ +#define CLRFLAGS GSU.vStatusReg &= ~(FLG_ALT1|FLG_ALT2|FLG_B); GSU.pvDreg = GSU.pvSreg = &R0; + +/* Read current RAM-Bank */ +#define RAM(adr) GSU.pvRamBank[USEX16(adr)] + +/* Read current ROM-Bank */ +#define ROM(idx) (GSU.pvRomBank[USEX16(idx)]) + +/* Access the current value in the pipe */ +#define PIPE GSU.vPipe + +/* Access data in the current program bank */ +#define PRGBANK(idx) GSU.pvPrgBank[USEX16(idx)] + +/* Update pipe from ROM */ +#if 0 +#define FETCHPIPE { PIPE = PRGBANK(R15); GSU.vPipeAdr = (GSU.vPrgBankReg<<16) + R15; } +#else +#define FETCHPIPE { PIPE = PRGBANK(R15); } +#endif + +/* ABS */ +#define ABS(x) ((x)<0?-(x):(x)) + +/* Access source register */ +#define SREG (*GSU.pvSreg) + +/* Access destination register */ +#define DREG (*GSU.pvDreg) + +#ifndef FX_DO_ROMBUFFER + +/* Don't read R14 */ +#define READR14 + +/* Don't test and/or read R14 */ +#define TESTR14 + +#else + +/* Read R14 */ +#define READR14 GSU.vRomBuffer = ROM(R14) + +/* Test and/or read R14 */ +#define TESTR14 if(GSU.pvDreg == &R14) READR14 + +#endif + +/* Access to registers */ +#define R0 GSU.avReg[0] +#define R1 GSU.avReg[1] +#define R2 GSU.avReg[2] +#define R3 GSU.avReg[3] +#define R4 GSU.avReg[4] +#define R5 GSU.avReg[5] +#define R6 GSU.avReg[6] +#define R7 GSU.avReg[7] +#define R8 GSU.avReg[8] +#define R9 GSU.avReg[9] +#define R10 GSU.avReg[10] +#define R11 GSU.avReg[11] +#define R12 GSU.avReg[12] +#define R13 GSU.avReg[13] +#define R14 GSU.avReg[14] +#define R15 GSU.avReg[15] +#define SFR GSU.vStatusReg +#define PBR GSU.vPrgBankReg +#define ROMBR GSU.vRomBankReg +#define RAMBR GSU.vRamBankReg +#define CBR GSU.vCacheBaseReg +#define SCBR USEX8(GSU.pvRegisters[GSU_SCBR]) +#define SCMR USEX8(GSU.pvRegisters[GSU_SCMR]) +#define COLR GSU.vColorReg +#define POR GSU.vPlotOptionReg +#define BRAMR USEX8(GSU.pvRegisters[GSU_BRAMR]) +#define VCR USEX8(GSU.pvRegisters[GSU_VCR]) +#define CFGR USEX8(GSU.pvRegisters[GSU_CFGR]) +#define CLSR USEX8(GSU.pvRegisters[GSU_CLSR]) + +/* Execute instruction from the pipe, and fetch next byte to the pipe */ +#define FX_STEP { uint32 vOpcode = (uint32)PIPE; FETCHPIPE; \ +(*fx_ppfOpcodeTable[ (GSU.vStatusReg & 0x300) | vOpcode ])(); } \ + +#define FX_FUNCTION_RUN 0 +#define FX_FUNCTION_RUN_TO_BREAKPOINT 1 +#define FX_FUNCTION_STEP_OVER 2 + +extern uint32 (**fx_ppfFunctionTable)(uint32); +extern void (**fx_ppfPlotTable)(); +extern void (**fx_ppfOpcodeTable)(); + +extern uint32 (*fx_apfFunctionTable[])(uint32); +extern void (*fx_apfOpcodeTable[])(); +extern void (*fx_apfPlotTable[])(); +extern uint32 (*fx_a_apfFunctionTable[])(uint32); +extern void (*fx_a_apfOpcodeTable[])(); +extern void (*fx_a_apfPlotTable[])(); +extern uint32 (*fx_r_apfFunctionTable[])(uint32); +extern void (*fx_r_apfOpcodeTable[])(); +extern void (*fx_r_apfPlotTable[])(); +extern uint32 (*fx_ar_apfFunctionTable[])(uint32); +extern void (*fx_ar_apfOpcodeTable[])(); +extern void (*fx_ar_apfPlotTable[])(); + +/* Set this define if branches are relative to the instruction in the delay slot */ +/* (I think they are) */ +#define BRANCH_DELAY_RELATIVE + +#endif + diff --git a/source/snes9x/getset.h b/source/snes9x/getset.h new file mode 100644 index 0000000..219ff6f --- /dev/null +++ b/source/snes9x/getset.h @@ -0,0 +1,887 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _GETSET_H_ +#define _GETSET_H_ + +#include "ppu.h" +#include "dsp1.h" +#include "cpuexec.h" +#include "sa1.h" +#include "spc7110.h" +#include "obc1.h" +#include "seta.h" +#include "bsx.h" + +extern "C" +{ + extern uint8 OpenBus; +} + +INLINE uint8 S9xGetByte (uint32 Address) +{ + int block; + uint8 *GetAddress = Memory.Map [block = ((Address&0xffffff) >> MEMMAP_SHIFT)]; + + if(!CPU.InDMA) + CPU.Cycles += Memory.MemorySpeed [block]; + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { +#ifdef CPU_SHUTDOWN + if (Memory.BlockIsRAM [block]) + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; +#endif + return (*(GetAddress + (Address & 0xffff))); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_PPU: + if(CPU.InDMA && (Address&0xff00)==0x2100) return OpenBus; + return (S9xGetPPU (Address & 0xffff)); + case CMemory::MAP_CPU: + return (S9xGetCPU (Address & 0xffff)); + case CMemory::MAP_DSP: + return (S9xGetDSP (Address & 0xffff)); + case CMemory::MAP_SA1RAM: + case CMemory::MAP_LOROM_SRAM: + //Address &0x7FFF -offset into bank + //Address&0xFF0000 -bank + //bank>>1 | offset = s-ram address, unbound + //unbound & SRAMMask = Sram offset + return (*(Memory.SRAM + ((((Address&0xFF0000)>>1) |(Address&0x7FFF)) &Memory.SRAMMask))); + + case CMemory::MAP_RONLY_SRAM: + case CMemory::MAP_HIROM_SRAM: + return (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask))); + + case CMemory::MAP_BWRAM: + return (*(Memory.BWRAM + ((Address & 0x7fff) - 0x6000))); + + case CMemory::MAP_C4: + return (S9xGetC4 (Address & 0xffff)); + + case CMemory::MAP_SPC7110_ROM: +#ifdef SPC7110_DEBUG + printf("reading spc7110 ROM (byte) at %06X\n", Address); +#endif + return S9xGetSPC7110Byte(Address); + + case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG + printf("reading Bank 50 (byte)\n"); +#endif + return S9xGetSPC7110(0x4800); + + case CMemory::MAP_OBC_RAM: + return GetOBC1(Address & 0xffff); + + case CMemory::MAP_SETA_DSP: + return S9xGetSetaDSP(Address); + + case CMemory::MAP_SETA_RISC: + return S9xGetST018(Address); + + case CMemory::MAP_BSX: + return S9xGetBSX(Address); + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("DEBUG R(B) %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return OpenBus; + } +} + +#ifdef NO_INLINE_SET_GET +INLINE uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w) +#else +INLINE uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w=WRAP_NONE) +#endif +{ + uint32 mask=MEMMAP_MASK&(w==WRAP_PAGE?0xff:(w==WRAP_BANK?0xffff:0xffffff)); + if ((Address & mask) == mask) + { + OpenBus=S9xGetByte(Address); + switch(w){ + case WRAP_PAGE: + { + PC_t a; + a.xPBPC = Address; + a.B.xPCl++; + return (OpenBus | (S9xGetByte (a.xPBPC) << 8)); + } + case WRAP_BANK: + { + PC_t a; + a.xPBPC = Address; + a.W.xPC++; + return (OpenBus | (S9xGetByte (a.xPBPC) << 8)); + } + case WRAP_NONE: + default: + return (OpenBus | (S9xGetByte (Address + 1) << 8)); + } + } + int block; + uint8 *GetAddress = Memory.Map [block = ((Address&0xffffff) >> MEMMAP_SHIFT)]; + + if(!CPU.InDMA) + CPU.Cycles += (Memory.MemorySpeed [block]<<1); + + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { +#ifdef CPU_SHUTDOWN + if (Memory.BlockIsRAM [block]) + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; +#endif + return READ_WORD(GetAddress + (Address & 0xffff)); + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_PPU: + if(CPU.InDMA){ + OpenBus=S9xGetByte (Address); + return (OpenBus | (S9xGetByte (Address + 1) << 8)); + } + return (S9xGetPPU (Address & 0xffff) | + (S9xGetPPU ((Address + 1) & 0xffff) << 8)); + case CMemory::MAP_CPU: + return (S9xGetCPU (Address & 0xffff) | + (S9xGetCPU ((Address + 1) & 0xffff) << 8)); + case CMemory::MAP_DSP: +#ifdef DSP_DUMMY_LOOPS + printf("Get DSP Word @ %06X\n", Address); +#endif + return (S9xGetDSP (Address & 0xffff) | + (S9xGetDSP ((Address + 1) & 0xffff) << 8)); + case CMemory::MAP_SA1RAM: + case CMemory::MAP_LOROM_SRAM: + //Address &0x7FFF -offset into bank + //Address&0xFF0000 -bank + //bank>>1 | offset = s-ram address, unbound + //unbound & SRAMMask = Sram offset + if(Memory.SRAMMask>=MEMMAP_MASK){ + return READ_WORD(Memory.SRAM + ((((Address&0xFF0000)>>1) |(Address&0x7FFF)) &Memory.SRAMMask)); + } else { + /* no READ_WORD here, since if Memory.SRAMMask=0x7ff + * then the high byte doesn't follow the low byte. */ + return + (*(Memory.SRAM + ((((Address&0xFF0000)>>1) |(Address&0x7FFF)) &Memory.SRAMMask)))| + ((*(Memory.SRAM + (((((Address+1)&0xFF0000)>>1) |((Address+1)&0x7FFF)) &Memory.SRAMMask)))<<8); + } + + case CMemory::MAP_RONLY_SRAM: + case CMemory::MAP_HIROM_SRAM: + if(Memory.SRAMMask>=MEMMAP_MASK){ + return READ_WORD(Memory.SRAM + + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); + } else { + /* no READ_WORD here, since if Memory.SRAMMask=0x7ff + * then the high byte doesn't follow the low byte. */ + return (*(Memory.SRAM + + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) | + (*(Memory.SRAM + + ((((Address + 1) & 0x7fff) - 0x6000 + + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask)) << 8)); + } + + case CMemory::MAP_BWRAM: + return READ_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)); + + case CMemory::MAP_C4: + return (S9xGetC4 (Address & 0xffff) | + (S9xGetC4 ((Address + 1) & 0xffff) << 8)); + + case CMemory::MAP_SPC7110_ROM: +#ifdef SPC7110_DEBUG + printf("reading spc7110 ROM (word) at %06X\n", Address); +#endif + return (S9xGetSPC7110Byte(Address)| + (S9xGetSPC7110Byte (Address+1))<<8); + case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG + printf("reading Bank 50 (word)\n"); +#endif + return (S9xGetSPC7110(0x4800)| + (S9xGetSPC7110 (0x4800) << 8)); + case CMemory::MAP_OBC_RAM: + return GetOBC1(Address&0xFFFF)| (GetOBC1((Address+1)&0xFFFF)<<8); + + case CMemory::MAP_SETA_DSP: + return S9xGetSetaDSP(Address)| (S9xGetSetaDSP((Address+1))<<8); + + case CMemory::MAP_SETA_RISC: + return S9xGetST018(Address)| (S9xGetST018((Address+1))<<8); + + case CMemory::MAP_BSX: + return S9xGetBSX(Address)| (S9xGetBSX((Address+1))<<8); + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("DEBUG R(W) %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return (OpenBus | (OpenBus<<8)); + } +} + +INLINE void S9xSetByte (uint8 Byte, uint32 Address) +{ +#if defined(CPU_SHUTDOWN) + CPU.WaitAddress = 0xffffffff; +#endif + int block; + uint8 *SetAddress = Memory.WriteMap [block = ((Address&0xffffff) >> MEMMAP_SHIFT)]; + + if (!CPU.InDMA) + CPU.Cycles += Memory.MemorySpeed [block]; + + + if (SetAddress >= (uint8 *) CMemory::MAP_LAST) + { +#ifdef CPU_SHUTDOWN + SetAddress += Address & 0xffff; + if (SetAddress == SA1.WaitByteAddress1 || + SetAddress == SA1.WaitByteAddress2) + { + SA1.Executing = SA1.S9xOpcodes != NULL; + SA1.WaitCounter = 0; + } + *SetAddress = Byte; +#else + *(SetAddress + (Address & 0xffff)) = Byte; +#endif + return; + } + + switch ((pint) SetAddress) + { + case CMemory::MAP_PPU: + if(CPU.InDMA && (Address&0xff00)==0x2100) return; + S9xSetPPU (Byte, Address & 0xffff); + return; + + case CMemory::MAP_CPU: + S9xSetCPU (Byte, Address & 0xffff); + return; + + case CMemory::MAP_DSP: +#ifdef DSP_DUMMY_LOOPS + printf("DSP Byte: %02X to %06X\n", Byte, Address); +#endif + S9xSetDSP (Byte, Address & 0xffff); + return; + + case CMemory::MAP_LOROM_SRAM: + if (Memory.SRAMMask) + { + *(Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF))& Memory.SRAMMask))=Byte; + CPU.SRAMModified = TRUE; + } + return; + + case CMemory::MAP_HIROM_SRAM: + if (Memory.SRAMMask) + { + *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = Byte; + CPU.SRAMModified = TRUE; + } + return; + + case CMemory::MAP_BWRAM: + *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte; + CPU.SRAMModified = TRUE; + return; + + case CMemory::MAP_SA1RAM: + *(Memory.SRAM + (Address & 0xffff)) = Byte; + SA1.Executing = !SA1.Waiting; + break; + + case CMemory::MAP_C4: + S9xSetC4 (Byte, Address & 0xffff); + return; + + case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG + printf("Writing Byte at %06X\n", Address); +#endif + s7r.bank50[(Address & 0xffff)]= (uint8) Byte; + break; + + case CMemory::MAP_OBC_RAM: + SetOBC1(Byte, Address &0xFFFF); + return; + + case CMemory::MAP_SETA_DSP: + S9xSetSetaDSP(Byte,Address); + return; + + case CMemory::MAP_SETA_RISC: + S9xSetST018(Byte,Address); + return; + + case CMemory::MAP_BSX: + S9xSetBSX(Byte,Address); + return; + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("W(B) %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return; + } +} + +#ifdef NO_INLINE_SET_GET +INLINE void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w, enum s9xwriteorder_t o) +#else +INLINE void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w=WRAP_NONE, enum s9xwriteorder_t o=WRITE_01) +#endif +{ + uint32 mask=MEMMAP_MASK&(w==WRAP_PAGE?0xff:(w==WRAP_BANK?0xffff:0xffffff)); + if ((Address & mask) == mask) + { + if(!o) S9xSetByte(Word&0x00FF, Address); + switch(w){ + case WRAP_PAGE: + { + PC_t a; + a.xPBPC = Address; + a.B.xPCl++; + S9xSetByte(Word>>8, a.xPBPC); + } + case WRAP_BANK: + { + PC_t a; + a.xPBPC = Address; + a.W.xPC++; + S9xSetByte(Word>>8, a.xPBPC); + } + case WRAP_NONE: + default: + S9xSetByte(Word>>8, Address+1); + } + if(o) S9xSetByte(Word&0x00FF, Address); + return; + } + +#if defined(CPU_SHUTDOWN) + CPU.WaitAddress = 0xffffffff; +#endif + int block; + uint8 *SetAddress = Memory.WriteMap [block = ((Address&0xffffff) >> MEMMAP_SHIFT)]; + + if (!CPU.InDMA) + CPU.Cycles += Memory.MemorySpeed [block] << 1; + + + if (SetAddress >= (uint8 *) CMemory::MAP_LAST) + { +#ifdef CPU_SHUTDOWN + SetAddress += Address & 0xffff; + if (SetAddress == SA1.WaitByteAddress1 || + SetAddress == SA1.WaitByteAddress2) + { + SA1.Executing = SA1.S9xOpcodes != NULL; + SA1.WaitCounter = 0; + } + WRITE_WORD(SetAddress, Word); +#else + WRITE_WORD(SetAddress + (Address & 0xffff), Word); +#endif + return; + } + + switch ((pint) SetAddress) + { + case CMemory::MAP_PPU: + if(CPU.InDMA){ + if((Address&0xff00)!=0x2100) S9xSetPPU((uint8)Word, Address&0xffff); + if(((Address+1)&0xff00)!=0x2100) S9xSetPPU(Word>>8, (Address+1)&0xffff); + return; + } + if(o){ + S9xSetPPU (Word >> 8, (Address & 0xffff) + 1); + S9xSetPPU ((uint8) Word, Address & 0xffff); + } else { + S9xSetPPU ((uint8) Word, Address & 0xffff); + S9xSetPPU (Word >> 8, (Address & 0xffff) + 1); + } + return; + + case CMemory::MAP_CPU: + if(o){ + S9xSetCPU (Word >> 8, (Address & 0xffff) + 1); + S9xSetCPU ((uint8) Word, (Address & 0xffff)); + } else { + S9xSetCPU ((uint8) Word, (Address & 0xffff)); + S9xSetCPU (Word >> 8, (Address & 0xffff) + 1); + } + return; + + case CMemory::MAP_DSP: +#ifdef DSP_DUMMY_LOOPS + printf("DSP Word: %04X to %06X\n", Word, Address); +#endif + if(o){ + S9xSetDSP (Word >> 8, (Address & 0xffff) + 1); + S9xSetDSP ((uint8) Word, (Address & 0xffff)); + } else { + S9xSetDSP ((uint8) Word, (Address & 0xffff)); + S9xSetDSP (Word >> 8, (Address & 0xffff) + 1); + } + return; + + case CMemory::MAP_LOROM_SRAM: + if (Memory.SRAMMask) { + if(Memory.SRAMMask>=MEMMAP_MASK){ + WRITE_WORD(Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF))&Memory.SRAMMask), Word); + } else { + /* no WRITE_WORD here, since if Memory.SRAMMask=0x7ff + * then the high byte doesn't follow the low byte. */ + *(Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF))& Memory.SRAMMask)) = (uint8) Word; + *(Memory.SRAM + (((((Address+1)&0xFF0000)>>1)|((Address+1)&0x7FFF))& Memory.SRAMMask)) = Word >> 8; + } + + CPU.SRAMModified = TRUE; + } + return; + + case CMemory::MAP_HIROM_SRAM: + if (Memory.SRAMMask) { + if(Memory.SRAMMask>=MEMMAP_MASK){ + WRITE_WORD(Memory.SRAM + + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3) & Memory.SRAMMask)), Word); + } else { + /* no WRITE_WORD here, since if Memory.SRAMMask=0x7ff + * then the high byte doesn't follow the low byte. */ + *(Memory.SRAM + + (((Address & 0x7fff) - 0x6000 + + ((Address & 0xf0000) >> 3) & Memory.SRAMMask))) = (uint8) Word; + *(Memory.SRAM + + ((((Address + 1) & 0x7fff) - 0x6000 + + (((Address + 1) & 0xf0000) >> 3) & Memory.SRAMMask))) = (uint8) (Word >> 8); + } + CPU.SRAMModified = TRUE; + } + return; + + case CMemory::MAP_BWRAM: + WRITE_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000), Word); + CPU.SRAMModified = TRUE; + return; + + case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG + printf("Writing Word at %06X\n", Address); +#endif + WRITE_WORD(s7r.bank50+(Address & 0xffff), Word); + break; + + case CMemory::MAP_SA1RAM: + WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word); + SA1.Executing = !SA1.Waiting; + break; + + case CMemory::MAP_C4: + if(o){ + S9xSetC4 ((uint8) (Word >> 8), (Address + 1) & 0xffff); + S9xSetC4 (Word & 0xff, Address & 0xffff); + } else { + S9xSetC4 (Word & 0xff, Address & 0xffff); + S9xSetC4 ((uint8) (Word >> 8), (Address + 1) & 0xffff); + } + return; + + case CMemory::MAP_OBC_RAM: + if(o){ + SetOBC1((uint8) (Word >> 8), (Address + 1) & 0xffff); + SetOBC1(Word & 0xff, Address &0xFFFF); + } else { + SetOBC1(Word & 0xff, Address &0xFFFF); + SetOBC1 ((uint8) (Word >> 8), (Address + 1) & 0xffff); + } + return; + + case CMemory::MAP_SETA_DSP: + if(o){ + S9xSetSetaDSP ((uint8) (Word >> 8),(Address + 1)); + S9xSetSetaDSP (Word & 0xff, Address); + } else { + S9xSetSetaDSP (Word & 0xff, Address); + S9xSetSetaDSP ((uint8) (Word >> 8),(Address + 1)); + } + return; + + case CMemory::MAP_SETA_RISC: + if(o){ + S9xSetST018 ((uint8) (Word >> 8),(Address + 1)); + S9xSetST018 (Word & 0xff, Address); + } else { + S9xSetST018 (Word & 0xff, Address); + S9xSetST018 ((uint8) (Word >> 8),(Address + 1)); + } + return; + + case CMemory::MAP_BSX: + if(o){ + S9xSetBSX ((uint8) (Word >> 8),(Address + 1)); + S9xSetBSX (Word & 0xff, Address); + } else { + S9xSetBSX (Word & 0xff, Address); + S9xSetBSX ((uint8) (Word >> 8),(Address + 1)); + } + return; + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("W(W) %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return; + } +} + +INLINE uint8 *GetBasePointer (uint32 Address) +{ + uint8 *GetAddress = Memory.Map [((Address&0xffffff) >> MEMMAP_SHIFT)]; + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + return (GetAddress); + + switch ((pint) GetAddress) + { +// case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG +// printf("Getting Base pointer to DRAM\n"); +#endif +// { +// return s7r.bank50; +// } + + case CMemory::MAP_SPC7110_ROM: +#ifdef SPC7110_DEBUG + printf("Getting Base pointer to SPC7110ROM\n"); +#endif + return Get7110BasePtr(Address); + + case CMemory::MAP_SA1RAM: + return (Memory.SRAM); + + case CMemory::MAP_LOROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK) return NULL; + return (Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF)) & Memory.SRAMMask) - (Address&0xffff)); + + case CMemory::MAP_BWRAM: + return (Memory.BWRAM - 0x6000 - (Address&0x8000)); + + case CMemory::MAP_HIROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK) return NULL; + return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address&0xffff)); + + case CMemory::MAP_C4: + return S9xGetBasePointerC4(Address); + + case CMemory::MAP_OBC_RAM: + return GetBasePointerOBC1(Address); + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("GBP %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return (0); + } +} + +INLINE uint8 *S9xGetMemPointer (uint32 Address) +{ + uint8 *GetAddress = Memory.Map [((Address&0xffffff) >> MEMMAP_SHIFT)]; + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + return (GetAddress + (Address&0xffff)); + + switch ((pint) GetAddress) + { +// case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG +// printf("Getting Mem pointer to DRAM\n"); +#endif +// { +// return s7r.bank50 + (Address&0xffff); +// } + + case CMemory::MAP_SPC7110_ROM: +#ifdef SPC7110_DEBUG + printf("Getting Mem pointer to SPC7110ROM\n"); +#endif + return Get7110BasePtr(Address) + (Address&0xffff); + + case CMemory::MAP_SA1RAM: + return (Memory.SRAM + (Address&0xffff)); + + case CMemory::MAP_LOROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK) return NULL; + return (Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF)) & Memory.SRAMMask)); + + case CMemory::MAP_BWRAM: + return (Memory.BWRAM - 0x6000 + (Address&0x7fff)); + + case CMemory::MAP_HIROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK) return NULL; + return (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)); + + case CMemory::MAP_C4: + return S9xGetBasePointerC4(Address) + (Address&0xffff); + + case CMemory::MAP_OBC_RAM: + return GetMemPointerOBC1(Address); + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("GMP %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + return (0); + } +} + +INLINE void S9xSetPCBase (uint32 Address) +{ + Registers.PBPC = Address & 0xffffff; + ICPU.ShiftedPB = Address & 0xff0000; + + int block; + uint8 *GetAddress = Memory.Map [block = ((Address&0xffffff) >> MEMMAP_SHIFT)]; + + CPU.MemSpeed = Memory.MemorySpeed [block]; + CPU.MemSpeedx2 = CPU.MemSpeed << 1; + + if (GetAddress >= (uint8 *) CMemory::MAP_LAST){ + CPU.PCBase = GetAddress; + return; + } + + switch ((pint) GetAddress) + { +// case CMemory::MAP_SPC7110_DRAM: +#ifdef SPC7110_DEBUG +// printf("Getting Base pointer to DRAM\n"); +#endif +// { +// CPU.PCBase = s7r.bank50; +// return; +// } + + case CMemory::MAP_SPC7110_ROM: +#ifdef SPC7110_DEBUG + printf("Getting Base pointer to SPC7110ROM\n"); +#endif + CPU.PCBase = Get7110BasePtr(Address); + return; + + case CMemory::MAP_SA1RAM: + CPU.PCBase = Memory.SRAM; + return; + + case CMemory::MAP_LOROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK){ + CPU.PCBase = NULL; + } else { + CPU.PCBase = (Memory.SRAM + ((((Address&0xFF0000)>>1)|(Address&0x7FFF)) & Memory.SRAMMask)) - (Address&0xffff); + } + return; + + case CMemory::MAP_BWRAM: + CPU.PCBase = (Memory.BWRAM - 0x6000 - (Address&0x8000)); + return; + + case CMemory::MAP_HIROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK){ + CPU.PCBase = NULL; + } else { + CPU.PCBase = (Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) - (Address&0xffff); + } + return; + + case CMemory::MAP_C4: + CPU.PCBase = S9xGetBasePointerC4(Address); + return; + + case CMemory::MAP_OBC_RAM: + CPU.PCBase = GetBasePointerOBC1(Address); + return; + + case CMemory::MAP_BSX: + CPU.PCBase = S9xGetPasePointerBSX(Address); + return; + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("SBP %06x\n", Address); +#endif + default: + case CMemory::MAP_NONE: + CPU.PCBase = NULL; + return; + } +} +#endif + diff --git a/source/snes9x/gfx.cpp b/source/snes9x/gfx.cpp new file mode 100644 index 0000000..702c0b8 --- /dev/null +++ b/source/snes9x/gfx.cpp @@ -0,0 +1,1746 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "cpuexec.h" +#include "gfx.h" +#include "ppu.h" +#include "tile.h" +#include "display.h" +#include "controls.h" +#include "screenshot.h" + +#ifndef NGC +#include "cheats.h" +#endif + +static void S9xDisplayString(const char *string); +static void S9xDisplayFrameRate(); +void ComputeClipWindows(); + +extern struct SLineData LineData[240]; +extern struct SLineMatrixData LineMatrixData [240]; + +bool8 S9xGraphicsInit(){ + S9xInitTileRenderer(); + ZeroMemory(BlackColourMap, 256*sizeof(uint16)); + +#ifdef GFX_MULTI_FORMAT + if(GFX.BuildPixel==NULL) S9xSetRenderPixelFormat(RGB565); +#endif + + GFX.DoInterlace=0; + GFX.InterlaceFrame=0; + PPU.BG_Forced=0; + IPPU.OBJChanged=TRUE; + IPPU.DirectColourMapsNeedRebuild=TRUE; + GFX.RealPPL=GFX.Pitch>>1; + S9xFixColourBrightness(); + + GFX.X2=GFX.ZERO_OR_X2=GFX.ZERO=NULL; + if(!(GFX.X2=(uint16*)malloc(sizeof(uint16)*0x10000))) goto FAIL; +#if !defined(NEW_COLOUR_BLENDING) + if(!(GFX.ZERO_OR_X2=(uint16*)malloc(sizeof(uint16)*0x10000))) goto FAIL; +#endif + if(!(GFX.ZERO=(uint16*)malloc(sizeof(uint16)*0x10000))) goto FAIL; + + GFX.ScreenSize=GFX.Pitch/2*SNES_HEIGHT_EXTENDED*(Settings.SupportHiRes?2:1); + if(!(GFX.SubScreen=(uint16*)malloc(GFX.ScreenSize*sizeof(uint16)))) goto FAIL; + if(!(GFX.ZBuffer=(uint8*)malloc(GFX.ScreenSize))) goto FAIL; + if(!(GFX.SubZBuffer=(uint8*)malloc(GFX.ScreenSize))) goto FAIL; + + uint32 r, g, b; + /* Lookup table for color addition */ + for(r=0; r<=MAX_RED; r++){ + uint32 r2=r<<1; if(r2>MAX_RED) r2=MAX_RED; + for(g=0; g<=MAX_GREEN; g++){ + uint32 g2=g<<1; if(g2>MAX_GREEN) g2=MAX_GREEN; + for(b=0; b<=MAX_BLUE; b++){ + uint32 b2=b<<1; if(b2>MAX_BLUE) b2=MAX_BLUE; + GFX.X2[BUILD_PIXEL2(r,g,b)]=BUILD_PIXEL2(r2,g2,b2); + GFX.X2[BUILD_PIXEL2(r,g,b) & ~ALPHA_BITS_MASK]=BUILD_PIXEL2(r2,g2,b2); + } + } + } + +#if !defined(NEW_COLOUR_BLENDING) + /* Lookup table for color subtraction */ + ZeroMemory(GFX.ZERO_OR_X2, 0x10000*sizeof(uint16)); + for(r=0; r<=MAX_RED; r++){ + uint32 r2=r; if(r2&0x10) r2=(r2<<1)&MAX_RED; else r2=0; +#if !defined(OLD_COLOUR_BLENDING) + if(r2==0) r2=1; +#endif + for(g=0; g<=MAX_GREEN; g++){ + uint32 g2=g; if(g2&GREEN_HI_BIT) g2=(g2<<1)&MAX_GREEN; else g2=0; +#if !defined(OLD_COLOUR_BLENDING) + if(g2==0) g2=1; +#endif + for(b=0; b<=MAX_BLUE; b++){ + uint32 b2=b; if(b2&0x10) b2=(b2<<1)&MAX_BLUE; else b2=0; +#if !defined(OLD_COLOUR_BLENDING) + if(b2==0) b2=1; +#endif + GFX.ZERO_OR_X2[BUILD_PIXEL2(r,g,b)]=BUILD_PIXEL2(r2,g2,b2); + GFX.ZERO_OR_X2[BUILD_PIXEL2(r,g,b) & ~ALPHA_BITS_MASK]=BUILD_PIXEL2(r2,g2,b2); + } + } + } +#endif + + /* Lookup table for 1/2 color subtraction */ + ZeroMemory(GFX.ZERO, 0x10000*sizeof(uint16)); + for(r=0; r<=MAX_RED; r++){ + uint32 r2=r; if(r2&0x10) r2&=~0x10; else r2=0; + for(g=0; g<=MAX_GREEN; g++){ + uint32 g2=g; if(g2&GREEN_HI_BIT) g2&=~GREEN_HI_BIT; else g2=0; + for(b=0; b<=MAX_BLUE; b++){ + uint32 b2=b; if(b2&0x10) b2&=~0x10; else b2=0; + GFX.ZERO[BUILD_PIXEL2(r,g,b)]=BUILD_PIXEL2(r2,g2,b2); + GFX.ZERO[BUILD_PIXEL2(r,g,b) & ~ALPHA_BITS_MASK]=BUILD_PIXEL2(r2,g2,b2); + } + } + } + + return TRUE; + +FAIL: + S9xGraphicsDeinit(); + return FALSE; +} + +void S9xGraphicsDeinit(void){ + if(GFX.X2) free(GFX.X2); GFX.X2=NULL; + if(GFX.ZERO_OR_X2) free(GFX.ZERO_OR_X2); GFX.ZERO_OR_X2=NULL; + if(GFX.ZERO) free(GFX.ZERO); GFX.ZERO=NULL; + if(GFX.SubScreen) free(GFX.SubScreen); GFX.SubScreen=NULL; + if(GFX.ZBuffer) free(GFX.ZBuffer); GFX.ZBuffer=NULL; + if(GFX.SubZBuffer) free(GFX.SubZBuffer); GFX.SubZBuffer=NULL; +} + +void S9xBuildDirectColourMaps(void){ + IPPU.XB=mul_brightness[PPU.Brightness]; + + for(uint32 p=0; p<8; p++){ + for(uint32 c=0; c<256; c++){ + DirectColourMaps[p][c]=BUILD_PIXEL(IPPU.XB[((c&7)<<2) | ((p&1)<<1)], + IPPU.XB[((c&0x38)>>1) | (p&2)], + IPPU.XB[((c&0xc0)>>3) | (p&4)]); + } + } + IPPU.DirectColourMapsNeedRebuild=FALSE; +} + +void S9xStartScreenRefresh(){ + if(GFX.InfoStringTimeout>0 && --GFX.InfoStringTimeout==0) + GFX.InfoString=NULL; + + if(IPPU.RenderThisFrame){ + if(GFX.DoInterlace && GFX.InterlaceFrame==0){ + GFX.InterlaceFrame=1; + } else { + if(!S9xInitUpdate()){ + IPPU.RenderThisFrame=FALSE; + return; + } + GFX.InterlaceFrame=0; + if(GFX.DoInterlace) GFX.DoInterlace--; + IPPU.RenderedFramesCount++; + IPPU.MaxBrightness=PPU.Brightness; + if(PPU.BGMode==5 || PPU.BGMode==6){ + IPPU.Interlace = (Memory.FillRAM[0x2133]&1); + IPPU.InterlaceOBJ = (Memory.FillRAM[0x2133]&2); + } + IPPU.PseudoHires = Memory.FillRAM[0x2133]&8; + if(Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires || IPPU.Interlace || IPPU.InterlaceOBJ)){ + GFX.RealPPL = GFX.Pitch>>1; + IPPU.DoubleWidthPixels = TRUE; + IPPU.RenderedScreenWidth = 512; + if(IPPU.Interlace || IPPU.InterlaceOBJ){ + GFX.PPL = GFX.RealPPL<<1; + IPPU.DoubleHeightPixels = TRUE; + IPPU.RenderedScreenHeight = PPU.ScreenHeight<<1; + GFX.DoInterlace++; + } else { + GFX.PPL = GFX.RealPPL; + IPPU.DoubleHeightPixels = FALSE; + IPPU.RenderedScreenHeight = PPU.ScreenHeight; + } + } else { + IPPU.DoubleWidthPixels = FALSE; + IPPU.DoubleHeightPixels = FALSE; + IPPU.RenderedScreenWidth = 256; + IPPU.RenderedScreenHeight = PPU.ScreenHeight; +#ifdef USE_GLIDE + if(Settings.GlideEnable) { + // Speed up hack for Glide: render low res. SNES images + // into a handy 256x256 sized buffer that can be uploaded + // into texture memory with one Glide call without having + // to copy it into a second, suitably sized buffer first. + GFX.RealPPL = GFX.PPL = 256; + } else +#endif +#ifdef USE_OPENGL + if(Settings.OpenGLEnable) { + // Ditto for OpenGL + GFX.RealPPL = GFX.PPL = 256; + } else +#endif + { + GFX.RealPPL = GFX.PPL = GFX.Pitch>>1; + } + } + } + PPU.MosaicStart=0; + IPPU.PreviousLine=IPPU.CurrentLine=0; + PPU.RecomputeClipWindows=TRUE; + ZeroMemory(GFX.ZBuffer, GFX.ScreenSize); + ZeroMemory(GFX.SubZBuffer, GFX.ScreenSize); + } + if(++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0) { + IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount; + IPPU.RenderedFramesCount = 0; + IPPU.FrameCount = 0; + } +} + +void RenderLine(uint8 C) { + if(IPPU.RenderThisFrame) { + LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1; + LineData[C].BG[0].HOffset = PPU.BG[0].HOffset; + LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1; + LineData[C].BG[1].HOffset = PPU.BG[1].HOffset; + + if(PPU.BGMode==7) { + struct SLineMatrixData *p = &LineMatrixData [C]; + p->MatrixA = PPU.MatrixA; + p->MatrixB = PPU.MatrixB; + p->MatrixC = PPU.MatrixC; + p->MatrixD = PPU.MatrixD; + p->CentreX = PPU.CentreX; + p->CentreY = PPU.CentreY; + p->M7HOFS = PPU.M7HOFS; + p->M7VOFS = PPU.M7VOFS; + } else { + LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1; + LineData[C].BG[2].HOffset = PPU.BG[2].HOffset; + LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1; + LineData[C].BG[3].HOffset = PPU.BG[3].HOffset; + } + IPPU.CurrentLine = C + 1; + } else { + /* if we're not rendering this frame, we still need to update this */ + // XXX: Check ForceBlank? Or anything else? + if(IPPU.OBJChanged) S9xSetupOBJ(); + PPU.RangeTimeOver |= GFX.OBJLines[C].RTOFlags; + } +} + +void S9xEndScreenRefresh() { + if(IPPU.RenderThisFrame) { + FLUSH_REDRAW(); + if(GFX.DoInterlace && GFX.InterlaceFrame==0){ + S9xControlEOF(); + // XXX: Invent S9xContinueUpdate()? + } else { + if(IPPU.ColorsChanged) { + uint32 saved = PPU.CGDATA[0]; + IPPU.ColorsChanged = FALSE; + S9xSetPalette (); + PPU.CGDATA[0] = saved; + } + +#ifndef NGC + if(Settings.TakeScreenshot) + S9xDoScreenshot(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); +#endif + S9xControlEOF(); + if (Settings.DisplayFrameRate) + S9xDisplayFrameRate(); + if (GFX.InfoString) + S9xDisplayString(GFX.InfoString); + S9xDeinitUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight); + } + } else { + S9xControlEOF(); + } + +#ifndef NGC + S9xApplyCheats(); +#endif + +#ifdef DEBUGGER + if(CPU.Flags & FRAME_ADVANCE_FLAG) { + if(ICPU.FrameAdvanceCount) { + ICPU.FrameAdvanceCount--; + IPPU.RenderThisFrame = TRUE; + IPPU.FrameSkip = 0; + } else { + CPU.Flags &= ~FRAME_ADVANCE_FLAG; + CPU.Flags |= DEBUG_MODE_FLAG; + } + } +#endif + if(CPU.SRAMModified) { + if(!CPU.AutoSaveTimer) { + if(!(CPU.AutoSaveTimer=Settings.AutoSaveDelay*Memory.ROMFramesPerSecond)) + CPU.SRAMModified=FALSE; + } else { + if(!--CPU.AutoSaveTimer) { + S9xAutoSaveSRAM(); + CPU.SRAMModified=FALSE; + } + } + } +} + + +void S9xSetupOBJ() { + int SmallWidth, SmallHeight; + int LargeWidth, LargeHeight; + + switch(PPU.OBJSizeSelect) { + case 0: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 16; + break; + case 1: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 32; + break; + case 2: + SmallWidth = SmallHeight = 8; + LargeWidth = LargeHeight = 64; + break; + case 3: + SmallWidth = SmallHeight = 16; + LargeWidth = LargeHeight = 32; + break; + case 4: + SmallWidth = SmallHeight = 16; + LargeWidth = LargeHeight = 64; + break; + default: + case 5: + SmallWidth = SmallHeight = 32; + LargeWidth = LargeHeight = 64; + break; + case 6: + SmallWidth = 16; SmallHeight = 32; + LargeWidth = 32; LargeHeight = 64; + break; + case 7: + SmallWidth = 16; SmallHeight = 32; + LargeWidth = LargeHeight = 32; + break; + } + int inc=IPPU.InterlaceOBJ?2:1; + + /* OK, we have three cases here. Either there's no priority, priority is + * normal FirstSprite, or priority is FirstSprite+Y. The first two are + * easy, the last is somewhat more ... interesting. So we split them up. */ + + int Height; + uint8 S; + + if(!PPU.OAMPriorityRotation || !(PPU.OAMFlip&PPU.OAMAddr&1)){ + /* normal case */ + uint8 LineOBJ[SNES_HEIGHT_EXTENDED]; + memset(LineOBJ, 0, sizeof(LineOBJ)); + for(int i=0; i-GFX.OBJWidths[S] && HPos<=256) + { + if(HPos<0){ + GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3; + } else if(HPos+GFX.OBJWidths[S]>=257){ + GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3; + } else { + GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3; + } + for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line=SNES_HEIGHT_EXTENDED) continue; + if(LineOBJ[Y]>=32){ + GFX.OBJLines[Y].RTOFlags|=0x40; + continue; + } + GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S]; + if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80; + GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite=S; + if(PPU.OBJ[S].VFlip){ + // Yes, Width not Height. It so happens that the + // sprites with H=2*W flip as two WxW sprites. + GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line^(GFX.OBJWidths[S]-1); + } else { + GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line; + } + LineOBJ[Y]++; + } + } + S=(S+1)&0x7F; + } while(S!=FirstSprite); + + for(int Y=1; Y-GFX.OBJWidths[S] && HPos<=256) + { + if(HPos<0){ + GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3; + } else if(HPos+GFX.OBJWidths[S]>=257){ + GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3; + } else { + GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3; + } + for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line=SNES_HEIGHT_EXTENDED) continue; + if(PPU.OBJ[S].VFlip){ + // Yes, Width not Height. It so happens that the + // sprites with H=2*W flip as two WxW sprites. + OBJOnLine[Y][S]=(line^(GFX.OBJWidths[S]-1)) | 0x80; + } else { + OBJOnLine[Y][S]=line | 0x80; + } + } + } + } + + /* Now go through and pull out those OBJ that are actually visible. */ + int j; + for(int Y=0; Y=32){ + GFX.OBJLines[Y].RTOFlags|=0x40; + break; + } + GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S]; + if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80; + GFX.OBJLines[Y].OBJ[j].Sprite=S; + GFX.OBJLines[Y].OBJ[j++].Line=OBJOnLine[Y][S]&~0x80; + } + S=(S+1)&0x7F; + } while(S!=FirstSprite); + if(j<32) GFX.OBJLines[Y].OBJ[j].Sprite=-1; + } + } + + IPPU.OBJChanged = FALSE; +} + +void DrawOBJS(int D){ + CHECK_SOUND(); + + void (*DrawTile)(uint32,uint32,uint32,uint32)=NULL; + void (*DrawClippedTile)(uint32,uint32,uint32,uint32,uint32,uint32)=NULL; + + int PixWidth = IPPU.DoubleWidthPixels?2:1; + GFX.Z1=2; + BG.InterlaceLine = GFX.InterlaceFrame?8:0; + + for(uint32 Y=GFX.StartY, Offset=Y*GFX.PPL; Y<=GFX.EndY; Y++, Offset+=GFX.PPL){ + int I = 0; + int tiles=GFX.OBJLines[Y].Tiles; + for (int S = GFX.OBJLines[Y].OBJ[I].Sprite; S >= 0 && I<32; S = GFX.OBJLines[Y].OBJ[++I].Sprite) + { + tiles+=GFX.OBJVisibleTiles[S]; + if(tiles<=0){ + continue; + } + + int BaseTile = (((GFX.OBJLines[Y].OBJ[I].Line<<1) + (PPU.OBJ[S].Name&0xf0))&0xf0) | (PPU.OBJ[S].Name&0x100) | (PPU.OBJ[S].Palette << 10); + int TileX = PPU.OBJ[S].Name&0x0f; + int TileLine = (GFX.OBJLines[Y].OBJ[I].Line&7)*8; + if(IPPU.InterlaceOBJ) TileLine>>=1; + int TileInc = 1; + + if (PPU.OBJ[S].HFlip) + { + TileX = (TileX + (GFX.OBJWidths[S] >> 3) - 1) & 0x0f; + BaseTile |= H_FLIP; + TileInc = -1; + } + + GFX.Z2 = D+PPU.OBJ[S].Priority*4; + + int DrawMode=3; + int clip=0, next_clip=-1000; + int X=PPU.OBJ[S].HPos; if(X==-256) X=256; + for(int t=tiles, O=Offset+X*PixWidth; X<=256 && X=next_clip){ + for(; clip=GFX.Clip[4].Right[clip-1]){ + DrawMode=0; + next_clip=((clip=(uint16*)(Memory.VRAM+0x10000)) SC1-=0x8000; + SC2=(PPU.BG[bg].SCSize&2)?SC1+1024:SC0; + if(SC2>=(uint16*)(Memory.VRAM+0x10000)) SC2-=0x8000; + SC3=(PPU.BG[bg].SCSize&1)?SC2+1024:SC2; + if(SC3>=(uint16*)(Memory.VRAM+0x10000)) SC3-=0x8000; + + uint32 Lines; + int OffsetMask = (BG.TileSizeH==16)?0x3ff:0x1ff; + int OffsetShift = (BG.TileSizeV==16)?4:3; + int PixWidth = IPPU.DoubleWidthPixels?2:1; + + void (*DrawTile)(uint32,uint32,uint32,uint32); + void (*DrawClippedTile)(uint32,uint32,uint32,uint32,uint32,uint32); + for(int clip=0; clip>(IPPU.Interlace?1:0); + + for(Lines=1; LinesGFX.EndY) Lines=GFX.EndY-Y+1; + VirtAlign<<=3; + + uint32 TilemapRow = (VOffset+Y2)>>OffsetShift; + BG.InterlaceLine = ((VOffset+Y2)&1)<<3; + uint32 t1, t2; + if(((VOffset+Y2)&8)){ + t1=16; t2=0; + } else { + t1=0; t2=16; + } + uint16 *b1; + uint16 *b2; + if(TilemapRow&0x20) { + b1=SC2; b2=SC3; + } else { + b1=SC0; b2=SC1; + } + b1+=(TilemapRow&0x1f)<<5; + b2+=(TilemapRow&0x1f)<<5; + + uint32 Left = GFX.Clip[bg].Left[clip]; + uint32 Right = GFX.Clip[bg].Right[clip]; + uint32 Offset = Left*PixWidth+Y*GFX.PPL; + uint32 HPos = (HOffset+Left)&OffsetMask; + uint32 HTile = HPos>>3; + uint16 *t; + if(BG.TileSizeH==8){ + if(HTile>31) + t=b2+(HTile&0x1f); + else + t=b1+HTile; + } else { + if(HTile>63) + t=b2+((HTile>>1)&0x1f); + else + t=b1+(HTile>>1); + } + + uint32 Width = Right-Left; + if(HPos&7) { + uint32 l=HPos&7; + uint32 w=8-l; + if(w>Width) w=Width; + Offset-=l*PixWidth; + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawClippedTile(Tile, Offset, l, w, VirtAlign, Lines); + t++; + if(HTile==31) t=b2; + else if(HTile==63) t=b1; + } else { + if(!(Tile&H_FLIP)){ + DrawClippedTile(TILE_PLUS(Tile, (HTile&1)), Offset, l, w, VirtAlign, Lines); + } else { + DrawClippedTile(TILE_PLUS(Tile, 1-(HTile&1)), Offset, l, w, VirtAlign, Lines); + } + t+=HTile&1; + if(HTile==63) t=b2; + else if(HTile==127) t=b1; + } + HTile++; + Offset+=8*PixWidth; + Width-=w; + } + while(Width>=8){ + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawTile(Tile, Offset, VirtAlign, Lines); + t++; + if(HTile==31) t=b2; + else if(HTile==63) t=b1; + } else { + if(!(Tile&H_FLIP)){ + DrawTile(TILE_PLUS(Tile, (HTile&1)), Offset, VirtAlign, Lines); + } else { + DrawTile(TILE_PLUS(Tile, 1-(HTile&1)), Offset, VirtAlign, Lines); + } + t+=HTile&1; + if(HTile==63) t=b2; + else if(HTile==127) t=b1; + } + HTile++; + Offset+=8*PixWidth; + Width-=8; + } + if(Width){ + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawClippedTile(Tile, Offset, 0, Width, VirtAlign, Lines); + } else { + if(!(Tile&H_FLIP)){ + DrawClippedTile(TILE_PLUS(Tile, (HTile&1)), Offset, 0, Width, VirtAlign, Lines); + } else { + DrawClippedTile(TILE_PLUS(Tile, 1-(HTile&1)), Offset, 0, Width, VirtAlign, Lines); + } + } + } + } + } +} + +static void DrawBackgroundMosaic(int bg, uint8 Zh, uint8 Zl){ + CHECK_SOUND(); + + BG.TileAddress = PPU.BG[bg].NameBase<<1; + + uint32 Tile; + uint16 *SC0, *SC1, *SC2, *SC3; + + SC0=(uint16*)&Memory.VRAM[PPU.BG[bg].SCBase<<1]; + SC1=(PPU.BG[bg].SCSize&1)?SC0+1024:SC0; + if(SC1>=(uint16*)(Memory.VRAM+0x10000)) SC1-=0x8000; + SC2=(PPU.BG[bg].SCSize&2)?SC1+1024:SC0; + if(SC2>=(uint16*)(Memory.VRAM+0x10000)) SC2-=0x8000; + SC3=(PPU.BG[bg].SCSize&1)?SC2+1024:SC2; + if(SC3>=(uint16*)(Memory.VRAM+0x10000)) SC3-=0x8000; + + int Lines; + int OffsetMask = (BG.TileSizeH==16)?0x3ff:0x1ff; + int OffsetShift = (BG.TileSizeV==16)?4:3; + int PixWidth = IPPU.DoubleWidthPixels?2:1; + + void (*DrawPix)(uint32,uint32,uint32,uint32,uint32,uint32); + + int MosaicStart = ((uint32)GFX.StartY-PPU.MosaicStart)%PPU.Mosaic; + for(int clip=0; clipGFX.EndY) Lines=GFX.EndY-Y-MosaicStart+1; + int VirtAlign = (((Y2 + VOffset)&7)>>(IPPU.Interlace?1:0))<<3; + + uint32 TilemapRow = (VOffset+Y2)>>OffsetShift; + BG.InterlaceLine = ((VOffset+Y2)&1)<<3; + uint32 t1, t2; + if(((VOffset+Y2)&8)){ + t1=16; t2=0; + } else { + t1=0; t2=16; + } + uint16 *b1; + uint16 *b2; + if(TilemapRow&0x20) { + b1=SC2; b2=SC3; + } else { + b1=SC0; b2=SC1; + } + b1+=(TilemapRow&0x1f)<<5; + b2+=(TilemapRow&0x1f)<<5; + + uint32 Left = GFX.Clip[bg].Left[clip]; + uint32 Right = GFX.Clip[bg].Right[clip]; + uint32 Offset = Left*PixWidth+(Y+MosaicStart)*GFX.PPL; + uint32 HPos = (HOffset+Left-(Left%PPU.Mosaic))&OffsetMask; + uint32 HTile = HPos>>3; + uint16 *t; + if(BG.TileSizeH==8){ + if(HTile>31) + t=b2+(HTile&0x1f); + else + t=b1+HTile; + } else { + if(HTile>63) + t=b2+((HTile>>1)&0x1f); + else + t=b1+(HTile>>1); + } + + uint32 Width = Right-Left; + uint32 f = 0; + while(LeftWidth) w=Width; + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawPix(Tile, Offset, VirtAlign, HPos&7, w, Lines); + } else { + if(!(Tile&H_FLIP)){ + DrawPix(TILE_PLUS(Tile, (HTile&1)), Offset, VirtAlign, HPos&7, w, Lines); + } else { + DrawPix(TILE_PLUS(Tile, 1-(HTile&1)), Offset, VirtAlign, HPos&7, w, Lines); + } + } + HPos+=PPU.Mosaic; + f+=PPU.Mosaic; + while(f>=8){ + f-=8; + if(BG.TileSizeH==8){ + t++; + if(HTile==31) t=b2; + else if(HTile==63) t=b1; + } else { + t+=HTile&1; + if(HTile==63) t=b2; + else if(HTile==127) t=b1; + } + HTile++; + } + Offset+=w*PixWidth; + Width-=w; + Left+=w; + } + MosaicStart=0; + } + } +} + +static void DrawBackgroundOffset(int bg, uint8 Zh, uint8 Zl, int VOffOff){ + CHECK_SOUND(); + + BG.TileAddress = PPU.BG[bg].NameBase<<1; + + uint32 Tile; + uint16 *SC0, *SC1, *SC2, *SC3; + uint16 *BPS0, *BPS1, *BPS2, *BPS3; + + BPS0=(uint16*)&Memory.VRAM[PPU.BG[2].SCBase<<1]; + BPS1=(PPU.BG[2].SCSize&1)?BPS0+1024:BPS0; + if(BPS1>=(uint16*)(Memory.VRAM+0x10000)) BPS1-=0x8000; + BPS2=(PPU.BG[2].SCSize&2)?BPS1+1024:BPS0; + if(BPS2>=(uint16*)(Memory.VRAM+0x10000)) BPS2-=0x8000; + BPS3=(PPU.BG[2].SCSize&1)?BPS2+1024:BPS2; + if(BPS3>=(uint16*)(Memory.VRAM+0x10000)) BPS3-=0x8000; + + SC0=(uint16*)&Memory.VRAM[PPU.BG[bg].SCBase<<1]; + SC1=(PPU.BG[bg].SCSize&1)?SC0+1024:SC0; + if(SC1>=(uint16*)(Memory.VRAM+0x10000)) SC1-=0x8000; + SC2=(PPU.BG[bg].SCSize&2)?SC1+1024:SC0; + if(SC2>=(uint16*)(Memory.VRAM+0x10000)) SC2-=0x8000; + SC3=(PPU.BG[bg].SCSize&1)?SC2+1024:SC2; + if(SC3>=(uint16*)(Memory.VRAM+0x10000)) SC3-=0x8000; + + int OffsetMask = (BG.TileSizeH==16)?0x3ff:0x1ff; + int OffsetShift = (BG.TileSizeV==16)?4:3; + int Offset2Mask = (BG.OffsetSizeH==16)?0x3ff:0x1ff; + int Offset2Shift = (BG.OffsetSizeV==16)?4:3; + int OffsetEnableMask = 0x2000<>Offset2Shift; + uint32 VOffsetRow = (VOff+VOffOff)>>Offset2Shift; + uint16 *s, *s1, *s2; + if(HOffsetRow&0x20){ + s1=BPS2; s2=BPS3; + } else { + s1=BPS0; s2=BPS1; + } + s1+=(HOffsetRow&0x1f)<<5; + s2+=(HOffsetRow&0x1f)<<5; + s=((VOffsetRow&0x20)?BPS2:BPS0)+((VOffsetRow&0x1f)<<5); + int32 VOffsetOffset = s-s1; + + uint32 Left = GFX.Clip[bg].Left[clip]; + uint32 Right = GFX.Clip[bg].Right[clip]; + uint32 Offset = Left*PixWidth+Y*GFX.PPL; + uint32 LineHOffset = LineData[Y].BG[bg].HOffset; + bool8 left_edge = (Left<(8-(LineHOffset&7))); + uint32 Width = Right-Left; + + while(Left>3; + if(BG.OffsetSizeH==8){ + if(HOffTile>31) + s=s2+(HOffTile&0x1f); + else + s=s1+HOffTile; + } else { + if(HOffTile>63) + s=s2+((HOffTile>>1)&0x1f); + else + s=s1+(HOffTile>>1); + } + uint16 HCellOffset = READ_WORD(s); + uint16 VCellOffset; + if(VOffOff){ + VCellOffset = READ_WORD(s+VOffsetOffset); + } else { + if(HCellOffset&0x8000){ + VCellOffset=HCellOffset; + HCellOffset=0; + } else { + VCellOffset=0; + } + } + if(VCellOffset&OffsetEnableMask){ + VOffset=VCellOffset+1; + } else { + VOffset=LineData[Y].BG[bg].VOffset; + } + if(HCellOffset&OffsetEnableMask){ + HOffset=(HCellOffset&~7)|(LineHOffset&7); + } else { + HOffset=LineHOffset; + } + } + if(IPPU.Interlace) VOffset++; + + int VirtAlign = (((Y2+VOffset)&7)>>(IPPU.Interlace?1:0))<<3; + int TilemapRow=(VOffset+Y2)>>OffsetShift; + BG.InterlaceLine = ((VOffset+Y2)&1)<<3; + uint32 t1, t2; + if(((VOffset+Y2)&8)){ + t1=16; t2=0; + } else { + t1=0; t2=16; + } + uint16 *b1, *b2; + if(TilemapRow&0x20) { + b1=SC2; b2=SC3; + } else { + b1=SC0; b2=SC1; + } + b1+=(TilemapRow&0x1f)<<5; + b2+=(TilemapRow&0x1f)<<5; + + uint32 HPos = (HOffset+Left)&OffsetMask; + uint32 HTile = HPos>>3; + uint16 *t; + if(BG.TileSizeH==8){ + if(HTile>31) + t=b2+(HTile&0x1f); + else + t=b1+HTile; + } else { + if(HTile>63) + t=b2+((HTile>>1)&0x1f); + else + t=b1+(HTile>>1); + } + + uint32 l=HPos&7; + uint32 w=8-l; + if(w>Width) w=Width; + Offset-=l*PixWidth; + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawClippedTile(Tile, Offset, l, w, VirtAlign, 1); + } else { + if(!(Tile&H_FLIP)){ + DrawClippedTile(TILE_PLUS(Tile, (HTile&1)), Offset, l, w, VirtAlign, 1); + } else { + DrawClippedTile(TILE_PLUS(Tile, 1-(HTile&1)), Offset, l, w, VirtAlign, 1); + } + } + Left+=w; + Offset+=8*PixWidth; + Width-=w; + } + } + } +} + +static void DrawBackgroundOffsetMosaic(int bg, uint8 Zh, uint8 Zl, int VOffOff){ + CHECK_SOUND(); + + BG.TileAddress = PPU.BG[bg].NameBase<<1; + + uint32 Tile; + uint16 *SC0, *SC1, *SC2, *SC3; + uint16 *BPS0, *BPS1, *BPS2, *BPS3; + + BPS0=(uint16*)&Memory.VRAM[PPU.BG[2].SCBase<<1]; + BPS1=(PPU.BG[2].SCSize&1)?BPS0+1024:BPS0; + if(BPS1>=(uint16*)(Memory.VRAM+0x10000)) BPS1-=0x8000; + BPS2=(PPU.BG[2].SCSize&2)?BPS1+1024:BPS0; + if(BPS2>=(uint16*)(Memory.VRAM+0x10000)) BPS2-=0x8000; + BPS3=(PPU.BG[2].SCSize&1)?BPS2+1024:BPS2; + if(BPS3>=(uint16*)(Memory.VRAM+0x10000)) BPS3-=0x8000; + + SC0=(uint16*)&Memory.VRAM[PPU.BG[bg].SCBase<<1]; + SC1=(PPU.BG[bg].SCSize&1)?SC0+1024:SC0; + if(SC1>=(uint16*)(Memory.VRAM+0x10000)) SC1-=0x8000; + SC2=(PPU.BG[bg].SCSize&2)?SC1+1024:SC0; + if(SC2>=(uint16*)(Memory.VRAM+0x10000)) SC2-=0x8000; + SC3=(PPU.BG[bg].SCSize&1)?SC2+1024:SC2; + if(SC3>=(uint16*)(Memory.VRAM+0x10000)) SC3-=0x8000; + + int Lines; + int OffsetMask = (BG.TileSizeH==16)?0x3ff:0x1ff; + int OffsetShift = (BG.TileSizeV==16)?4:3; + int Offset2Mask = (BG.OffsetSizeH==16)?0x3ff:0x1ff; + int Offset2Shift = (BG.OffsetSizeV==16)?4:3; + int OffsetEnableMask = 0x2000<GFX.EndY) Lines=GFX.EndY-Y-MosaicStart+1; + + uint32 VOff = LineData[Y].BG[2].VOffset - 1; + uint32 HOff = LineData[Y].BG[2].HOffset; + + uint32 HOffsetRow = VOff>>Offset2Shift; + uint32 VOffsetRow = (VOff+VOffOff)>>Offset2Shift; + uint16 *s, *s1, *s2; + if(HOffsetRow&0x20){ + s1=BPS2; s2=BPS3; + } else { + s1=BPS0; s2=BPS1; + } + s1+=(HOffsetRow&0x1f)<<5; + s2+=(HOffsetRow&0x1f)<<5; + s=((VOffsetRow&0x20)?BPS2:BPS0)+((VOffsetRow&0x1f)<<5); + int32 VOffsetOffset = s-s1; + + uint32 Left = GFX.Clip[bg].Left[clip]; + uint32 Right = GFX.Clip[bg].Right[clip]; + uint32 Offset = Left*PixWidth+(Y+MosaicStart)*GFX.PPL; + uint32 LineHOffset = LineData[Y].BG[bg].HOffset; + bool8 left_edge = (Left<(8-(LineHOffset&7))); + uint32 Width = Right-Left; + + while(Left>3; + if(BG.OffsetSizeH==8){ + if(HOffTile>31) + s=s2+(HOffTile&0x1f); + else + s=s1+HOffTile; + } else { + if(HOffTile>63) + s=s2+((HOffTile>>1)&0x1f); + else + s=s1+(HOffTile>>1); + } + uint16 HCellOffset = READ_WORD(s); + uint16 VCellOffset; + if(VOffOff){ + VCellOffset = READ_WORD(s+VOffsetOffset); + } else { + if(HCellOffset&0x8000){ + VCellOffset=HCellOffset; + HCellOffset=0; + } else { + VCellOffset=0; + } + } + if(VCellOffset&OffsetEnableMask){ + VOffset=VCellOffset+1; + } else { + VOffset=LineData[Y].BG[bg].VOffset; + } + if(HCellOffset&OffsetEnableMask){ + HOffset=(HCellOffset&~7)|(LineHOffset&7); + } else { + HOffset=LineHOffset; + } + } + if(IPPU.Interlace) VOffset++; + + int VirtAlign = (((Y2+VOffset)&7)>>(IPPU.Interlace?1:0))<<3; + int TilemapRow=(VOffset+Y2)>>OffsetShift; + BG.InterlaceLine = ((VOffset+Y2)&1)<<3; + uint32 t1, t2; + if(((VOffset+Y2)&8)){ + t1=16; t2=0; + } else { + t1=0; t2=16; + } + uint16 *b1, *b2; + if(TilemapRow&0x20) { + b1=SC2; b2=SC3; + } else { + b1=SC0; b2=SC1; + } + b1+=(TilemapRow&0x1f)<<5; + b2+=(TilemapRow&0x1f)<<5; + + uint32 HPos = (HOffset+Left-(Left%PPU.Mosaic))&OffsetMask; + uint32 HTile = HPos>>3; + uint16 *t; + if(BG.TileSizeH==8){ + if(HTile>31) + t=b2+(HTile&0x1f); + else + t=b1+HTile; + } else { + if(HTile>63) + t=b2+((HTile>>1)&0x1f); + else + t=b1+(HTile>>1); + } + + uint32 w=PPU.Mosaic-(Left%PPU.Mosaic); + if(w>Width) w=Width; + Tile=READ_WORD(t); + GFX.Z1=GFX.Z2=(Tile&0x2000)?Zh:Zl; + if(BG.TileSizeV==16) + Tile=TILE_PLUS(Tile, ((Tile&V_FLIP)?t2:t1)); + if(BG.TileSizeH==8){ + DrawPix(Tile, Offset, VirtAlign, HPos&7, w, Lines); + } else { + if(!(Tile&H_FLIP)){ + DrawPix(TILE_PLUS(Tile, (HTile&1)), Offset, VirtAlign, HPos&7, w, Lines); + } else if(!(Tile&V_FLIP)){ + DrawPix(TILE_PLUS(Tile, 1-(HTile&1)), Offset, VirtAlign, HPos&7, w, Lines); + } + } + Left+=w; + Offset+=w*PixWidth; + Width-=w; + } + MosaicStart=0; + } + } +} + +static inline void DrawBackgroundMode7(int bg, void (*DrawMath)(uint32,uint32,int), void (*DrawNomath)(uint32,uint32,int), int D){ + CHECK_SOUND(); + + for(int clip=0; clip1)) \ + DrawBackgroundOffsetMosaic(n, D+Zh, D+Zl, voffoff); \ + else \ + DrawBackgroundOffset(n, D+Zh, D+Zl, voffoff); \ + } else { \ + if(PPU.BGMosaic[n] && (hires || PPU.Mosaic>1)) \ + DrawBackgroundMosaic(n, D+Zh, D+Zl); \ + else \ + DrawBackground(n, D+Zh, D+Zl); \ + } \ + } + switch(PPU.BGMode){ + case 0: + DO_BG(0, 0, 2, FALSE, FALSE, 15, 11, 0); + DO_BG(1, 32, 2, FALSE, FALSE, 14, 10, 0); + DO_BG(2, 64, 2, FALSE, FALSE, 7, 3, 0); + DO_BG(3, 96, 2, FALSE, FALSE, 6, 2, 0); + break; + case 1: + DO_BG(0, 0, 4, FALSE, FALSE, 15, 11, 0); + DO_BG(1, 0, 4, FALSE, FALSE, 14, 10, 0); + DO_BG(2, 0, 2, FALSE, FALSE, (PPU.BG3Priority?17:7), 3, 0); + break; + case 2: + DO_BG(0, 0, 4, FALSE, TRUE, 15, 7, 8); + DO_BG(1, 0, 4, FALSE, TRUE, 11, 3, 8); + break; + case 3: + DO_BG(0, 0, 8, FALSE, FALSE, 15, 7, 0); + DO_BG(1, 0, 4, FALSE, FALSE, 11, 3, 0); + break; + case 4: + DO_BG(0, 0, 8, FALSE, TRUE, 15, 7, 0); + DO_BG(1, 0, 2, FALSE, TRUE, 11, 3, 0); + break; + case 5: + DO_BG(0, 0, 4, TRUE, FALSE, 15, 7, 0); + DO_BG(1, 0, 2, TRUE, FALSE, 11, 3, 0); + break; + case 6: + DO_BG(0, 0, 4, TRUE, TRUE, 15, 7, 8); + break; + case 7: + if(BGActive&0x01){ + BG.EnableMath = !sub && (Memory.FillRAM[0x2131]&1); + DrawBackgroundMode7(0, GFX.DrawMode7BG1Math, GFX.DrawMode7BG1Nomath,D); + } + if((Memory.FillRAM[0x2133]&0x40) && (BGActive&0x02)){ + BG.EnableMath = !sub && (Memory.FillRAM[0x2131]&2); + DrawBackgroundMode7(1, GFX.DrawMode7BG2Math, GFX.DrawMode7BG2Nomath,D); + } + break; + } +#undef DO_BG + + BG.EnableMath = !sub && (Memory.FillRAM[0x2131]&0x20); + DrawBackdrop(); +} + + +void S9xUpdateScreen() { + if(IPPU.OBJChanged) S9xSetupOBJ(); + // XXX: Check ForceBlank? Or anything else? + PPU.RangeTimeOver |= GFX.OBJLines[GFX.EndY].RTOFlags; + + GFX.StartY = IPPU.PreviousLine; + if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight) + GFX.EndY = PPU.ScreenHeight - 1; + + if(!PPU.ForcedBlanking){ + /* If force blank, may as well completely skip all this. We only did + * the OBJ because (AFAWK) the RTO flags are updated even during + * force-blank */ + + if(PPU.RecomputeClipWindows) { + ComputeClipWindows(); + PPU.RecomputeClipWindows=FALSE; + } + + if (Settings.SupportHiRes){ + if(!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires || IPPU.Interlace || IPPU.InterlaceOBJ)){ +#if defined (USE_GLIDE) || defined (USE_OPENGL) + if ( +#ifdef USE_GLIDE + (Settings.GlideEnable && GFX.RealPPL == 256) || +#endif +#ifdef USE_OPENGL + (Settings.OpenGLEnable && GFX.RealPPL == 256) || +#endif + 0) + { + // Have to back out of the speed up hack where the low res. + // SNES image was rendered into a 256x239 sized buffer, + // ignoring the true, larger size of the buffer. + GFX.RealPPL = GFX.Pitch>>1; + for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--){ + register uint16 *p = GFX.Screen + y * GFX.PPL + 255; + register uint16 *q = GFX.Screen + y * GFX.RealPPL + 510; + for (register int x = 255; x >= 0; x--, p--, q -= 2) + *q = *(q + 1) = *p; + } + GFX.PPL = GFX.RealPPL; // = GFX.Pitch>>1 above + } else +#endif + { + // Have to back out of the regular speed hack + for (register uint32 y = 0; y < GFX.StartY; y++) + { + register uint16 *p = GFX.Screen + y * GFX.PPL + 255; + register uint16 *q = GFX.Screen + y * GFX.PPL + 510; + + for (register int x = 255; x >= 0; x--, p--, q -= 2) + *q = *(q + 1) = *p; + } + } + IPPU.DoubleWidthPixels = TRUE; + IPPU.RenderedScreenWidth = 512; + } + if(!IPPU.DoubleHeightPixels && (IPPU.Interlace || IPPU.InterlaceOBJ)){ + IPPU.DoubleHeightPixels = TRUE; + GFX.PPL=GFX.RealPPL<<1; + IPPU.RenderedScreenHeight=PPU.ScreenHeight<<1; + GFX.DoInterlace=2; + for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--){ + memmove (GFX.Screen + y * GFX.PPL, + GFX.Screen + y * GFX.RealPPL, + IPPU.RenderedScreenWidth*sizeof(uint16)); + } + } + } + + if((Memory.FillRAM[0x2130]&0x30)!=0x30 && (Memory.FillRAM[0x2131]&0x3f)) + GFX.FixedColour = BUILD_PIXEL(IPPU.XB[PPU.FixedColourRed], + IPPU.XB[PPU.FixedColourGreen], + IPPU.XB[PPU.FixedColourBlue]); + + if(PPU.BGMode==5 || PPU.BGMode==6 || IPPU.PseudoHires || + ((Memory.FillRAM[0x2130]&0x30)!=0x30 && (Memory.FillRAM[0x2130]&2) && + (Memory.FillRAM[0x2131]&0x3f) && (Memory.FillRAM[0x212d]&0x1f))){ + /* If hires (Mode 5/6 or pseudo-hires) or math is to be done + * involving the subscreen, then we need to render the subscreen... + */ + RenderScreen(TRUE); + } + RenderScreen(FALSE); + } else { + GFX.S = GFX.Screen+GFX.StartY*GFX.PPL; + if(GFX.DoInterlace && GFX.InterlaceFrame) GFX.S+=GFX.RealPPL; + uint16 black=BUILD_PIXEL(0,0,0); + for(uint32 l=GFX.StartY; l<=GFX.EndY; l++, GFX.S+=GFX.PPL){ + for(int x=0; x> 4) * font_height; + int offset = ((c - 32) & 15) * font_width; + int h, w, rws; + rws = Settings.OpenGLEnable ? IPPU.RenderedScreenWidth : GFX.RealPPL; + for(h=0; h= max_chars || (unsigned char) string [i] < 32) { + Screen -= (font_width - 1) * max_chars; + Screen += font_height * GFX.RealPPL; + if(Screen >= GFX.Screen+GFX.RealPPL*IPPU.RenderedScreenHeight) + break; + char_count -= max_chars; + } + if((unsigned char) string[i]<32) continue; + DisplayChar(Screen, string [i]); + Screen += font_width-1; + } +} + +#include "crosshairs.h" + +static uint16 get_crosshair_color(uint8 color){ + switch(color&15){ + case 0: return BUILD_PIXEL(0,0,0); // transparent, shouldn't be used + case 1: return BUILD_PIXEL(0,0,0); // Black + case 2: return BUILD_PIXEL(8,8,8); // 25Grey + case 3: return BUILD_PIXEL(16,16,16); // 50Grey + case 4: return BUILD_PIXEL(23,23,23); // 75Grey + case 5: return BUILD_PIXEL(31,31,31); // White + case 6: return BUILD_PIXEL(31,0,0); // Red + case 7: return BUILD_PIXEL(31,16,0); // Orange + case 8: return BUILD_PIXEL(31,31,0); // Yellow + case 9: return BUILD_PIXEL(0,31,0); // Green + case 10: return BUILD_PIXEL(0,31,31); // Cyan + case 11: return BUILD_PIXEL(0,23,31); // Sky + case 12: return BUILD_PIXEL(0,0,31); // Blue + case 13: return BUILD_PIXEL(23,0,31); // Violet + case 14: return BUILD_PIXEL(31,0,31); // MagicPink + case 15: return BUILD_PIXEL(31,0,16); // Purple + } + return 0; // stupid compiler warning +} + +void S9xDrawCrosshair(const char *crosshair, uint8 fgcolor, uint8 bgcolor, int16 x, int16 y) { + int16 r, rx=1, c, cx=1, W, H, rws; + + W=256; H=PPU.ScreenHeight; + x-=7; y-=7; + if(IPPU.DoubleWidthPixels){ cx=2; x*=2; W*=2; } + if(IPPU.DoubleHeightPixels){ rx=2; y*=2; H*=2; } + if(crosshair==NULL) return; + uint16 fg, bg; + fg=get_crosshair_color(fgcolor); + bg=get_crosshair_color(bgcolor); + uint16 *s = GFX.Screen + y * GFX.RealPPL + x; + rws = Settings.OpenGLEnable ? IPPU.RenderedScreenWidth : GFX.RealPPL; + for(r=0; r<15*rx; r++, s+=rws-15*cx) { + if(y+r<0){ s+=15*cx; continue; } + if(y+r>=H) break; + for(c=0; c<15*cx; c++, s++) { + if(x+c<0) continue; + if(x+c>=W){ s+=15*cx-c; break; } + uint8 p = crosshair[(r/rx)*15+(c/cx)]; + + if(p == '#' && fgcolor) { + *s=(fgcolor&0x10)?COLOR_ADD1_2(fg,*s):fg; + } else if(p == '.' && bgcolor) { + *s=(bgcolor&0x10)?COLOR_ADD1_2(*s,bg):bg; + } + } + } +} + + +#ifdef GFX_MULTI_FORMAT + +#define _BUILD_PIXEL(F) \ +uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \ +{ \ + return (BUILD_PIXEL_##F(R,G,B)); \ +}\ +uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \ +{ \ + return (BUILD_PIXEL2_##F(R,G,B)); \ +} \ +void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \ +{ \ + DECOMPOSE_PIXEL_##F(pixel,R,G,B); \ +} + +_BUILD_PIXEL(RGB565) +_BUILD_PIXEL(RGB555) +_BUILD_PIXEL(BGR565) +_BUILD_PIXEL(BGR555) +_BUILD_PIXEL(GBR565) +_BUILD_PIXEL(GBR555) +_BUILD_PIXEL(RGB5551) + +#define _BUILD_SETUP(F) \ +GFX.BuildPixel = BuildPixel##F; \ +GFX.BuildPixel2 = BuildPixel2##F; \ +GFX.DecomposePixel = DecomposePixel##F; \ +RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \ +GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \ +BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \ +RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \ +GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \ +BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \ +MAX_RED = MAX_RED_##F; \ +MAX_GREEN = MAX_GREEN_##F; \ +MAX_BLUE = MAX_BLUE_##F; \ +GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \ +SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \ +RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \ + GREEN_LOW_BIT_MASK_##F | \ + BLUE_LOW_BIT_MASK_##F); \ +RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \ + GREEN_HI_BIT_MASK_##F | \ + BLUE_HI_BIT_MASK_##F); \ +RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \ + GREEN_HI_BIT_MASK_##F | \ + BLUE_HI_BIT_MASK_##F) << 1); \ +RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \ +FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \ +SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \ +THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \ +ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \ +FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \ +TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \ +HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \ + ~TWO_LOW_BITS_MASK ) >> 2); + +bool8 S9xSetRenderPixelFormat (int format) +{ + extern uint32 current_graphic_format; + + current_graphic_format = format; + + switch (format) + { + case RGB565: + _BUILD_SETUP(RGB565) + return (TRUE); + case RGB555: + _BUILD_SETUP(RGB555) + return (TRUE); + case BGR565: + _BUILD_SETUP(BGR565) + return (TRUE); + case BGR555: + _BUILD_SETUP(BGR555) + return (TRUE); + case GBR565: + _BUILD_SETUP(GBR565) + return (TRUE); + case GBR555: + _BUILD_SETUP(GBR555) + return (TRUE); + case RGB5551: + _BUILD_SETUP(RGB5551) + return (TRUE); + default: + break; + } + return (FALSE); +} +#endif + diff --git a/source/snes9x/gfx.h b/source/snes9x/gfx.h new file mode 100644 index 0000000..980ecd6 --- /dev/null +++ b/source/snes9x/gfx.h @@ -0,0 +1,361 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _GFX_H_ +#define _GFX_H_ + +#include "port.h" +#include "snes9x.h" + +struct SGFX{ + // Initialize these variables + uint16 *Screen; + uint16 *SubScreen; + uint8 *ZBuffer; + uint8 *SubZBuffer; + uint32 Pitch; + uint32 ScreenSize; + + uint16 *S; + uint8 *DB; + + // Setup in call to S9xGraphicsInit() + uint16 *X2; + uint16 *ZERO_OR_X2; + uint16 *ZERO; + + uint32 RealPPL; // True PPL of Screen buffer. + uint32 PPL; // Number of pixels on each of Screen buffer + uint32 LinesPerTile; // number of lines in 1 tile (4 or 8 due to interlace) + uint16 *ScreenColors; // Screen colors for rendering main + uint16 *RealScreenColors; // Screen colors, ignoring color window clipping + uint8 Z1; // Depth for comparison + uint8 Z2; // Depth to save + uint32 FixedColour; + const char *InfoString; + uint32 InfoStringTimeout; + uint8 DoInterlace; + uint8 InterlaceFrame; + uint32 StartY; + uint32 EndY; + struct ClipData *Clip; + bool8 ClipColors; + uint8 OBJWidths[128]; + uint8 OBJVisibleTiles[128]; + struct { + uint8 RTOFlags; + int16 Tiles; + struct { + int8 Sprite; + uint8 Line; + } OBJ[32]; + } OBJLines [SNES_HEIGHT_EXTENDED]; + +#ifdef GFX_MULTI_FORMAT + uint32 PixelFormat; + uint32 (*BuildPixel) (uint32 R, uint32 G, uint32 B); + uint32 (*BuildPixel2) (uint32 R, uint32 G, uint32 B); + void (*DecomposePixel) (uint32 Pixel, uint32 &R, uint32 &G, uint32 &B); +#endif + + void (*DrawBackdropMath)(uint32,uint32,uint32); + void (*DrawBackdropNomath)(uint32,uint32,uint32); + void (*DrawTileMath)(uint32,uint32,uint32,uint32); + void (*DrawTileNomath)(uint32,uint32,uint32,uint32); + void (*DrawClippedTileMath)(uint32,uint32,uint32,uint32,uint32,uint32); + void (*DrawClippedTileNomath)(uint32,uint32,uint32,uint32,uint32,uint32); + void (*DrawMosaicPixelMath)(uint32,uint32,uint32,uint32,uint32,uint32); + void (*DrawMosaicPixelNomath)(uint32,uint32,uint32,uint32,uint32,uint32); + void (*DrawMode7BG1Math)(uint32,uint32,int); + void (*DrawMode7BG1Nomath)(uint32,uint32,int); + void (*DrawMode7BG2Math)(uint32,uint32,int); + void (*DrawMode7BG2Nomath)(uint32,uint32,int); +}; + +struct SLineData { + struct { + uint16 VOffset; + uint16 HOffset; + } BG [4]; +}; + +#define H_FLIP 0x4000 +#define V_FLIP 0x8000 +#define BLANK_TILE 2 + +struct SBG { + uint8 (*ConvertTile)(uint8 *,uint32,uint32); + uint8 (*ConvertTileFlip)(uint8 *,uint32,uint32); + + uint32 TileSizeH; + uint32 TileSizeV; + uint32 OffsetSizeH; + uint32 OffsetSizeV; + uint32 TileShift; + uint32 TileAddress; + uint32 NameSelect; + uint32 SCBase; + + uint32 StartPalette; + uint32 PaletteShift; + uint32 PaletteMask; + uint8 EnableMath; + uint8 InterlaceLine; + + uint8 *Buffer, *BufferFlip; + uint8 *Buffered, *BufferedFlip; + bool8 DirectColourMode; +}; + +struct SLineMatrixData +{ + short MatrixA; + short MatrixB; + short MatrixC; + short MatrixD; + short CentreX; + short CentreY; + short M7HOFS; + short M7VOFS; +}; + +extern SBG BG; +extern uint16 BlackColourMap [256]; +extern uint16 DirectColourMaps [8][256]; + +extern uint8 add32_32 [32][32]; +extern uint8 add32_32_half [32][32]; +extern uint8 sub32_32 [32][32]; +extern uint8 sub32_32_half [32][32]; +extern uint8 mul_brightness [16][32]; + +// Could use BSWAP instruction on Intel port... +#define SWAP_DWORD(dw) dw = ((dw & 0xff) << 24) | ((dw & 0xff00) << 8) | \ + ((dw & 0xff0000) >> 8) | ((dw & 0xff000000) >> 24) + +#define SUB_SCREEN_DEPTH 0 +#define MAIN_SCREEN_DEPTH 32 + +#if defined(OLD_COLOUR_BLENDING) +#define COLOR_ADD(C1, C2) \ +GFX.X2 [((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \ + ((C1) & (C2) & RGB_LOW_BITS_MASK)] +#else +#define COLOR_ADD(C1, C2) \ +(GFX.X2 [((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \ + ((C1) & (C2) & RGB_LOW_BITS_MASK)] | \ + (((C1) ^ (C2)) & RGB_LOW_BITS_MASK)) +#endif + +#define COLOR_ADD1_2(C1, C2) \ +(((((C1) & RGB_REMOVE_LOW_BITS_MASK) + \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1) + \ + ((C1) & (C2) & RGB_LOW_BITS_MASK) | ALPHA_BITS_MASK) + +#if defined(OLD_COLOUR_BLENDING) +#define COLOR_SUB(C1, C2) \ +GFX.ZERO_OR_X2 [(((C1) | RGB_HI_BITS_MASKx2) - \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1] +#elif !defined(NEW_COLOUR_BLENDING) +#define COLOR_SUB(C1, C2) \ +(GFX.ZERO_OR_X2 [(((C1) | RGB_HI_BITS_MASKx2) - \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1] + \ +((C1) & RGB_LOW_BITS_MASK) - ((C2) & RGB_LOW_BITS_MASK)) +#else +inline uint16 COLOR_SUB(uint16, uint16); + +inline uint16 COLOR_SUB(uint16 C1, uint16 C2) +{ + uint16 mC1, mC2, v = 0; + + mC1 = C1 & FIRST_COLOR_MASK; + mC2 = C2 & FIRST_COLOR_MASK; + if (mC1 > mC2) v += (mC1 - mC2); + + mC1 = C1 & SECOND_COLOR_MASK; + mC2 = C2 & SECOND_COLOR_MASK; + if (mC1 > mC2) v += (mC1 - mC2); + + mC1 = C1 & THIRD_COLOR_MASK; + mC2 = C2 & THIRD_COLOR_MASK; + if (mC1 > mC2) v += (mC1 - mC2); + + return v; +} +#endif + +#define COLOR_SUB1_2(C1, C2) \ +GFX.ZERO [(((C1) | RGB_HI_BITS_MASKx2) - \ + ((C2) & RGB_REMOVE_LOW_BITS_MASK)) >> 1] + +START_EXTERN_C +void S9xStartScreenRefresh (); +void S9xDrawScanLine (uint8 Line); +void S9xEndScreenRefresh (); +void S9xSetupOBJ (); +void S9xUpdateScreen (); +void RenderLine (uint8 line); +void S9xBuildDirectColourMaps (); + +// External port interface which must be implemented or initialised for each +// port. +extern struct SGFX GFX; + +bool8 S9xGraphicsInit (); +void S9xGraphicsDeinit(); +bool8 S9xInitUpdate (void); +bool8 S9xDeinitUpdate (int Width, int Height); +void S9xSetPalette (); +void S9xSyncSpeed (); + +#ifdef GFX_MULTI_FORMAT +bool8 S9xSetRenderPixelFormat (int format); +#endif + +END_EXTERN_C + +#endif + diff --git a/source/snes9x/globals.cpp b/source/snes9x/globals.cpp new file mode 100644 index 0000000..6e9217c --- /dev/null +++ b/source/snes9x/globals.cpp @@ -0,0 +1,380 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" +#include "dsp1.h" +#include "missing.h" +#include "cpuexec.h" +#include "debug.h" +#include "apu.h" +#include "dma.h" +#include "fxemu.h" +#include "gfx.h" +#include "soundux.h" + +#ifndef NGC +#include "cheats.h" +#endif + +#include "sa1.h" +#include "bsx.h" + +#ifdef NETPLAY_SUPPORT +#include "netplay.h" +#endif + +#include "spc7110.h" + +START_EXTERN_C +char String[513]; + +struct Missing missing; + +struct SICPU ICPU; + +struct SCPUState CPU; + +struct STimings Timings; + +struct SRegisters Registers; + +struct SAPU APU; + +struct SIAPU IAPU; + +struct SAPURegisters APURegisters; + +struct SSettings Settings; + +struct SDSP1 DSP1; + +struct SSA1Registers SA1Registers; + +struct SSA1 SA1; + +struct SBSX BSX; + +SSoundData SoundData; + +SnesModel M1SNES={1,3,2}; +SnesModel M2SNES={2,4,3}; +SnesModel* Model=&M1SNES; + + +uint8 *SRAM = NULL; +uint8 *ROM = NULL; +uint8 *RegRAM = NULL; + +CMemory Memory; + +struct SSNESGameFixes SNESGameFixes; + +unsigned char OpenBus = 0; + + +END_EXTERN_C + +#ifndef ZSNES_FX +struct FxInit_s SuperFX; +#else +START_EXTERN_C +uint8 *SFXPlotTable = NULL; +END_EXTERN_C +#endif + +struct SPPU PPU; +struct InternalPPU IPPU; + +struct SDMA DMA[8]; + +uint8 *HDMAMemPointers [8]; +uint8 *HDMABasePointers [8]; + +struct SBG BG; + +struct SGFX GFX; +struct SLineData LineData[240]; +struct SLineMatrixData LineMatrixData [240]; + +#ifdef GFX_MULTI_FORMAT + +uint32 RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_RGB565; +uint32 GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_RGB565; +uint32 BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_RGB565; +uint32 RED_HI_BIT_MASK = RED_HI_BIT_MASK_RGB565; +uint32 GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_RGB565; +uint32 BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_RGB565; +uint32 MAX_RED = MAX_RED_RGB565; +uint32 MAX_GREEN = MAX_GREEN_RGB565; +uint32 MAX_BLUE = MAX_BLUE_RGB565; +uint32 SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_RGB565; +uint32 GREEN_HI_BIT = (MAX_GREEN_RGB565 + 1) >> 1; +uint32 RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_RGB565 | + GREEN_LOW_BIT_MASK_RGB565 | + BLUE_LOW_BIT_MASK_RGB565); +uint32 RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_RGB565 | + GREEN_HI_BIT_MASK_RGB565 | + BLUE_HI_BIT_MASK_RGB565); +uint32 RGB_HI_BITS_MASKx2 = (RED_HI_BIT_MASK_RGB565 | + GREEN_HI_BIT_MASK_RGB565 | + BLUE_HI_BIT_MASK_RGB565) << 1; +uint32 RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; +uint32 FIRST_COLOR_MASK = FIRST_COLOR_MASK_RGB565; +uint32 SECOND_COLOR_MASK = SECOND_COLOR_MASK_RGB565; +uint32 THIRD_COLOR_MASK = THIRD_COLOR_MASK_RGB565; +uint32 ALPHA_BITS_MASK = ALPHA_BITS_MASK_RGB565; +uint32 FIRST_THIRD_COLOR_MASK = 0; +uint32 TWO_LOW_BITS_MASK = 0; +uint32 HIGH_BITS_SHIFTED_TWO_MASK = 0; + +uint32 current_graphic_format = RGB565; +#endif + +uint8 GetBank = 0; + +#ifndef NGC +struct SCheatData Cheat; +#endif + +volatile SoundStatus so; + +int32 Loop[16]; +int32 Echo[24000]; +int32 FilterTaps[8]; +int32 MixBuffer[SOUND_BUFFER_SIZE]; +int32 EchoBuffer[SOUND_BUFFER_SIZE]; +int32 DummyEchoBuffer[SOUND_BUFFER_SIZE]; +uint32 FIRIndex = 0; + +uint16 SignExtend [2] = { + 0x00, 0xff00 +}; + +//modified per anomie Mode 5 findings +int HDMA_ModeByteCounts [8] = { + 1, 2, 2, 4, 4, 4, 2, 4 +}; + +uint16 BlackColourMap [256]; +uint16 DirectColourMaps [8][256]; + +uint32 HeadMask [4] = { +#ifdef LSB_FIRST + 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000 +#else + 0xffffffff, 0x00ffffff, 0x0000ffff, 0x000000ff +#endif +}; + +uint32 TailMask [5] = { +#ifdef LSB_FIRST + 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff +#else + 0x00000000, 0xff000000, 0xffff0000, 0xffffff00, 0xffffffff +#endif +}; + +START_EXTERN_C +uint8 APUROM [64] = +{ + 0xCD,0xEF,0xBD,0xE8,0x00,0xC6,0x1D,0xD0,0xFC,0x8F,0xAA,0xF4,0x8F, + 0xBB,0xF5,0x78,0xCC,0xF4,0xD0,0xFB,0x2F,0x19,0xEB,0xF4,0xD0,0xFC, + 0x7E,0xF4,0xD0,0x0B,0xE4,0xF5,0xCB,0xF4,0xD7,0x00,0xFC,0xD0,0xF3, + 0xAB,0x01,0x10,0xEF,0x7E,0xF4,0x10,0xEB,0xBA,0xF6,0xDA,0x00,0xBA, + 0xF4,0xC4,0xF4,0xDD,0x5D,0xD0,0xDB,0x1F,0x00,0x00,0xC0,0xFF +}; + +#ifdef NETPLAY_SUPPORT +struct SNetPlay NetPlay; +#endif + +// Raw SPC700 instruction cycle lengths +int32 S9xAPUCycleLengths [256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 00 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 6, 8, + /* 10 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 4, 6, + /* 20 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 5, 4, + /* 30 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 3, 8, + /* 40 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 6, 6, + /* 50 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 4, 5, 2, 2, 4, 3, + /* 60 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 5, 5, + /* 70 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 6, + /* 80 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 2, 4, 5, + /* 90 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2,12, 5, + /* A0 */ 3, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 2, 4, 4, + /* B0 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 4, + /* C0 */ 3, 8, 4, 5, 4, 5, 4, 7, 2, 5, 6, 4, 5, 2, 4, 9, + /* D0 */ 2, 8, 4, 5, 5, 6, 6, 7, 4, 5, 5, 5, 2, 2, 6, 3, + /* E0 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 4, 5, 3, 4, 3, 4, 3, + /* F0 */ 2, 8, 4, 5, 4, 5, 5, 6, 3, 4, 5, 4, 2, 2, 4, 3 +}; + +// Actual data used by CPU emulation, will be scaled by APUReset routine +// to be relative to the 65c816 instruction lengths. +int32 S9xAPUCycles [256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 00 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 6, 8, + /* 10 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 4, 6, + /* 20 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 4, 5, 4, + /* 30 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 6, 5, 2, 2, 3, 8, + /* 40 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 6, 6, + /* 50 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 4, 5, 2, 2, 4, 3, + /* 60 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 4, 5, 5, + /* 70 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 6, + /* 80 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 6, 5, 4, 5, 2, 4, 5, + /* 90 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2,12, 5, + /* A0 */ 3, 8, 4, 5, 3, 4, 3, 6, 2, 6, 4, 4, 5, 2, 4, 4, + /* B0 */ 2, 8, 4, 5, 4, 5, 5, 6, 5, 5, 5, 5, 2, 2, 3, 4, + /* C0 */ 3, 8, 4, 5, 4, 5, 4, 7, 2, 5, 6, 4, 5, 2, 4, 9, + /* D0 */ 2, 8, 4, 5, 5, 6, 6, 7, 4, 5, 5, 5, 2, 2, 6, 3, + /* E0 */ 2, 8, 4, 5, 3, 4, 3, 6, 2, 4, 5, 3, 4, 3, 4, 3, + /* F0 */ 2, 8, 4, 5, 4, 5, 5, 6, 3, 4, 5, 4, 2, 2, 4, 3 +}; + +END_EXTERN_C + diff --git a/source/snes9x/language.h b/source/snes9x/language.h new file mode 100644 index 0000000..91aa32f --- /dev/null +++ b/source/snes9x/language.h @@ -0,0 +1,163 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +/* This file is for core emulator messages. Use a port-specific file for * + * GUI strings and the like. Thank you. */ + +/* Movie Messages */ + +#define MOVIE_INFO_REPLAY "Movie replay" +#define MOVIE_INFO_RECORD "Movie record" +#define MOVIE_INFO_RERECORD "Movie re-record" +#define MOVIE_INFO_REWIND "Movie rewind" +#define MOVIE_INFO_STOP "Movie stop" +#define MOVIE_INFO_END "Movie end" +#define MOVIE_INFO_RECORDING_ENABLED "Recording enabled" +#define MOVIE_INFO_RECORDING_DISABLED "Recording disabled" +#define MOVIE_ERR_SNAPSHOT_WRONG_MOVIE "Snapshot not from this movie" +#define MOVIE_ERR_SNAPSHOT_NOT_MOVIE "Not a movie snapshot" +#define MOVIE_ERR_COULD_NOT_OPEN "Could not open movie file." +#define MOVIE_ERR_NOT_FOUND "File not found." +#define MOVIE_ERR_WRONG_FORMAT "File is wrong format." +#define MOVIE_ERR_WRONG_VERSION "File is wrong version." diff --git a/source/snes9x/memmap.cpp b/source/snes9x/memmap.cpp new file mode 100644 index 0000000..b389e9d --- /dev/null +++ b/source/snes9x/memmap.cpp @@ -0,0 +1,4558 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include + +#ifdef __linux +#include +#endif + +#ifdef JMA_SUPPORT +#include "jma/s9x-jma.h" +#endif + +#include "snes9x.h" +#include "memmap.h" +#include "cpuexec.h" +#include "ppu.h" +#include "display.h" + +#ifndef NGC +#include "cheats.h" +#endif + +#include "apu.h" +#include "sa1.h" +#include "dsp1.h" +#include "srtc.h" +#include "sdd1.h" +#include "spc7110.h" +#include "seta.h" +#include "bsx.h" + +#ifndef NGC +#include "reader.h" +#else +#include +#include "aram.h" /*** Nintendo GameCube ARAM loader. + FileLoader requires that the ROM is preloaded in ARAM first + ***/ +extern unsigned long ARAM_ROMSIZE; +extern int hasloaded; +#endif + +#include "controls.h" + +#ifdef UNZIP_SUPPORT +#include "unzip.h" +#endif + +#ifdef __W32_HEAP +#include +#endif + +#ifndef ZSNES_FX +#include "fxemu.h" +extern struct FxInit_s SuperFX; +#else +START_EXTERN_C +extern uint8 *SFXPlotTable; +END_EXTERN_C +#endif + +#ifndef SET_UI_COLOR +#define SET_UI_COLOR(r,g,b) ; +#endif + +//you would think everyone would have these +//since they're so useful. +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static int retry_count=0; +void S9xDeinterleaveType2 (bool8 reset=TRUE); +inline uint32 caCRC32(uint8 *array, uint32 size, register uint32 crc32 = 0xFFFFFFFF); + +extern char *rom_filename; + +const uint32 crc32Table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + + +void S9xDeinterleaveType1(int TotalFileSize, uint8 * base) +{ + if(Settings.DisplayColor==0xffff) + { + Settings.DisplayColor=BUILD_PIXEL(0,31,0); + SET_UI_COLOR(0,255,0); + } + + int i; + int nblocks = TotalFileSize >> 16; + uint8 blocks [256]; + for (i = 0; i < nblocks; i++) + { + blocks [i * 2] = i + nblocks; + blocks [i * 2 + 1] = i; + } + uint8 *tmp = (uint8 *) malloc (0x8000); + if (tmp) + { + for (i = 0; i < nblocks * 2; i++) + { + for (int j = i; j < nblocks * 2; j++) + { + if (blocks [j] == i) + { + memmove (tmp, &base [blocks [j] * 0x8000], 0x8000); + memmove (&base [blocks [j] * 0x8000], + &base [blocks [i] * 0x8000], 0x8000); + memmove (&base [blocks [i] * 0x8000], tmp, 0x8000); + uint8 b = blocks [j]; + blocks [j] = blocks [i]; + blocks [i] = b; + break; + } + } + } + free ((char *) tmp); + } +} + +void S9xDeinterleaveGD24(int TotalFileSize, uint8 * base) +{ + + if(TotalFileSize!=0x300000) + return; + + if(Settings.DisplayColor==0xffff) + { + Settings.DisplayColor=BUILD_PIXEL(0,31,31); + SET_UI_COLOR(0,255,255); + } + + uint8 *tmp = (uint8 *) malloc (0x80000); + if (tmp) + { + memmove(tmp, &base[0x180000], 0x80000); + memmove(&base[0x180000], &base[0x200000], 0x80000); + memmove(&base[0x200000], &base[0x280000], 0x80000); + memmove(&base[0x280000], tmp, 0x80000); + free ((char *) tmp); + + S9xDeinterleaveType1(TotalFileSize, base); + } +} + +bool8 CMemory::AllASCII (uint8 *b, int size) +{ + for (int i = 0; i < size; i++) + { + if (b[i] < 32 || b[i] > 126) + return (FALSE); + } + return (TRUE); +} + +int CMemory::ScoreHiROM (bool8 skip_header, int32 romoff) +{ + int score = 0; + int o = skip_header ? 0xff00 + 0x200 : 0xff00; + + o+=romoff; + + if(Memory.ROM [o + 0xd5] & 0x1) + score+=2; + + //Mode23 is SA-1 + if(Memory.ROM [o + 0xd5] == 0x23) + score-=2; + + if(Memory.ROM [o+0xd4] == 0x20) + score +=2; + + if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) + { + score += 2; + if(0!=(Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8))) + score++; + } + + if (Memory.ROM [o + 0xda] == 0x33) + score += 2; + if ((Memory.ROM [o + 0xd5] & 0xf) < 4) + score += 2; + if (!(Memory.ROM [o + 0xfd] & 0x80)) + score -= 6; + if ((Memory.ROM [o + 0xfc]|(Memory.ROM [o + 0xfd]<<8))>0xFFB0) + score -= 2; //reduced after looking at a scan by Cowering + if (CalculatedSize > 1024 * 1024 * 3) + score += 4; + if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48) + score -= 1; + if (!AllASCII (&Memory.ROM [o + 0xb0], 6)) + score -= 1; + if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1)) + score -= 1; + + return (score); +} + +int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff) +{ + int score = 0; + int o = skip_header ? 0x7f00 + 0x200 : 0x7f00; + + o+=romoff; + + if(!(Memory.ROM [o + 0xd5] & 0x1)) + score+=3; + + //Mode23 is SA-1 + if(Memory.ROM [o + 0xd5] == 0x23) + score+=2; + + if ((Memory.ROM [o + 0xdc] + (Memory.ROM [o + 0xdd] << 8) + + Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8)) == 0xffff) + { + score += 2; + if(0!=(Memory.ROM [o + 0xde] + (Memory.ROM [o + 0xdf] << 8))) + score++; + } + + if (Memory.ROM [o + 0xda] == 0x33) + score += 2; + if ((Memory.ROM [o + 0xd5] & 0xf) < 4) + score += 2; + if (CalculatedSize <= 1024 * 1024 * 16) + score += 2; + if (!(Memory.ROM [o + 0xfd] & 0x80)) + score -= 6; + if ((Memory.ROM [o + 0xfc]|(Memory.ROM [o + 0xfd]<<8))>0xFFB0) + score -= 2;//reduced per Cowering suggestion + if ((1 << (Memory.ROM [o + 0xd7] - 7)) > 48) + score -= 1; + if (!AllASCII (&Memory.ROM [o + 0xb0], 6)) + score -= 1; + if (!AllASCII (&Memory.ROM [o + 0xc0], ROM_NAME_LEN - 1)) + score -= 1; + + return (score); +} + +char *CMemory::Safe (const char *s) +{ + static char *safe; + static int safe_len = 0; + + if(s==NULL) + { + if(safe!=NULL) + { + free((char*)safe); + safe = NULL; + } + return NULL; + } + int len = strlen (s); + if (!safe || len + 1 > safe_len) + { + if (safe) + free ((char *) safe); + safe = (char *) malloc (safe_len = len + 1); + } + + for (int i = 0; i < len; i++) + { + if (s [i] >= 32 && s [i] < 127) + safe [i] = s[i]; + else + safe [i] = '?'; + } + safe [len] = 0; + return (safe); +} + +char *CMemory::SafeANK (const char *s) +{ + static char *safe; + static int safe_len = 0; + + if(s==NULL) + { + if(safe!=NULL) + { + free((char*)safe); + safe = NULL; + } + return NULL; + } + int len = strlen (s); + if (!safe || len + 1 > safe_len) + { + if (safe) + free ((char *) safe); + safe = (char *) malloc (safe_len = len + 1); + } + + for (int i = 0; i < len; i++) + { + if (s [i] >= 32 && s [i] < 127) // ASCII + safe [i] = s[i]; + else + if (Memory.ROMRegion == 0 && ((unsigned char) s[i] >= 0xa0 && (unsigned char) s[i] < 0xe0)) // JIS X 201 + safe [i] = s[i]; + else + safe [i] = '?'; + + } + safe [len] = 0; + return (safe); +} + +/**********************************************************************************************/ +/* Init() */ +/* This function allocates all the memory needed by the emulator */ +/**********************************************************************************************/ +bool8 CMemory::Init () +{ + RAM = (uint8 *) malloc (0x20000); + SRAM = (uint8 *) malloc (0x20000); + VRAM = (uint8 *) malloc (0x10000); + ROM = (uint8 *) malloc (MAX_ROM_SIZE + 0x200 + 0x8000); + + memset (RAM, 0, 0x20000); + memset (SRAM, 0, 0x20000); + memset (VRAM, 0, 0x10000); + memset (ROM, 0, MAX_ROM_SIZE + 0x200 + 0x8000); + + FillRAM = NULL; + + IPPU.TileCache [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES * 64); + IPPU.TileCache [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES * 64); + IPPU.TileCache [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES * 64); + IPPU.TileCache [TILE_2BIT_EVEN] = (uint8 *) malloc (MAX_2BIT_TILES * 64); + IPPU.TileCache [TILE_2BIT_ODD] = (uint8 *) malloc (MAX_2BIT_TILES * 64); + IPPU.TileCache [TILE_4BIT_EVEN] = (uint8 *) malloc (MAX_4BIT_TILES * 64); + IPPU.TileCache [TILE_4BIT_ODD] = (uint8 *) malloc (MAX_4BIT_TILES * 64); + + IPPU.TileCached [TILE_2BIT] = (uint8 *) malloc (MAX_2BIT_TILES); + IPPU.TileCached [TILE_4BIT] = (uint8 *) malloc (MAX_4BIT_TILES); + IPPU.TileCached [TILE_8BIT] = (uint8 *) malloc (MAX_8BIT_TILES); + IPPU.TileCached [TILE_2BIT_EVEN] = (uint8 *) malloc (MAX_2BIT_TILES); + IPPU.TileCached [TILE_2BIT_ODD] = (uint8 *) malloc (MAX_2BIT_TILES); + IPPU.TileCached [TILE_4BIT_EVEN] = (uint8 *) malloc (MAX_4BIT_TILES); + IPPU.TileCached [TILE_4BIT_ODD] = (uint8 *) malloc (MAX_4BIT_TILES); + + if (!RAM || !SRAM || !VRAM || !ROM || + !IPPU.TileCache [TILE_2BIT] || !IPPU.TileCache [TILE_4BIT] || + !IPPU.TileCache [TILE_8BIT] || !IPPU.TileCached [TILE_2BIT] || + !IPPU.TileCached [TILE_4BIT] || !IPPU.TileCached [TILE_8BIT] || + !IPPU.TileCache [TILE_2BIT_EVEN] || !IPPU.TileCache [TILE_2BIT_ODD] || + !IPPU.TileCache [TILE_4BIT_EVEN] || !IPPU.TileCache [TILE_4BIT_ODD] || + !IPPU.TileCached [TILE_2BIT_EVEN] || !IPPU.TileCached [TILE_2BIT_ODD] || + !IPPU.TileCached [TILE_4BIT_EVEN] || !IPPU.TileCached [TILE_4BIT_ODD]) + { + Deinit (); + return (FALSE); + } + + // FillRAM uses first 32K of ROM image area, otherwise space just + // wasted. Might be read by the SuperFX code. + + FillRAM = ROM; + + // Add 0x8000 to ROM image pointer to stop SuperFX code accessing + // unallocated memory (can cause crash on some ports). + ROM += 0x8000; + + C4RAM = ROM + 0x400000 + 8192 * 8; + ::ROM = ROM; + ::SRAM = SRAM; + ::RegRAM = FillRAM; + + // BS + BIOSROM = ROM + 0x300000; + BSRAM = ROM + 0x400000; + +#ifdef ZSNES_FX + SFXPlotTable = ROM + 0x400000; +#else + SuperFX.pvRegisters = &Memory.FillRAM [0x3000]; + SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB, 2=128KB=1024Mb + SuperFX.pvRam = ::SRAM; + SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024); + SuperFX.pvRom = (uint8 *) ROM; +#endif + + ZeroMemory (IPPU.TileCache [TILE_2BIT], MAX_2BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_4BIT], MAX_4BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_8BIT], MAX_8BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_2BIT_EVEN], MAX_2BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_2BIT_ODD], MAX_2BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_4BIT_EVEN], MAX_4BIT_TILES * 64); + ZeroMemory (IPPU.TileCache [TILE_4BIT_ODD], MAX_4BIT_TILES * 64); + + ZeroMemory (IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_2BIT_EVEN], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_2BIT_ODD], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT_EVEN], MAX_4BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT_ODD], MAX_4BIT_TILES); + + SDD1Data = NULL; + SDD1Index = NULL; + + return (TRUE); +} + +void CMemory::Deinit () +{ +#ifdef __W32_HEAP + if(_HEAPOK!=_heapchk()) + MessageBox(GUI.hWnd, "CMemory::Deinit", "Heap Corrupt", MB_OK); +#endif + + if (RAM) + { + free ((char *) RAM); + RAM = NULL; + } + if (SRAM) + { + free ((char *) SRAM); + SRAM = NULL; + } + if (VRAM) + { + free ((char *) VRAM); + VRAM = NULL; + } + if (ROM) + { + ROM -= 0x8000; + free ((char *) ROM); + ROM = NULL; + } + + for(int t=0; t<7; t++){ + if(IPPU.TileCache[t]) { + free ((char *) IPPU.TileCache[t]); + IPPU.TileCache[t] = NULL; + } + if(IPPU.TileCached[t]) { + free ((char *) IPPU.TileCached[t]); + IPPU.TileCached[t] = NULL; + } + } + + FreeSDD1Data (); + Safe(NULL); + SafeANK(NULL); +} + +void CMemory::FreeSDD1Data () +{ + if (SDD1Index) + { + free ((char *) SDD1Index); + SDD1Index = NULL; + } + if (SDD1Data) + { + free ((char *) SDD1Data); + SDD1Data = NULL; + } +} + +/**********************************************************************************************/ +/* LoadROM() */ +/* This function loads a Snes-Backup image */ +/**********************************************************************************************/ + +bool8 CMemory::LoadROM (const char *filename) +{ + int32 TotalFileSize = 0; + bool8 Interleaved = FALSE; + bool8 Tales = FALSE; + + uint8* RomHeader=ROM; + + ExtendedFormat=NOPE; + + + if(CleanUp7110!=NULL) + (*CleanUp7110)(); + + memset (&SNESGameFixes, 0, sizeof(SNESGameFixes)); + SNESGameFixes.SRAMInitialValue = 0x60; + + CPU.TriedInterleavedMode2 = FALSE; + + CalculatedSize = 0; + retry_count =0; + +again: + Settings.DisplayColor=0xffff; + SET_UI_COLOR(255,255,255); + + TotalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE); + + if (!TotalFileSize) + return FALSE; // it ends here + +#ifndef NGC + else if(!Settings.NoPatch) + CheckForIPSPatch (filename, HeaderCount != 0, TotalFileSize); +#endif + + //fix hacked games here. + if((strncmp("HONKAKUHA IGO GOSEI", (char*)&ROM[0x7FC0],19)==0)&&(ROM[0x7FD5]!=0x31)) + { + ROM[0x7FD5]=0x31; + ROM[0x7FD6]=0x02; + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); + } + + if((strncmp("HONKAKUHA IGO GOSEI", (char*)&ROM[0xFFC0],19)==0)&&(ROM[0xFFD5]!=0x31)) + { + ROM[0xFFD5]=0x31; + ROM[0xFFD6]=0x02; + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); + } + + if((ROM[0x7FD5]==0x42)&&(ROM[0x7FD6]==0x13)&&(strncmp("METAL COMBAT",(char*)&ROM[0x7FC0],12)==0)) + { + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + S9xMessage(S9X_ERROR,S9X_ROM_CONFUSING_FORMAT_INFO, "Warning! Hacked Dump!"); + } + + int orig_hi_score, orig_lo_score; + int hi_score, lo_score; + + orig_hi_score = hi_score = ScoreHiROM (FALSE); + orig_lo_score = lo_score = ScoreLoROM (FALSE); + + if (HeaderCount == 0 && !Settings.ForceNoHeader && + ((hi_score > lo_score && ScoreHiROM (TRUE) > hi_score) || + (hi_score <= lo_score && ScoreLoROM (TRUE) > lo_score))) + { + memmove (Memory.ROM, Memory.ROM + 512, TotalFileSize - 512); + TotalFileSize -= 512; + S9xMessage (S9X_INFO, S9X_HEADER_WARNING, + "Try specifying the -nhd command line option if the game doesn't work\n"); + //modifying ROM, so we need to rescore + orig_hi_score = hi_score = ScoreHiROM (FALSE); + orig_lo_score = lo_score = ScoreLoROM (FALSE); + } + + CalculatedSize = (TotalFileSize / 0x2000) * 0x2000; + ZeroMemory (ROM + CalculatedSize, MAX_ROM_SIZE - CalculatedSize); + + if(CalculatedSize >0x400000&& + !(ROM[0x7FD5]==0x32&&((ROM[0x7FD6]&0xF0)==0x40)) && //exclude S-DD1 + !(ROM[0xFFD5]==0x3A&&((ROM[0xFFD6]&0xF0)==0xF0))) //exclude SPC7110 + { + //you might be a Jumbo! + ExtendedFormat=YEAH; + } + + //If both vectors are invalid, it's type 1 LoROM + + if(ExtendedFormat==NOPE&&((ROM[0x7FFC]|(ROM[0x7FFD]<<8))<0x8000)&&((ROM[0xFFFC]|(ROM[0xFFFD]<<8)) <0x8000)) + { + if(Settings.DisplayColor==0xffff) + { + Settings.DisplayColor=BUILD_PIXEL(0,31,0); + SET_UI_COLOR(0,255,0); + } + if(!Settings.ForceInterleaved) + S9xDeinterleaveType1(TotalFileSize, ROM); + } + + //CalculatedSize is now set, so rescore + orig_hi_score = hi_score = ScoreHiROM (FALSE); + orig_lo_score = lo_score = ScoreLoROM (FALSE); + + if(NOPE!=ExtendedFormat) + { + int loromscore, hiromscore, swappedlorom, swappedhirom; + loromscore=ScoreLoROM(FALSE); + hiromscore=ScoreHiROM(FALSE); + swappedlorom=ScoreLoROM(FALSE, 0x400000); + swappedhirom=ScoreHiROM(FALSE, 0x400000); + + //set swapped here. + + if(max(swappedlorom, swappedhirom) >= max(loromscore, hiromscore)) + { + ExtendedFormat = BIGFIRST; + hi_score=swappedhirom; + lo_score=swappedlorom; + RomHeader=ROM+0x400000; + } + else + { + ExtendedFormat = SMALLFIRST; + lo_score=loromscore; + hi_score=hiromscore; + RomHeader=ROM; + } + + + } + + Interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2; + if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score)) + { + LoROM = TRUE; + HiROM = FALSE; + + // Ignore map type byte if not 0x2x or 0x3x + if ((RomHeader [0x7fd5] & 0xf0) == 0x20 || (RomHeader [0x7fd5] & 0xf0) == 0x30) + { + switch (RomHeader [0x7fd5] & 0xf) + { + case 1: + Interleaved = TRUE; + break; + case 5: + Interleaved = TRUE; + Tales = TRUE; + break; + } + } + } + else + { + if ((RomHeader [0xffd5] & 0xf0) == 0x20 || (RomHeader [0xffd5] & 0xf0) == 0x30) + { + switch (RomHeader [0xffd5] & 0xf) + { + case 0: + case 3: + Interleaved = TRUE; + break; + } + } + LoROM = FALSE; + HiROM = TRUE; + } + + // More + if (!Settings.ForceHiROM && !Settings.ForceLoROM && + !Settings.ForceInterleaved && !Settings.ForceInterleaved2 && + !Settings.ForceNotInterleaved && !Settings.ForcePAL && + !Settings.ForceSuperFX && !Settings.ForceDSP1 && + !Settings.ForceSA1 && !Settings.ForceC4 && + !Settings.ForceSDD1) + { + + +#ifdef DETECT_NASTY_FX_INTERLEAVE +//MK: Damn. YI trips a BRK currently. Maybe even on a real cart. + + if(strncmp((char *)&ROM[0x7fc0], "YOSHI'S ISLAND", 14) == 0 && READ_WORD(ROM+0x7FDE)==57611 && ROM[0x10002]==0xA9) + { + Interleaved=true; + Settings.ForceInterleaved2=true; + } +#endif + if (strncmp ((char *) &ROM [0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0) + { + LoROM = TRUE; + HiROM = FALSE; + Interleaved = FALSE; + } + } + + if (!Settings.ForceNotInterleaved && Interleaved) + { + CPU.TriedInterleavedMode2 = TRUE; + S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO, + "ROM image is in interleaved format - converting..."); + + if (Tales) + { + if(Memory.ExtendedFormat==BIGFIRST) + { + S9xDeinterleaveType1(0x400000, ROM); + S9xDeinterleaveType1(CalculatedSize-0x400000, ROM+0x400000); + } + else + { + S9xDeinterleaveType1(CalculatedSize-0x400000, ROM); + S9xDeinterleaveType1(0x400000, ROM+CalculatedSize-0x400000); + + } + + LoROM = FALSE; + HiROM = TRUE; + + + } + else if (Settings.ForceInterleaved2) + { + S9xDeinterleaveType2(FALSE); + } + else if (Settings.ForceInterleaveGD24 && CalculatedSize ==0x300000) + { + bool8 t = LoROM; + + LoROM = HiROM; + HiROM = t; + S9xDeinterleaveGD24(CalculatedSize, ROM); + } + else + { + if(Settings.DisplayColor==0xffff) + { + Settings.DisplayColor=BUILD_PIXEL(0,31,0); + SET_UI_COLOR(0,255,0); + } + bool8 t = LoROM; + + LoROM = HiROM; + HiROM = t; + + S9xDeinterleaveType1(CalculatedSize, ROM); + } + + hi_score = ScoreHiROM (FALSE); + lo_score = ScoreLoROM (FALSE); + + if ((HiROM && + (lo_score >= hi_score || hi_score < 0)) || + (LoROM && + (hi_score > lo_score || lo_score < 0))) + { + if (retry_count == 0) + { + S9xMessage (S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, + "ROM lied about its type! Trying again."); + Settings.ForceNotInterleaved = TRUE; + Settings.ForceInterleaved = FALSE; + retry_count++; + goto again; + } + } + } + + if(ExtendedFormat==SMALLFIRST) + Tales=true; + + FreeSDD1Data (); + InitROM (Tales); + +#ifndef NGC + S9xLoadCheatFile (S9xGetFilename(".cht", PATCH_DIR)); + S9xInitCheatData (); + S9xApplyCheats (); +#endif + + S9xReset (); + + return (TRUE); +} + +uint32 CMemory::FileLoader (uint8* buffer, const char* filename, int32 maxsize) +{ + + +#ifndef NGC + STREAM ROMFile; + int len = 0; + int nFormat=FILE_DEFAULT; +#endif + + int32 TotalFileSize = 0; + char dir [_MAX_DIR + 1]; + char drive [_MAX_DRIVE + 1]; + char name [_MAX_FNAME + 1]; + char ext [_MAX_EXT + 1]; + char fname [_MAX_PATH + 1]; + + unsigned long FileSize = 0; + +#ifdef UNZIP_SUPPORT + unzFile file=NULL; +#endif + + _splitpath (filename, drive, dir, name, ext); + _makepath (fname, drive, dir, name, ext); + +#if defined(__WIN32__) || defined(__MACOSX__) + memmove (&ext [0], &ext[1], 4); +#endif + +#ifndef NGC + if (strcasecmp (ext, "zip") == 0) + nFormat = FILE_ZIP; + else if (strcasecmp (ext, "rar") == 0) + nFormat = FILE_RAR; + else if (strcasecmp (ext, "jma") == 0) + nFormat = FILE_JMA; + else + nFormat = FILE_DEFAULT; + + switch( nFormat ) + { + case FILE_ZIP: + +#ifdef UNZIP_SUPPORT + + file = unzOpen(fname); + + if(file != NULL) + { + + // its a valid ZIP, close it and let LoadZIP handle it. + + unzClose(file); + + if (!LoadZip (fname, &TotalFileSize, &HeaderCount, ROM)) + return (0); + + strcpy (ROMFilename, fname); + + } + else + { + // its a bad zip file. Walk away + + S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Invalid Zip Archive."); + return (0); + } +#else + S9xMessage (S9X_ERROR, S9X_ROM_INFO, "This binary was not created with Zip support."); + return (0); +#endif + break; + + case FILE_JMA: + { +#ifdef JMA_SUPPORT + size_t FileSize = load_jma_file(fname, ROM); + + if (!FileSize) + { + S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Invalid JMA."); + return (0); + } + + TotalFileSize = FileSize; + HeaderCount = 0; + + size_t calc_size = (FileSize / 0x2000) * 0x2000; + + + if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || + Settings.ForceHeader) + { + memmove (ROM, ROM + 512, calc_size); + HeaderCount = 1; + FileSize -= 512; + } + + strcpy (ROMFilename, fname); +#else + S9xMessage (S9X_ERROR, S9X_ROM_INFO, "This binary was not created with JMA support."); + return (0); +#endif + break; + } + + case FILE_RAR: + // non existant rar loading + S9xMessage (S9X_ERROR, S9X_ROM_INFO, "Rar Archives are not currently supported."); + return (0); + break; + + case FILE_DEFAULT: + default: + // any other roms go here + + if ((ROMFile = OPEN_STREAM (fname, "rb")) == NULL) + return (0); + + strcpy (ROMFilename, fname); + + HeaderCount = 0; + uint8 *ptr = buffer; + bool8 more = FALSE; + + do + { + FileSize = READ_STREAM (ptr, maxsize + 0x200 - (ptr - ROM), ROMFile); + CLOSE_STREAM (ROMFile); + + int calc_size = (FileSize / 0x2000) * 0x2000; + + if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || + Settings.ForceHeader) + { + memmove (ptr, ptr + 512, calc_size); + HeaderCount++; + FileSize -= 512; + } + + ptr += FileSize; + TotalFileSize += FileSize; + + + // check for multi file roms + + if (ptr - ROM < maxsize + 0x200 && + (isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9')) + { + more = TRUE; + ext [0]++; +#if defined(__WIN32__) || defined(__MACOSX__) + memmove (&ext [1], &ext [0], 4); + ext [0] = '.'; +#endif + _makepath (fname, drive, dir, name, ext); + } + else if (ptr - ROM < maxsize + 0x200 && + (((len = strlen (name)) == 7 || len == 8) && + strncasecmp (name, "sf", 2) == 0 && + isdigit (name [2]) && isdigit (name [3]) && isdigit (name [4]) && + isdigit (name [5]) && isalpha (name [len - 1]))) + { + more = TRUE; + name [len - 1]++; +#if defined(__WIN32__) || defined(__MACOSX__) + memmove (&ext [1], &ext [0], 4); + ext [0] = '.'; +#endif + _makepath (fname, drive, dir, name, ext); + } + else + more = FALSE; + + } while (more && (ROMFile = OPEN_STREAM (fname, "rb")) != NULL); + + break; + } + +#else + + /*** Nintendo Gamecube ARAM ROM File Loader + This is simply a modified version of FILE_DEFAULT, which uses + the ARAM as temporary ROM storage. + + NB: Make sure ARAM_ROMSIZE is correct! All hell ensues if you don't + ***/ + HeaderCount = 0; + uint8 *ptr = buffer; + + unsigned long ARAM_max = maxsize + 0x200 - (ptr - ROM); + FileSize = ARAM_ROMSIZE; + + if ( FileSize > ARAM_max ) + FileSize = ARAM_max; + + if ( hasloaded == 0 ) + ARAMFetchSlow( (char *)ptr, (char *)AR_SNESROM, FileSize ); + + int calc_size = (FileSize / 0x2000) * 0x2000; + + if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || + Settings.ForceHeader) + { + memmove (ptr, ptr + 512, calc_size); + HeaderCount++; + FileSize -= 512; + } + + ptr += FileSize; + TotalFileSize += FileSize; + +#endif + + if (HeaderCount == 0) + S9xMessage (S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found."); + else + { + if (HeaderCount == 1) + S9xMessage (S9X_INFO, S9X_HEADERS_INFO, + "Found ROM file header (and ignored it)."); + else + S9xMessage (S9X_INFO, S9X_HEADERS_INFO, + "Found multiple ROM file headers (and ignored them)."); + } + + + return TotalFileSize; + +} + +#if 0 +/**********************************************************************************************/ +/* LoadMulti() */ +/* This function loads a Slotted SNES-Backup image and fills the slot. */ +/**********************************************************************************************/ + +bool8 CMemory::LoadMulti (const char *basename, const char *slot1name, const char *slot2name) +{ + unsigned long FileSize = 0; + + if(*basename=='\0') + return FALSE; + + SufamiTurbo=TRUE; + + int32 offset; + + memset (&SNESGameFixes, 0, sizeof(SNESGameFixes)); + SNESGameFixes.SRAMInitialValue = 0x60; + + CalculatedSize = 0; + + Settings.DisplayColor=0xffff; + SET_UI_COLOR(255,255,255); + + int32 TotalFileSize = FileLoader(ROM, basename, MAX_ROM_SIZE); + + if(0== TotalFileSize) return FALSE; + +#ifndef NGC + CheckForIPSPatch (basename, HeaderCount != 0, TotalFileSize); +#endif + + CalculatedSize=TotalFileSize; + + for(offset=0; offset0x100000||size <0x80000) + return FALSE; + //probably a minicart + return TRUE; + } + return FALSE; +} + +bool8 SameGameSig(uint8* file, int32 size) +{ + //preheader sig + if(strcmp((char*)(file+0xFFA0),"1995/12/16 10:2018ZS5J")) + return FALSE; + if(size!=0x100000) + return FALSE; + if(0x133E1C5B==caCRC32(file, size)) + return TRUE; + return FALSE; +} +bool8 GNextSig(uint8* file, int32 size) +{ + //preheader sig + if(strcmp((char*)(file+0xFFAA),"GNEXT B2ZX3J")) + return FALSE; + if(size!=0x180000) + return FALSE; + if(0x845E420D==caCRC32(file, size)) + return TRUE; + return FALSE; +} +int MultiType(uint8* file, int32 size) +{ + //check for ST signiture + if(SufamiTurboBIOSSig(file, size)) + return 1; + //check for Same Game signiture + if(SameGameSig(file, size)) + return 2; + //check for G-Next signiture + if(GNextSig(file, size)) + return 3; + return 0; +} + +#endif + +//compatibility wrapper +void S9xDeinterleaveMode2 () +{ + S9xDeinterleaveType2(); +} + +void S9xDeinterleaveType2 (bool8 reset) +{ + if(Settings.DisplayColor==0xffff||Settings.DisplayColor==BUILD_PIXEL(0,31,0)) + { + Settings.DisplayColor=BUILD_PIXEL(31,14,6); + SET_UI_COLOR(255,119,25); + + } + S9xMessage (S9X_INFO, S9X_ROM_INTERLEAVED_INFO, + "ROM image is in interleaved format - converting..."); + + int nblocks = Memory.CalculatedSize >> 16; + int step = 64; + + while (nblocks <= step) + step >>= 1; + + nblocks = step; + uint8 blocks [256]; + int i; + + for (i = 0; i < nblocks * 2; i++) + { + blocks [i] = (i & ~0xF) | ((i & 3) << 2) | + ((i & 12) >> 2); + } + + uint8 *tmp = (uint8 *) malloc (0x10000); + + if (tmp) + { + for (i = 0; i < nblocks * 2; i++) + { + for (int j = i; j < nblocks * 2; j++) + { + if (blocks [j] == i) + { + memmove (tmp, &Memory.ROM [blocks [j] * 0x10000], 0x10000); + memmove (&Memory.ROM [blocks [j] * 0x10000], + &Memory.ROM [blocks [i] * 0x10000], 0x10000); + memmove (&Memory.ROM [blocks [i] * 0x10000], tmp, 0x10000); + uint8 b = blocks [j]; + blocks [j] = blocks [i]; + blocks [i] = b; + break; + } + } + } + free ((char *) tmp); + tmp=NULL; + } + if(reset) + { + Memory.InitROM (FALSE); + S9xReset (); + } +} + +//CRC32 for char arrays +inline uint32 caCRC32(uint8 *array, uint32 size, register uint32 crc32) +{ + for (register uint32 i = 0; i < size; i++) + { + crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF]; + } + return ~crc32; +} + +void CMemory::InitROM (bool8 Interleaved) +{ +#ifndef ZSNES_FX + SuperFX.nRomBanks = CalculatedSize >> 15; +#endif + Settings.DSP1Master = Settings.ForceDSP1; + Settings.SuperFX = FALSE; + Settings.SA1 = FALSE; + Settings.C4 = FALSE; + Settings.SDD1 = FALSE; + Settings.SRTC = FALSE; + Settings.SPC7110=FALSE; + Settings.SPC7110RTC=FALSE; + Settings.BS=FALSE; + Settings.OBC1=FALSE; + Settings.SETA=FALSE; + s7r.DataRomSize = 0; + CalculatedChecksum=0; + + uint8* RomHeader; + + RomHeader=ROM+0x7FB0; + + if(ExtendedFormat==BIGFIRST) + RomHeader+=0x400000; + + if(HiROM) + RomHeader+=0x8000; + + for (int i = 0; i < MEMMAP_NUM_BLOCKS; i++) + { + Map [MEMMAP_NUM_BLOCKS] = (uint8 *) MAP_NONE; + BlockIsRAM [MEMMAP_NUM_BLOCKS] = FALSE; + BlockIsROM [MEMMAP_NUM_BLOCKS] = FALSE; + } + + S9xInitBSX(); + + ::SRAM = SRAM; + memset (ROMId, 0, 5); + memset (CompanyId, 0, 3); + + ParseSNESHeader(RomHeader); + + // Try to auto-detect the DSP1 chip + if (!Settings.ForceNoDSP1 && + (ROMType & 0xf) >= 3 && (ROMType & 0xf0) == 0) + Settings.DSP1Master = TRUE; + + if (Memory.HiROM) + { + // Enable S-RTC (Real Time Clock) emulation for Dai Kaijyu Monogatari 2 + Settings.SRTC = ((ROMType & 0xf0) >> 4) == 5; + + if(((ROMSpeed&0x0F)==0x0A)&&((ROMType&0xF0)==0xF0)) + { + Settings.SPC7110=true; + if((ROMType&0x0F)==0x09) + Settings.SPC7110RTC=true; + } + + if (Settings.BS) + /* Do nothing */; + else if(Settings.SPC7110) + { + SPC7110HiROMMap(); + } + else if ((ROMSpeed & ~0x10) == 0x25) + { + TalesROMMap (Interleaved); + } + else HiROMMap (); + } + else + { + Settings.SuperFX = Settings.ForceSuperFX; + + if(ROMType==0x25) + { + Settings.OBC1=TRUE; + } + + if ((ROMType & 0xf0) == 0x10) + Settings.SuperFX = !Settings.ForceNoSuperFX; + + Settings.SDD1 = Settings.ForceSDD1; + if ((ROMType & 0xf0) == 0x40) + Settings.SDD1 = !Settings.ForceNoSDD1; + + if (Settings.SDD1) + S9xLoadSDD1Data (); + + if(((ROMType &0xF0) == 0xF0)&((ROMSpeed&0x0F)!=5)) + { + SRAMSize=2; + SNESGameFixes.SRAMInitialValue = 0x00; + if((ROMType &0x0F)==6) + { + if(ROM[0x7FD7]==0x09) + { + Settings.SETA=ST_011; + SetSETA=&S9xSetST011; + GetSETA=&S9xGetST011; + } + else + { + Settings.SETA=ST_010; + SetSETA=&S9xSetST010; + GetSETA=&S9xGetST010; + } + } + else + { + Settings.SETA=ST_018; + SRAMSize=2; + } + } + + Settings.C4 = Settings.ForceC4; + if ((ROMType & 0xf0) == 0xf0 && + (strncmp (ROMName, "MEGAMAN X", 9) == 0 || + strncmp (ROMName, "ROCKMAN X", 9) == 0)) + { + Settings.C4 = !Settings.ForceNoC4; + } + + if(Settings.SETA&&Settings.SETA!=ST_018) + { + SetaDSPMap(); + } + else if (Settings.SuperFX) + { + //::SRAM = ROM + 1024 * 1024 * 4; + SuperFXROMMap (); + Settings.MultiPlayer5Master = FALSE; + //Settings.MouseMaster = FALSE; + //Settings.SuperScopeMaster = FALSE; + Settings.DSP1Master = FALSE; + Settings.SA1 = FALSE; + Settings.C4 = FALSE; + Settings.SDD1 = FALSE; + } + else if (Settings.ForceSA1 || + (!Settings.ForceNoSA1 && (ROMSpeed & ~0x10) == 0x23 && + (ROMType & 0xf) > 3 && (ROMType & 0xf0) == 0x30)) + { + Settings.SA1 = TRUE; +// Settings.MultiPlayer5Master = FALSE; + //Settings.MouseMaster = FALSE; + //Settings.SuperScopeMaster = FALSE; + Settings.DSP1Master = FALSE; + Settings.C4 = FALSE; + Settings.SDD1 = FALSE; + SA1ROMMap (); + } + else if ((ROMSpeed & ~0x10) == 0x25) + TalesROMMap (Interleaved); + else if(ExtendedFormat!=NOPE) + JumboLoROMMap(Interleaved); + else if (strncmp ((char *) &Memory.ROM [0x7fc0], "SOUND NOVEL-TCOOL", 17) == 0 || + strncmp ((char *) &Memory.ROM [0x7fc0], "DERBY STALLION 96", 17) == 0) + { + LoROM24MBSMap (); + Settings.DSP1Master = FALSE; + } + + else if (strncmp ((char *) &Memory.ROM [0x7fc0], "THOROUGHBRED BREEDER3", 21) == 0 || + strncmp ((char *) &Memory.ROM [0x7fc0], "RPG-TCOOL 2", 11) == 0) + { + SRAM512KLoROMMap (); + Settings.DSP1Master = FALSE; + } + else if (strncmp ((char *) &Memory.ROM [0x7fc0], "ADD-ON BASE CASSETE", 19) == 0) + { + Settings.MultiPlayer5Master = FALSE; + Settings.MouseMaster = FALSE; + Settings.SuperScopeMaster = FALSE; + Settings.DSP1Master = FALSE; + SufamiTurboLoROMMap(); + Memory.SRAMSize = 3; + } + else if ((ROMSpeed & ~0x10) == 0x22 && + strncmp (ROMName, "Super Street Fighter", 20) != 0) + { + AlphaROMMap (); + } + else if (Settings.BS) + /* Do nothing */; + else LoROMMap (); + } + + uint32 sum1 = 0; + uint32 sum2 = 0; + if(0==CalculatedChecksum) + { + int power2 = 0; + int size = CalculatedSize; + + while (size >>= 1) + power2++; + + size = 1 << power2; + uint32 remainder = CalculatedSize - size; + + + int i; + + for (i = 0; i < size; i++) + sum1 += ROM [i]; + + for (i = 0; i < (int) remainder; i++) + sum2 += ROM [size + i]; + + int sub = 0; + if (Settings.BS && !Settings.BSXItself) + { + if (Memory.HiROM) + { + for (i = 0; i < 48; i++) + sub += ROM[0xffb0 + i]; + } + else if (Memory.LoROM) + { + for (i = 0; i < 48; i++) + sub += ROM[0x7fb0 + i]; + } + sum1 -= sub; + } + + + if (remainder) + { + sum1 += sum2 * (size / remainder); + } + + + sum1 &= 0xffff; + Memory.CalculatedChecksum=sum1; + } + //now take a CRC32 + ROMCRC32 = caCRC32(ROM, CalculatedSize); + + if (Settings.ForceNTSC) + Settings.PAL = FALSE; + else if (Settings.ForcePAL) + Settings.PAL = TRUE; + else + { + //Korea refers to South Korea, which uses NTSC + switch(ROMRegion) + { + case 13: + case 1: + case 0: + Settings.PAL=FALSE; + break; + default: Settings.PAL=TRUE; + break; + } + } + + Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE; + Timings.H_Max = Timings.H_Max_Master; + Timings.HBlankStart = SNES_HBLANK_START_HC; + Timings.HBlankEnd = SNES_HBLANK_END_HC; + Timings.HDMAInit = SNES_HDMA_INIT_HC; + Timings.HDMAStart = SNES_HDMA_START_HC; + Timings.RenderPos = SNES_RENDER_START_HC; + Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER; + Timings.V_Max = Timings.V_Max_Master; + + if (Settings.PAL) + { + Settings.FrameTime = Settings.FrameTimePAL; + Memory.ROMFramesPerSecond = 50; + } + else + { + Settings.FrameTime = Settings.FrameTimeNTSC; + Memory.ROMFramesPerSecond = 60; + } + + ROMName[ROM_NAME_LEN - 1] = 0; + if (strlen (ROMName)) + { + char *p = ROMName + strlen (ROMName); + if(p>ROMName+21 && ROMName[20]==' ') p=ROMName+21; + + while (p > ROMName && *(p - 1) == ' ') + p--; + *p = 0; + } + + { + SRAMMask = Memory.SRAMSize ? + ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0; + } + if((ROMChecksum + ROMComplementChecksum != 0xffff) || ROMChecksum != CalculatedChecksum || ((uint32)CalculatedSize > (uint32)(((1<<(ROMSize-7))*128)*1024))) + { + if(Settings.DisplayColor==0xffff || Settings.DisplayColor!=BUILD_PIXEL(31,0,0)) + { + Settings.DisplayColor=BUILD_PIXEL(31,31,0); + SET_UI_COLOR(255,255,0); + } + } + + IAPU.OneCycle = ONE_APU_CYCLE; + Settings.Shutdown = Settings.ShutdownMaster; + + SetDSP=&DSP1SetByte; + GetDSP=&DSP1GetByte; + + CPU.FastROMSpeed = 0; + ResetSpeedMap(); + ApplyROMFixes (); + + char displayName[ROM_NAME_LEN]; + strcpy (RawROMName, ROMName); + sprintf (displayName, "%s", SafeANK (ROMName)); + sprintf (ROMName, "%s", Safe (ROMName)); + sprintf (ROMId, "%s", Safe (ROMId)); + sprintf (CompanyId, "%s", Safe (CompanyId)); + + sprintf (String, "\"%s\" [%s] %s, %s, Type: %s, Mode: %s, TV: %s, S-RAM: %s, ROMId: %s Company: %2.2s CRC32: %08X", + displayName, + (ROMChecksum + ROMComplementChecksum != 0xffff || + ROMChecksum != CalculatedChecksum) ? "bad checksum" : "checksum ok", + MapType (), + Size (), + KartContents (), + MapMode (), + TVStandard (), + StaticRAMSize (), + ROMId, + CompanyId, + ROMCRC32); + + S9xMessage (S9X_INFO, S9X_ROM_INFO, String); +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_ROM_INFO, MF_ENABLED); + #endif + #ifdef RTC_DEBUGGER + if(Settings.SPC7110RTC) + EnableMenuItem(GUI.hMenu, IDM_7110_RTC, MF_ENABLED); + else EnableMenuItem(GUI.hMenu, IDM_7110_RTC, MF_GRAYED); + #endif +#endif + Settings.ForceHeader = Settings.ForceHiROM = Settings.ForceLoROM = + Settings.ForceInterleaved = Settings.ForceNoHeader = Settings.ForceNotInterleaved = + Settings.ForceInterleaved2=false; + + S9xVerifyControllers(); +} + +bool8 CMemory::LoadSRAM (const char *filename) +{ + int size = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + + memset (SRAM, SNESGameFixes.SRAMInitialValue, 0x20000); + + if (size > 0x20000) + size = 0x20000; +#ifndef NGC + if (size) + { + FILE *file; + if ((file = fopen (filename, "rb"))) + { + int len = fread ((char*) ::SRAM, 1, 0x20000, file); + fclose (file); + if (len - size == 512) + { + // S-RAM file has a header - remove it + memmove (::SRAM, ::SRAM + 512, size); + } + if (len == size + SRTC_SRAM_PAD) + { + S9xSRTCPostLoadState (); + S9xResetSRTC (); + rtc.index = -1; + rtc.mode = MODE_READ; + } + else + S9xHardResetSRTC (); + + if(Settings.SPC7110RTC) + { + S9xLoadSPC7110RTC (&rtc_f9); + } + + return (TRUE); + } + else + if (Settings.BS && !Settings.BSXItself) + { + // The BS game's SRAM was not found + // Try to read BS-X.srm instead + + char path[_MAX_PATH + 1]; + + strcpy(path, S9xGetDirectory(SRAM_DIR)); + strcat(path, SLASH_STR); + strcat(path, "BS-X.srm"); + + if ((file = fopen(path, "rb"))) + { + fread((char *) ::SRAM, 1, 0x20000, file); + fclose (file); + S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found: BS-X.srm was read instead."); + S9xHardResetSRTC(); + return (TRUE); + } + else + { + S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found, BS-X.srm wasn't found either."); + S9xHardResetSRTC(); + return (FALSE); + } + } + + S9xHardResetSRTC (); + return (FALSE); + } + if (Settings.SDD1) + S9xSDD1LoadLoggedData (); + +#endif + + return (TRUE); +} + +bool8 CMemory::SaveSRAM (const char *filename) +{ + if(Settings.SuperFX && Memory.ROMType < 0x15) + return TRUE; + if(Settings.SA1 && Memory.ROMType == 0x34) + return TRUE; + + int size = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (Settings.SRTC) + { + size += SRTC_SRAM_PAD; + S9xSRTCPreSaveState (); + } + + if (Settings.SDD1) + S9xSDD1SaveLoggedData (); + + if (size > 0x20000) + size = 0x20000; + + if (size && *Memory.ROMFilename) + { + FILE *file; + if ((file = fopen (filename, "wb"))) + { + fwrite ((char *) ::SRAM, size, 1, file); + fclose (file); +#if defined(__linux) + chown (filename, getuid (), getgid ()); +#endif + if(Settings.SPC7110RTC) + { + S9xSaveSPC7110RTC (&rtc_f9); + } + return (TRUE); + } + } + return (FALSE); +} + +void CMemory::FixROMSpeed () +{ + int c; + + if(CPU.FastROMSpeed==0) + CPU.FastROMSpeed=SLOW_ONE_CYCLE; + + + for (c = 0x800; c < 0x1000; c++) + { + if (c&0x8 || c&0x400) + MemorySpeed [c] = (uint8) CPU.FastROMSpeed; + } +} + + +void CMemory::ResetSpeedMap() +{ + int i; + memset(MemorySpeed, SLOW_ONE_CYCLE, 0x1000); + for(i=0;i<0x400;i+=0x10) + { + MemorySpeed[i+2]=MemorySpeed[0x800+i+2]= ONE_CYCLE; + MemorySpeed[i+3]=MemorySpeed[0x800+i+3]= ONE_CYCLE; + MemorySpeed[i+4]=MemorySpeed[0x800+i+4]= ONE_CYCLE; + MemorySpeed[i+5]=MemorySpeed[0x800+i+5]= ONE_CYCLE; + } + CMemory::FixROMSpeed (); +} + +void CMemory::WriteProtectROM () +{ + memmove ((void *) WriteMap, (void *) Map, sizeof (Map)); + for (int c = 0; c < 0x1000; c++) + { + if (BlockIsROM [c]) + WriteMap [c] = (uint8 *) MAP_NONE; + } +} + +void CMemory::MapRAM () +{ + int c; + + if(Memory.LoROM&&!Settings.SDD1) + { + // Banks 70->77, S-RAM + for (c = 0; c < 0x0f; c++) + { + for(int i=0;i<8;i++) + { + Map [(c<<4) + 0xF00+i]=Map [(c<<4) + 0x700+i] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [(c<<4) + 0xF00+i] =BlockIsRAM [(c<<4) + 0x700+i] = TRUE; + BlockIsROM [(c<<4) + 0xF00+i] =BlockIsROM [(c<<4) + 0x700+i] = FALSE; + } + } + } + else if(Memory.LoROM&&Settings.SDD1) + { + // Banks 70->77, S-RAM + for (c = 0; c < 0x0f; c++) + { + for(int i=0;i<8;i++) + { + Map [(c<<4) + 0x700+i] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [(c<<4) + 0x700+i] = TRUE; + BlockIsROM [(c<<4) + 0x700+i] = FALSE; + } + } + } + // Banks 7e->7f, RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + WriteProtectROM (); +} + +void CMemory::MapExtraRAM () +{ + int c; + + // Banks 7e->7f, RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + + // Banks 70->73, S-RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x700] = ::SRAM; + Map [c + 0x710] = ::SRAM + 0x8000; + Map [c + 0x720] = ::SRAM + 0x10000; + Map [c + 0x730] = ::SRAM + 0x18000; + + BlockIsRAM [c + 0x700] = TRUE; + BlockIsROM [c + 0x700] = FALSE; + BlockIsRAM [c + 0x710] = TRUE; + BlockIsROM [c + 0x710] = FALSE; + BlockIsRAM [c + 0x720] = TRUE; + BlockIsROM [c + 0x720] = FALSE; + BlockIsRAM [c + 0x730] = TRUE; + BlockIsROM [c + 0x730] = FALSE; + } +} + +void CMemory::LoROMMap () +{ + int c; + int i; + int j; + int mask[4]; + for (j=0; j<4; j++) + mask[j]=0x00ff; + + mask[0]=(CalculatedSize/0x8000)-1; + + int x; + bool foundZeros; + bool pastZeros; + + for(j=0;j<3;j++) + { + x=1; + foundZeros=false; + pastZeros=false; + + mask[j+1]=mask[j]; + + while (x>0x100&&!pastZeros) + { + if(mask[j]&x) + { + x<<=1; + if(foundZeros) + pastZeros=true; + } + else + { + foundZeros=true; + pastZeros=false; + mask[j+1]|=x; + x<<=1; + } + } + } + + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + if(Settings.SETA==ST_018) + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_SETA_RISC; + else Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + if (Settings.DSP1Master) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP; + } + else if (Settings.C4) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_C4; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_C4; + } + else if(Settings.OBC1) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_OBC_RAM; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_OBC_RAM; + } + else + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + } + + for (i = c + 8; i < c + 16; i++) + { + int e=3; + int d=c>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + Map [i] = Map [i + 0x800] = ROM + (((d)-1)*0x8000); + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + if (Settings.DSP1Master) + { + // Banks 30->3f and b0->bf + for (c = 0x300; c < 0x400; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = (uint8 *) MAP_DSP; + BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE; + } + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) % CalculatedSize]; + + for (i = c + 8; i < c + 16; i++) + { + int e=3; + int d=(c+0x400)>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + + Map [i + 0x400] = Map [i + 0xc00] = ROM + (((d)-1)*0x8000); + } + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + if (Settings.DSP1Master) + { + for (c = 0; c < 0x100; c++) + { + Map [c + 0xe00] = (uint8 *) MAP_DSP; + BlockIsROM [c + 0xe00] = FALSE; + } + } + + int sum=0, k,l, bankcount; + bankcount=1<<(ROMSize-7);//Mbits + + //safety for corrupt headers + if(bankcount > 128) + bankcount = (CalculatedSize/0x8000)/4; + bankcount*=4;//to banks + bankcount<<=4;//Map banks + bankcount+=0x800;//normalize + for(k=0x800;k<(bankcount);k+=16) + { + uint8* bank=0x8000+Map[k+8]; + for(l=0;l<0x8000;l++) + sum+=bank[l]; + } + CalculatedChecksum=sum&0xFFFF; + + MapRAM (); + WriteProtectROM (); +} + +void CMemory::SetaDSPMap () +{ + int c; + int i; + int j; + int mask[4]; + for (j=0; j<4; j++) + mask[j]=0x00ff; + + mask[0]=(CalculatedSize/0x8000)-1; + + int x; + bool foundZeros; + bool pastZeros; + + for(j=0;j<3;j++) + { + x=1; + foundZeros=false; + pastZeros=false; + + mask[j+1]=mask[j]; + + while (x>0x100&&!pastZeros) + { + if(mask[j]&x) + { + x<<=1; + if(foundZeros) + pastZeros=true; + } + else + { + foundZeros=true; + pastZeros=false; + mask[j+1]|=x; + x<<=1; + } + } + } + + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + int e=3; + int d=c>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + Map [i] = Map [i + 0x800] = ROM + (((d)-1)*0x8000); + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + int e=3; + int d=(c+0x400)>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + + Map [i + 0x400] = Map [i + 0xc00] = ROM + (((d)-1)*0x8000); + } + + //only upper half is ROM + for (i = c+8; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + memset(SRAM, 0, 0x1000); + for (c=0x600;c<0x680;c+=0x10) + { + for(i=0;i<0x08;i++) + { + //where does the SETA chip access, anyway? + //please confirm this? + Map[c+0x80+i]=(uint8*)MAP_SETA_DSP; + BlockIsROM [c+0x80+i] = FALSE; + BlockIsRAM [c+0x80+i] = TRUE; + } + + for(i=0;i<0x04;i++) + { + //and this! + Map[c+i]=(uint8*)MAP_SETA_DSP; + BlockIsROM [c+i] = FALSE; + } + } + + int sum=0, k,l, bankcount; + bankcount=1<<(ROMSize-7);//Mbits + //safety for corrupt headers + if(bankcount > 128) + bankcount = (CalculatedSize/0x8000)/4; + bankcount*=4;//to banks + bankcount<<=4;//Map banks + bankcount+=0x800;//normalize + for(k=0x800;k<(bankcount);k+=16) + { + uint8* bank=0x8000+Map[k+8]; + for(l=0;l<0x8000;l++) + sum+=bank[l]; + } + CalculatedChecksum=sum&0xFFFF; + + MapRAM (); + WriteProtectROM (); +} + +void CMemory::HiROMMap () +{ + int i; + int c; + int j; + + int mask[4]; + for (j=0; j<4; j++) + mask[j]=0x00ff; + + mask[0]=(CalculatedSize/0x10000)-1; + + if (Settings.ForceSA1 || + (!Settings.ForceNoSA1 && (ROMSpeed & ~0x10) == 0x23 && + (ROMType & 0xf) > 3 && (ROMType & 0xf0) == 0x30)) + { + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + } + + + int x; + bool foundZeros; + bool pastZeros; + + for(j=0;j<3;j++) + { + x=1; + foundZeros=false; + pastZeros=false; + + mask[j+1]=mask[j]; + + while (x>0x100&&!pastZeros) + { + if(mask[j]&x) + { + x<<=1; + if(foundZeros) + pastZeros=true; + } + else + { + foundZeros=true; + pastZeros=false; + mask[j+1]|=x; + x<<=1; + } + } + } + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + + if (Settings.DSP1Master) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP; + } + else + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + } + + for (i = c + 8; i < c + 16; i++) + { + int e=3; + int d=c>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + Map [i] = Map [i + 0x800] = ROM + (d*0x10000); + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM. + for (c = 0; c < 16; c++) + { + Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + BlockIsRAM [0x306 + (c << 4)] = TRUE; + BlockIsRAM [0x307 + (c << 4)] = TRUE; + BlockIsRAM [0xb06 + (c << 4)] = TRUE; + BlockIsRAM [0xb07 + (c << 4)] = TRUE; + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + int e=3; + int d=(c)>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + Map [i + 0x400] = Map [i + 0xc00] = ROM + (d*0x10000); + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + int bankmax=0x40+ (1<<(ROMSize-6)); + //safety for corrupt headers + if(bankmax > 128) + bankmax = 0x80; + int sum=0; + for(i=0x40;i3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + + //makes more sense to map the range here. + //ToP seems to use sram to skip intro??? + if(c>=0x300) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_HIROM_SRAM; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_HIROM_SRAM; + BlockIsRAM [6 + c] = BlockIsRAM [7 + c] = + BlockIsRAM [0x806 + c]= BlockIsRAM [0x807 + c] = TRUE; + } + else + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + + } + for (i = c + 8; i < c + 16; i++) + { + Map [i] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET0]; + Map [i + 0x800] = &ROM [((c << 12) % 0x400000) + OFFSET2]; + BlockIsROM [i] = TRUE; + BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + { + Map [i + 0x400] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET1]; + Map [i + 0x408] = &ROM [((c << 12) % (CalculatedSize-0x400000)) + OFFSET1]; + Map [i + 0xc00] = &ROM [((c << 12) %0x400000)+ OFFSET2]; + Map [i + 0xc08] = &ROM [((c << 12) % 0x400000) + OFFSET2]; + BlockIsROM [i + 0x400] = TRUE; + BlockIsROM [i + 0x408] = TRUE; + BlockIsROM [i + 0xc00] = TRUE; + BlockIsROM [i + 0xc08] = TRUE; + } + } + + if((strncmp("TALES",(char*)Map[8]+0xFFC0, 5)==0)) + { + if(((*(Map[8]+0xFFDE))==(*(Map[0x808]+0xFFDE)))) + { + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + } + } + + ROMChecksum = *(Map[8]+0xFFDE) + (*(Map[8]+0xFFDF) << 8); + ROMComplementChecksum = *(Map[8]+0xFFDC) + (*(Map[8]+0xFFDD) << 8); + +int sum=0; +for(i=0x40;i<0x80; i++) +{ + uint8 * bank_low=(uint8*)Map[i<<4]; + uint8 * bank_high=(uint8*)Map[(i<<4)+0x800]; + for (c=0;c<0x10000; c++) + { + sum+=bank_low[c]; + sum+=bank_high[c]; + } +} + +CalculatedChecksum=sum&0xFFFF; + + MapRAM (); + WriteProtectROM (); +} + +void CMemory::AlphaROMMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = TRUE; + } + } + + // Banks 40->7f and c0->ff + + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map [i + 0x400] = &ROM [(c << 12) % CalculatedSize]; + Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + MapRAM (); + WriteProtectROM (); +} + +void DetectSuperFxRamSize() +{ + if(ROM[0x7FDA]==0x33) + { + Memory.SRAMSize=ROM[0x7FBD]; + } + else + { + if(strncmp(Memory.ROMName, "STAR FOX 2", 10)==0) + { + Memory.SRAMSize=6; + } + else Memory.SRAMSize=5; + } +} + +void CMemory::SuperFXROMMap () +{ + int c; + int i; + + DetectSuperFxRamSize(); + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [0x006 + c] = Map [0x806 + c] = (uint8 *) ::SRAM - 0x6000; + Map [0x007 + c] = Map [0x807 + c] = (uint8 *) ::SRAM - 0x6000; + BlockIsRAM [0x006 + c] = BlockIsRAM [0x007 + c] = BlockIsRAM [0x806 + c] = BlockIsRAM [0x807 + c] = TRUE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + // Banks 7e->7f, RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + + // Banks 70->71, S-RAM + for (c = 0; c < 32; c++) + { + Map [c + 0x700] = ::SRAM + (((c >> 4) & 1) << 16); + BlockIsRAM [c + 0x700] = TRUE; + BlockIsROM [c + 0x700] = FALSE; + } + + // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K + // block is repeated twice in each 64K block. + for (c = 0; c < 64; c++) + { + memmove (&ROM [0x200000 + c * 0x10000], &ROM [c * 0x8000], 0x8000); + memmove (&ROM [0x208000 + c * 0x10000], &ROM [c * 0x8000], 0x8000); + } + + WriteProtectROM (); +} + +void CMemory::SA1ROMMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) &Memory.FillRAM [0x3000] - 0x3000; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_BWRAM; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_BWRAM; + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + Map [i + 0x400] = (uint8 *) &SRAM [(c << 12) & 0x1ffff]; + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = FALSE; + } + } + + // c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i + 0xc00] = TRUE; + } + } + + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + WriteProtectROM (); + + // Now copy the map and correct it for the SA1 CPU. + memmove ((void *) SA1.WriteMap, (void *) WriteMap, sizeof (WriteMap)); + memmove ((void *) SA1.Map, (void *) Map, sizeof (Map)); + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000]; + SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8 *) MAP_NONE; + SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000]; + SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8 *) MAP_NONE; + } + + // Banks 60->6f + for (c = 0; c < 0x100; c++) + SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8 *) MAP_BWRAM_BITMAP; + + BWRAM = SRAM; +} + +void CMemory::LoROM24MBSMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x200; c += 16) + { + Map [c + 0x800] = RAM; + Map [c + 0x801] = RAM; + BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 0x807] = (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i + 0x800] = &ROM [c << 11] - 0x8000 + 0x200000; + BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000]; + + for (i = c + 8; i < c + 16; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000]; + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + MapExtraRAM (); + WriteProtectROM (); +} + +void CMemory::SufamiTurboLoROMMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000]; + + for (i = c + 8; i < c + 16; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000]; + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + if (Settings.DSP1Master) + { + for (c = 0; c < 0x100; c++) + { + Map [c + 0xe00] = (uint8 *) MAP_DSP; + BlockIsROM [c + 0xe00] = FALSE; + } + } + + // Banks 7e->7f, RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + + // Banks 60->67, S-RAM + for (c = 0; c < 0x80; c++) + { + Map [c + 0x600] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [c + 0x600] = TRUE; + BlockIsROM [c + 0x600] = FALSE; + } + + WriteProtectROM (); +} + +#if 0 + +//untested!! +void CMemory::SameGameMap () +{ + int i; + int c; + int j; + + int mask[4]; + int mask2[4]; + for (j=0; j<4; j++) + mask[j]=mask2[j]=0x00ff; + + mask[0]=(CalculatedSize/0x10000)-1; + mask2[0]=(Slot1Size/0x10000)-1; + + int x; + bool foundZeros; + bool pastZeros; + + for(j=0;j<3;j++) + { + x=1; + foundZeros=false; + pastZeros=false; + + mask[j+1]=mask[j]; + + while (x>0x100&&!pastZeros) + { + if(mask[j]&x) + { + x<<=1; + if(foundZeros) + pastZeros=true; + } + else + { + foundZeros=true; + pastZeros=false; + mask[j+1]|=x; + x<<=1; + } + } + } + + for(j=0;j<3;j++) + { + x=1; + foundZeros=false; + pastZeros=false; + + mask2[j+1]=mask2[j]; + + while (x>0x100&&!pastZeros) + { + if(mask2[j]&x) + { + x<<=1; + if(foundZeros) + pastZeros=true; + } + else + { + foundZeros=true; + pastZeros=false; + mask2[j+1]|=x; + x<<=1; + } + } + } + + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + } + + // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM. + for (c = 0; c < 16; c++) + { + Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0xb06 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0xb07 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + BlockIsRAM [0x306 + (c << 4)] = TRUE; + BlockIsRAM [0x307 + (c << 4)] = TRUE; + BlockIsRAM [0xb06 + (c << 4)] = TRUE; + BlockIsRAM [0xb07 + (c << 4)] = TRUE; + } + + for c=0; c<0x200; c+=16) + { + for(i=0;i<8;i++) + { + int e=3; + int d=c>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + + int f=3; + int g=c>>4; + while(g>mask2[0]) + { + g&=mask2[f]; + f--; + } + + //stuff in HiROM areas + Map[c+0x400+i]=&ROM[d*0x10000]; + Map[c+0xC00+i]=&ROM[d*0x10000]; + //MINI + Map[c+0x600+i]=&ROMOffset1[g*0x10000]; + Map[c+0xE00+i]=&ROMOffset1[g*0x10000]; + + } + for(i=8;i<16;i++) + { + int e=3; + int d=c>>4; + while(d>mask[0]) + { + d&=mask[e]; + e--; + } + + int f=3; + int g=c>>4; + while(g>mask2[0]) + { + g&=mask2[f]; + f--; + } + + + //all stuff + //BASE + Map[c+i]=&ROM[d*0x10000]; + Map[c+0x800+i]=&ROM[d*0x10000]; + Map[c+0x400+i]=&ROM[d*0x10000]; + Map[c+0xC00+i]=&ROM[d*0x10000]; + //MINI + Map[c+0x200+i]=&ROMOffset1[g*0x10000]; + Map[c+0xA00+i]=&ROMOffset1[g*0x10000]; + Map[c+0x600+i]=&ROMOffset1[g*0x10000]; + Map[c+0xE00+i]=&ROMOffset1[g*0x10000]; + } + + } + + int bankmax=0x40+ (1<<(ROMSize-6)); + //safety for corrupt headers + if(bankmax > 128) + bankmax = 0x80; + int sum=0; + for(i=0x40;i3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) &Memory.FillRAM [0x3000] - 0x3000; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_BWRAM; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_BWRAM; + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + + // Banks 40->4f (was 7f, but SNES docs and GNext overdumping shows nothing here.) + for (c = 0; c < 0x100; c += 16) + { + for (i = c; i < c + 16; i++) + Map [i + 0x400] = (uint8 *) &SRAM [(c << 12) & 0x1ffff]; + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = FALSE; + } + } + + for (c = 0; c < 0x100; c += 16) + { + for (i = c; i < c + 16; i++) + Map [i + 0x700] = (uint8 *) &ROMOffset1 [(c << 12) & (Slot1Size-1)]; + } + + // c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i + 0xc00] = TRUE; + } + } + + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + WriteProtectROM (); + + // Now copy the map and correct it for the SA1 CPU. + memmove ((void *) SA1.WriteMap, (void *) WriteMap, sizeof (WriteMap)); + memmove ((void *) SA1.Map, (void *) Map, sizeof (Map)); + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + SA1.Map [c + 0] = SA1.Map [c + 0x800] = &Memory.FillRAM [0x3000]; + SA1.Map [c + 1] = SA1.Map [c + 0x801] = (uint8 *) MAP_NONE; + SA1.WriteMap [c + 0] = SA1.WriteMap [c + 0x800] = &Memory.FillRAM [0x3000]; + SA1.WriteMap [c + 1] = SA1.WriteMap [c + 0x801] = (uint8 *) MAP_NONE; + } + + // Banks 60->6f + for (c = 0; c < 0x100; c++) + SA1.Map [c + 0x600] = SA1.WriteMap [c + 0x600] = (uint8 *) MAP_BWRAM_BITMAP; + + BWRAM = SRAM; +} + +void CMemory::SufamiTurboAltROMMap () +{ + int c; + int i; + + if(Slot1Size!=0) + Slot1SRAMSize=(1<<((uint8)ROMOffset1[0x32]))*1024; + else Slot1Size=0x8000; + if(Slot2Size!=0) + Slot2SRAMSize=(1<<((uint8)ROMOffset2[0x32]))*1024; +else Slot2Size=0x8000; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + +// for (i = c + 8; i < c + 16; i++) +// { +// Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; +// BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; +// } + + } + + //Map Bios + + for (c=0; c<0x200; c+=16) + { + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [((c>>4)*0x8000)%CalculatedSize] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + + } + + + for (c=0x200; c<0x400; c+=16) + { + for (i = c + 8; i < c + 16; i++) + { + if(Slot1Size!=0) + { + Map [i] = Map [i + 0x800] = &ROMOffset1 [(((c>>4)*0x8000)%Slot1Size)] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE; + } + + } + + for (c=0x400; c<0x600; c+=16) + { + for (i = c; i < c + 8; i++) + { + if(Slot2Size!=0) + { + Map [i] = Map [i + 0x800] = &ROMOffset2[(((c>>4)*0x8000)%Slot2Size)]; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE; + + } + for (i = c + 8; i < c + 16; i++) + { + if(Slot2Size!=0) + { + Map [i] = Map [i + 0x800] = &ROMOffset2[(((c>>4)*0x8000)%Slot2Size)] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + else Map [i] = Map [i + 0x800] = (uint8*)MAP_NONE; + + } + + } + + // Banks 60->67 (7F?), S-RAM + if(Slot1SRAMSize!=0) + { + for (c = 0; c < 0x100; c++) + { + Map [c + 0xE00] = Map [c + 0x600] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [c + 0xE00] = BlockIsRAM [c + 0x600] = TRUE; + BlockIsROM [c + 0xE00] = BlockIsROM [c + 0x600] = FALSE; + } + } + if(Slot2SRAMSize!=0) + { + for (c = 0; c < 0x100; c++) + { + Map [c + 0xF00] = Map [c + 0x700] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [c + 0xF00] = BlockIsRAM [c + 0x700] = TRUE; + BlockIsROM [c + 0xF00] = BlockIsROM [c + 0x700] = FALSE; + } + } + + // Banks 7e->7f, RAM + for (c = 0; c < 16; c++) + { + Map [c + 0x7e0] = RAM; + Map [c + 0x7f0] = RAM + 0x10000; + BlockIsRAM [c + 0x7e0] = TRUE; + BlockIsRAM [c + 0x7f0] = TRUE; + BlockIsROM [c + 0x7e0] = FALSE; + BlockIsROM [c + 0x7f0] = FALSE; + } + + WriteProtectROM (); +} +#endif + + +void CMemory::SRAM512KLoROMMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [c << 11] - 0x8000; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 8; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000]; + + for (i = c + 8; i < c + 16; i++) + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 11) + 0x200000 - 0x8000]; + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + MapExtraRAM (); + WriteProtectROM (); +} + +void CMemory::JumboLoROMMap (bool8 Interleaved) +{ + int c; + int i; + + uint32 OFFSET0 = 0x400000; + uint32 OFFSET1 = 0x400000; + uint32 OFFSET2 = 0x000000; + + if (Interleaved) + { + OFFSET0 = 0x000000; + OFFSET1 = 0x000000; + OFFSET2 = CalculatedSize-0x400000; //changed to work with interleaved DKJM2. + } + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + if (Settings.DSP1Master) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_DSP; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_DSP; + } + else if (Settings.C4) + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_C4; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_C4; + } + else + { + Map [c + 6] = Map [c + 0x806] = (uint8 *) MAP_NONE; + Map [c + 7] = Map [c + 0x807] = (uint8 *) MAP_NONE; + } + + for (i = c + 8; i < c + 16; i++) + { + Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0] - 0x8000; + Map [i + 0x800] = &ROM [((c << 11) % (0x400000)) + OFFSET2] - 0x8000; + BlockIsROM [i + 0x800] = BlockIsROM [i] = TRUE; + } + } + + if (Settings.DSP1Master) + { + // Banks 30->3f and b0->bf + for (c = 0x300; c < 0x400; c += 16) + { + for (i = c + 8; i < c + 16; i++) + { + Map [i + 0x800] = (uint8 *) MAP_DSP; + BlockIsROM [i] = BlockIsROM [i + 0x800] = FALSE; + } + } + } + + // Banks 40->7f and c0->ff + for (c = 0x400; c < 0x800; c += 16) + { + //updated mappings to correct A15 mirroring + for (i = c; i < c + 8; i++) + { + Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0]; + Map [i + 0x800] = &ROM [((c << 11) % 0x400000) +OFFSET2]; + } + + for (i = c + 8; i < c + 16; i++) + { + Map [i]= &ROM [((c << 11) % (CalculatedSize - 0x400000)) + OFFSET0] - 0x8000; + Map [i + 0x800] = &ROM [((c << 11) % 0x400000) + OFFSET2 ] - 0x8000; + } + + for (i = c; i < c + 16; i++) + { + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + //ROM type has to be 64 Mbit header! + int sum=0, k,l; + for(k=0;k<256;k++) + { + uint8* bank=0x8000+Map[8+(k<<4)];//use upper half of the banks, and adjust for LoROM. + for(l=0;l<0x8000;l++) + sum+=bank[l]; + } + CalculatedChecksum=sum&0xFFFF; + + MapRAM (); + WriteProtectROM (); +} + +void CMemory::SPC7110HiROMMap () +{ + int c; + int i; + + // Banks 00->3f and 80->bf + for (c = 0; c < 0x400; c += 16) + { + Map [c + 0] = Map [c + 0x800] = RAM; + BlockIsRAM [c + 0] = BlockIsRAM [c + 0x800] = TRUE; + Map [c + 1] = Map [c + 0x801] = RAM; + BlockIsRAM [c + 1] = BlockIsRAM [c + 0x801] = TRUE; + + Map [c + 2] = Map [c + 0x802] = (uint8 *) MAP_PPU; + Map [c + 3] = Map [c + 0x803] = (uint8 *) MAP_PPU; + Map [c + 4] = Map [c + 0x804] = (uint8 *) MAP_CPU; + Map [c + 5] = Map [c + 0x805] = (uint8 *) MAP_CPU; + + Map [c + 6] /*= Map [c + 0x806]*/ = (uint8 *) MAP_HIROM_SRAM; + Map [c + 7] /*= Map [c + 0x807]*/ = (uint8 *) MAP_HIROM_SRAM; + Map [c + 0x806]=Map [c + 0x807]= (uint8 *) MAP_NONE; + + for (i = c + 8; i < c + 16; i++) + { + Map [i] = Map [i + 0x800] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i] = BlockIsROM [i + 0x800] = TRUE; + } + } + + // Banks 30->3f and b0->bf, address ranges 6000->7fff is S-RAM. + for (c = 0; c < 16; c++) + { + Map [0x306 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0x307 + (c << 4)] = (uint8 *) MAP_HIROM_SRAM; + Map [0xb06 + (c << 4)] = (uint8 *) MAP_NONE; + Map [0xb07 + (c << 4)] = (uint8 *) MAP_NONE; + BlockIsRAM [0x306 + (c << 4)] = TRUE; + BlockIsRAM [0x307 + (c << 4)] = TRUE; + // BlockIsRAM [0xb06 + (c << 4)] = TRUE; + // BlockIsRAM [0xb07 + (c << 4)] = TRUE; + } + + // Banks 40->7f and c0->ff + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map [i + 0x400] = Map [i + 0xc00] = &ROM [(c << 12) % CalculatedSize]; + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = TRUE; + } + } + + for (c=0;c<0x10;c++) + { + Map [0x500+c]=(uint8 *)MAP_SPC7110_DRAM; + BlockIsROM [0x500+c]=TRUE; + } + + for (c=0;c<0x100;c++) + { + Map [0xD00+c] = (uint8 *) MAP_SPC7110_ROM; + Map [0xE00+c] = (uint8 *) MAP_SPC7110_ROM; + Map [0xF00+c] = (uint8 *) MAP_SPC7110_ROM; + BlockIsROM [0xD00+c] = BlockIsROM [0xE00+c] = BlockIsROM [0xF00+c] = TRUE; + + } + S9xSpc7110Init(); + +int sum=0; +for(i=0;i<(int)CalculatedSize; i++) +{ + sum+=ROM[i]; +} + +if(CalculatedSize==0x300000) + sum<<=1; +CalculatedChecksum=sum&0xFFFF; + + MapRAM (); + WriteProtectROM (); +} +void CMemory::SPC7110Sram(uint8 newstate) +{ + if(newstate&0x80) + { + Memory.Map[6]=(uint8 *)MAP_HIROM_SRAM; + Memory.Map[7]=(uint8 *)MAP_HIROM_SRAM; + Memory.Map[0x306]=(uint8 *)MAP_HIROM_SRAM; + Memory.Map[0x307]=(uint8 *)MAP_HIROM_SRAM; + + + } + else + { + Memory.Map[6]=(uint8 *)MAP_RONLY_SRAM; + Memory.Map[7]=(uint8 *)MAP_RONLY_SRAM; + Memory.Map[0x306]=(uint8 *)MAP_RONLY_SRAM; + Memory.Map[0x307]=(uint8 *)MAP_RONLY_SRAM; + } +} +const char *CMemory::TVStandard () +{ + return (Settings.PAL ? "PAL" : "NTSC"); +} + +const char *CMemory::Speed () +{ + return (ROMSpeed & 0x10 ? "120ns" : "200ns"); +} + +const char *CMemory::MapType () +{ + return (HiROM ? "HiROM" : "LoROM"); +} + +const char *CMemory::StaticRAMSize () +{ + static char tmp [20]; + + if (Memory.SRAMSize > 16) + return ("Corrupt"); + sprintf (tmp, "%dKB", (SRAMMask + 1) / 1024); + return (tmp); +} + +const char *CMemory::Size () +{ + static char tmp [20]; + + if (ROMSize < 7 || ROMSize - 7 > 23) + return ("Corrupt"); + sprintf (tmp, "%dMbits", 1 << (ROMSize - 7)); + return (tmp); +} + +const char *CMemory::KartContents () +{ + static char tmp [30]; + static const char *CoPro [16] = { + "DSP", "SuperFX", "OBC1", "SA-1", "S-DD1", "S-RTC", "CoPro#6", + "CoPro#7", "CoPro#8", "CoPro#9", "CoPro#10", "CoPro#11", "CoPro#12", + "CoPro#13", "CoPro#14", "CoPro-Custom" + }; + static const char *Contents [3] = { + "ROM", "ROM+RAM", "ROM+RAM+BAT" + }; + static const char *DSPSel [4] = { + "DSP1", "DSP2", "DSP3", "DSP4" + }; + if (ROMType == 0&&!Settings.BS) + return ("ROM only"); + + sprintf (tmp, "%s", Contents [(ROMType & 0xf) % 3]); + + if(Settings.BS) + sprintf (tmp, "%s+%s", tmp, "BSX"); + else if(Settings.SPC7110&&Settings.SPC7110RTC) + sprintf (tmp, "%s+%s", tmp, "SPC7110+RTC"); + else if(Settings.SPC7110) + sprintf (tmp, "%s+%s", tmp, "SPC7110"); + else if(Settings.C4) + sprintf (tmp, "%s+%s", tmp, "C4"); + else if(Settings.SETA!=0) + { + switch(Settings.SETA) + { + case ST_010: + sprintf (tmp, "%s+%s", tmp, "ST-010"); + break; + case ST_011: + sprintf (tmp, "%s+%s", tmp, "ST-011"); + break; + + case ST_018: + sprintf (tmp, "%s+%s", tmp, "ST-018"); + break; + + } + } + else if ((ROMType & 0xf) >= 3) + { + if (ROMType & 0xf0) + sprintf (tmp, "%s+%s", tmp, CoPro [(ROMType & 0xf0) >> 4]); + else + sprintf (tmp, "%s+%s", tmp, DSPSel [DSP1.version]); + } + + return (tmp); +} + +const char *CMemory::MapMode () +{ + static char tmp [4]; + sprintf (tmp, "%02x", ROMSpeed & ~0x10); + return (tmp); +} + +const char *CMemory::ROMID () +{ + return (ROMId); +} + +void CMemory::ApplyROMFixes () +{ +#ifdef __W32_HEAP + if(_HEAPOK!=_heapchk()) + MessageBox(GUI.hWnd, "CMemory::ApplyROMFixes", "Heap Corrupt", MB_OK); +#endif + + //don't steal my work! -MK + if(ROMCRC32 == 0x1B4A5616 && strncmp(ROMName, "RUDORA NO HIHOU", 15)==0) + { + strncpy(ROMName, "THIS SCRIPT WAS STOLEN", 22); + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + } + + /* + HACKS NSRT can fix that we hadn't detected before. +[14:25:13] <@Nach> case 0x0c572ef0: //So called Hook (US)(2648) +[14:25:13] <@Nach> case 0x6810aa95: //Bazooka Blitzkreig swapped sizes hack -handled +[14:25:17] <@Nach> case 0x61E29C06: //The Tick region hack +[14:25:19] <@Nach> case 0x1EF90F74: //Jikkyou Keiba Simulation Stable Star PAL hack +[14:25:23] <@Nach> case 0x4ab225b5: //So called Krusty's Super Fun House (E) +[14:25:25] <@Nach> case 0x77fd806a: //Donkey Kong Country 2 (E) v1.1 bad dump -handled +[14:25:27] <@Nach> case 0x340f23e5: //Donkey Kong Country 3 (U) copier hack - handled + */ + + if(ROMCRC32==0x6810aa95 || ROMCRC32==0x340f23e5 || ROMCRC32==0x77fd806a || + strncmp (ROMName, "HIGHWAY BATTLE 2", 16)==0 || + (strcmp (ROMName, "FX SKIING NINTENDO 96") == 0 && ROM[0x7FDA]==0)) + { + Settings.DisplayColor=BUILD_PIXEL(31,0,0); + SET_UI_COLOR(255,0,0); + } + + //Ambiguous chip function pointer assignments + DSP1.version=0; + + //DSP switching: + if(strncmp(ROMName, "DUNGEON MASTER", 14)==0) + { + //Set DSP-2 + DSP1.version=1; + SetDSP=&DSP2SetByte; + GetDSP=&DSP2GetByte; + } + + if(strncmp(ROMName, "SD\x0b6\x0de\x0dd\x0c0\x0de\x0d1GX", 10)==0) // SD Gundam GX + { + //Set DSP-3 + DSP1.version=2; + SetDSP = &DSP3SetByte; + GetDSP = &DSP3GetByte; + DSP3_Reset(); + } + + if(strncmp(ROMName, "TOP GEAR 3000", 13)==0 + ||strncmp(ROMName, "PLANETS CHAMP TG3000", 20)==0) + { + //Set DSP-4 + DSP1.version=3; + SetDSP=&DSP4SetByte; + GetDSP=&DSP4GetByte; + // FIXME: memory map correction + for (int c = 0; c < 0x400; c += 16) + { + Map[c + 6] = Map[c + 0x806] = (uint8 *) MAP_NONE; + Map[c + 7] = Map[c + 0x807] = (uint8 *) MAP_NONE; + } + WriteProtectROM(); + } + + //memory map corrections + if(strncmp(ROMName, "XBAND",5)==0) + { + for (int c=0xE00;c<0xE10;c++) + { + Map [c] = (uint8 *) MAP_LOROM_SRAM; + BlockIsRAM [c] = TRUE; + BlockIsROM [c] = FALSE; + } + WriteProtectROM (); + } + + //not MAD-1 compliant + if(strcmp (ROMName, "WANDERERS FROM YS") == 0) + { + for(int c=0;c<0xE0;c++) + { + Map[c+0x700]=(uint8*)MAP_LOROM_SRAM; + BlockIsROM[c+0x700]=FALSE; + BlockIsRAM[c+0x700]=TRUE; + } + WriteProtectROM(); + } + +#if 0 +// These two games don't have SRAM. Sounds like OpenBus issue... + if (strcmp (ROMName, "GOGO ACKMAN3") == 0 || + strcmp (ROMName, "HOME ALONE") == 0) + { + // Banks 00->3f and 80->bf + for (int c = 0; c < 0x400; c += 16) + { + Map [c + 6] = Map [c + 0x806] = SRAM; + Map [c + 7] = Map [c + 0x807] = SRAM; + BlockIsROM [c + 6] = BlockIsROM [c + 0x806] = FALSE; + BlockIsROM [c + 7] = BlockIsROM [c + 0x807] = FALSE; + BlockIsRAM [c + 6] = BlockIsRAM [c + 0x806] = TRUE; + BlockIsRAM [c + 7] = BlockIsRAM [c + 0x807] = TRUE; + } + WriteProtectROM (); + } +#endif + + if (strncmp (ROMName, "BATMAN--REVENGE JOKER", 21) == 0) + { + Memory.HiROM = FALSE; + Memory.LoROM = TRUE; + LoROMMap (); + } + + // Force Disabling a speed-up hack (CPU_Shutdown()) + // Games which spool sound samples between the SNES and sound CPU using + // H-DMA as the sample is playing. + if (strcmp (ROMName, "EARTHWORM JIM 2") == 0 || + strcmp (ROMName, "PRIMAL RAGE") == 0 || + strcmp (ROMName, "CLAY FIGHTER") == 0 || + strcmp (ROMName, "ClayFighter 2") == 0 || + strncasecmp (ROMName, "MADDEN", 6) == 0 || + strncmp (ROMName, "NHL", 3) == 0 || + strcmp (ROMName, "WeaponLord") == 0 || + strncmp(ROMName, "WAR 2410", 8) == 0 || + strncmp (ROMId, "ARF", 3) == 0) // Star Ocean + { + Settings.Shutdown = FALSE; + } + + //APU timing hacks + + // Stunt Racer FX + if (strcmp (ROMId, "CQ ") == 0 || + // Illusion of Gaia + strncmp (ROMId, "JG", 2) == 0 || + strcmp (ROMName, "GAIA GENSOUKI 1 JPN") == 0) + { + IAPU.OneCycle = 13; + } + + // RENDERING RANGER R2 + if (strcmp (ROMId, "AVCJ") == 0 || + //Mark Davis + strncmp(ROMName, "THE FISHING MASTER", 18)==0 || //needs >= actual APU timing. (21 is .002 Mhz slower) + // Star Ocean + strncmp (ROMId, "ARF", 3) == 0 || + // Tales of Phantasia + strncmp (ROMId, "ATV", 3) == 0 || + // Act Raiser 1 & 2 + strncasecmp (ROMName, "ActRaiser", 9) == 0 || + // Soulblazer + strcmp (ROMName, "SOULBLAZER - 1 USA") == 0 || + strcmp (ROMName, "SOULBLADER - 1") == 0 || + + // Terranigma + strncmp (ROMId, "AQT", 3) == 0 || + // Robotrek + strncmp (ROMId, "E9 ", 3) == 0 || + strcmp (ROMName, "SLAP STICK 1 JPN") == 0 || + // ZENNIHON PURORESU2 + strncmp (ROMId, "APR", 3) == 0 || + // Bomberman 4 + strncmp (ROMId, "A4B", 3) == 0 || + // UFO KAMEN YAKISOBAN + strncmp (ROMId, "Y7 ", 3) == 0 || + strncmp (ROMId, "Y9 ", 3) == 0 || + // Panic Bomber World + strncmp (ROMId, "APB", 3) == 0 || + ((strncmp (ROMName, "Parlor", 6) == 0 || + strcmp (ROMName, "HEIWA Parlor!Mini8") == 0 || + strncmp (ROMName, "SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!", 21) == 0) && //SANKYO Fever! Fever! + strcmp (CompanyId, "A0") == 0) || + strcmp (ROMName, "DARK KINGDOM") == 0 || + strcmp (ROMName, "ZAN3 SFC") == 0 || + strcmp (ROMName, "HIOUDEN") == 0 || + strcmp (ROMName, "\xC3\xDD\xBC\xC9\xB3\xC0") == 0 || //Tenshi no Uta + strcmp (ROMName, "FORTUNE QUEST") == 0 || + strcmp (ROMName, "FISHING TO BASSING") == 0 || + strncmp (ROMName, "TokyoDome '95Battle 7", 21) == 0 || + strcmp (ROMName, "OHMONO BLACKBASS") == 0 || + strncmp (ROMName, "SWORD WORLD SFC", 15) == 0 || + strcmp (ROMName, "MASTERS") ==0 || //Augusta 2 J + strcmp (ROMName, "SFC \xB6\xD2\xDD\xD7\xB2\xC0\xDE\xB0") == 0 || //Kamen Rider + strcmp (ROMName, "ZENKI TENCHIMEIDOU") == 0 || + strncmp (ROMName, "LETs PACHINKO(", 14) == 0) //A set of BS games + { + IAPU.OneCycle = 15; + } + + //Specific game fixes + + // for ZSNES SuperFX: is it still necessary? + Settings.WinterGold = strcmp (ROMName, "FX SKIING NINTENDO 96") == 0 || + strcmp (ROMName, "DIRT RACER") == 0; + + //OAM hacks because we don't fully understand the + //behavior of the SNES. + //Totally wacky display... + //seems to need a disproven behavior, so + //we're definitely overlooking some other bug? + if(strncmp(ROMName, "UNIRACERS", 9)==0) + SNESGameFixes.Uniracers=true; + +#if 0 + if (strcmp (ROMName, "\xBD\xB0\xCA\xDF\xB0\xCC\xA7\xD0\xBD\xC0") == 0 || //Super Famista + strcmp (ROMName, "\xBD\xB0\xCA\xDF\xB0\xCC\xA7\xD0\xBD\xC0 2") == 0 || //Super Famista 2 + strcmp (ROMName, "GANBA LEAGUE") == 0) + { + SNESGameFixes.APU_OutPorts_ReturnValueFix = TRUE; + } +#endif + + //CPU timing hacks + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * Settings.CyclesPercentage) / 100; + Timings.HBlankStart = SNES_HBLANK_START_HC; + Timings.HDMAStart = SNES_HDMA_START_HC; + Timings.RenderPos = SNES_RENDER_START_HC; + + //The first new hack since timings were changed :( + if (strncmp(ROMName, "SeikenDensetsu 2", 16) == 0 || + strncmp(ROMName, "Secret of MANA", 14) == 0) + { + Timings.HBlankStart -= 34; + Timings.HDMAStart -= 34; + } + +/* if(strcmp(ROMName, "HOME IMPROVEMENT")==0) + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 200) / 100; + + if (strcmp (ROMId, "ASRJ") == 0 && Settings.CyclesPercentage == 100) + // Street Racer + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 95) / 100; + + // Power Rangers Fight + if (strncmp (ROMId, "A3R", 3) == 0 || + // Clock Tower + strncmp (ROMId, "AJE", 3) == 0) + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 103) / 100; + + if (strncmp (ROMId, "A3M", 3) == 0 && Settings.CyclesPercentage == 100) + // Mortal Kombat 3. Fixes cut off speech sample + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100; + + //Darkness Beyond Twilight + //Crimson beyond blood that flows + //buried in the stream of time + //is where your power grows + //I pledge myself to conquer + //all the foes who stand + //before the might gift betsowed + //in my unworthy hand + if (strcmp (ROMName, "\x0bd\x0da\x0b2\x0d4\x0b0\x0bd\x0de") == 0 && + Settings.CyclesPercentage == 100) + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 101) / 100; + // Start Trek: Deep Sleep 9 + if (strncmp (ROMId, "A9D", 3) == 0 && Settings.CyclesPercentage == 100) + Timings.H_Max = (SNES_CYCLES_PER_SCANLINE * 110) / 100; +*/ + Timings.H_Max_Master = Timings.H_Max; + + //SA-1 Speedup settings + SA1.WaitAddress = 0xffffffff; + SA1.WaitByteAddress1 = NULL; + SA1.WaitByteAddress2 = NULL; + + /* Bass Fishing */ + if (strcmp (ROMId, "ZBPJ") == 0) + { + SA1.WaitAddress = 0x0093f1; + SA1.WaitByteAddress1 = FillRAM + 0x304a; + } + /* DAISENRYAKU EXPERTWW2 */ + if (strcmp (ROMId, "AEVJ") == 0) + { + SA1.WaitAddress = 0x0ed18d; + SA1.WaitByteAddress1 = FillRAM + 0x3000; + } + /* debjk2 */ + if (strcmp (ROMId, "A2DJ") == 0) + { + SA1.WaitAddress = 0x008b62; + } + /* Dragon Ballz HD */ + if (strcmp (ROMId, "AZIJ") == 0) + { + SA1.WaitAddress = 0x008083; + SA1.WaitByteAddress1 = FillRAM + 0x3020; + } + /* SFC SDGUNDAMGNEXT */ + if (strcmp (ROMId, "ZX3J") == 0) + { + SA1.WaitAddress = 0x0087f2; + SA1.WaitByteAddress1 = FillRAM + 0x30c4; + } + /* ShougiNoHanamichi */ + if (strcmp (ROMId, "AARJ") == 0) + { + SA1.WaitAddress = 0xc1f85a; + SA1.WaitByteAddress1 = SRAM + 0x0c64; + SA1.WaitByteAddress2 = SRAM + 0x0c66; + } + /* KATO HIFUMI9DAN SYOGI */ + if (strcmp (ROMId, "A23J") == 0) + { + SA1.WaitAddress = 0xc25037; + SA1.WaitByteAddress1 = SRAM + 0x0c06; + SA1.WaitByteAddress2 = SRAM + 0x0c08; + } + /* idaten */ + if (strcmp (ROMId, "AIIJ") == 0) + { + SA1.WaitAddress = 0xc100be; + SA1.WaitByteAddress1 = SRAM + 0x1002; + SA1.WaitByteAddress2 = SRAM + 0x1004; + } + /* igotais */ + if (strcmp (ROMId, "AITJ") == 0) + { + SA1.WaitAddress = 0x0080b7; + } + /* J96 DREAM STADIUM */ + if (strcmp (ROMId, "AJ6J") == 0) + { + SA1.WaitAddress = 0xc0f74a; + } + /* JumpinDerby */ + if (strcmp (ROMId, "AJUJ") == 0) + { + SA1.WaitAddress = 0x00d926; + } + /* JKAKINOKI SHOUGI */ + if (strcmp (ROMId, "AKAJ") == 0) + { + SA1.WaitAddress = 0x00f070; + } + /* HOSHI NO KIRBY 3 & KIRBY'S DREAM LAND 3 JAP & US */ + if (strcmp (ROMId, "AFJJ") == 0 || strcmp (ROMId, "AFJE") == 0) + { + SA1.WaitAddress = 0x0082d4; + SA1.WaitByteAddress1 = SRAM + 0x72a4; + } + /* KIRBY SUPER DELUXE JAP */ + if (strcmp (ROMId, "AKFJ") == 0) + { + SA1.WaitAddress = 0x008c93; + SA1.WaitByteAddress1 = FillRAM + 0x300a; + SA1.WaitByteAddress2 = FillRAM + 0x300e; + } + /* KIRBY SUPER DELUXE US */ + if (strcmp (ROMId, "AKFE") == 0) + { + SA1.WaitAddress = 0x008cb8; + SA1.WaitByteAddress1 = FillRAM + 0x300a; + SA1.WaitByteAddress2 = FillRAM + 0x300e; + } + /* SUPER MARIO RPG JAP & US */ + if (strcmp (ROMId, "ARWJ") == 0 || strcmp (ROMId, "ARWE") == 0) + { + SA1.WaitAddress = 0xc0816f; + SA1.WaitByteAddress1 = FillRAM + 0x3000; + } + /* marvelous.zip */ + if (strcmp (ROMId, "AVRJ") == 0) + { + SA1.WaitAddress = 0x0085f2; + SA1.WaitByteAddress1 = FillRAM + 0x3024; + } + /* AUGUSTA3 MASTERS NEW */ + if (strcmp (ROMId, "AO3J") == 0) + { + SA1.WaitAddress = 0x00dddb; + SA1.WaitByteAddress1 = FillRAM + 0x37b4; + } + /* OSHABERI PARODIUS */ + if (strcmp (ROMId, "AJOJ") == 0) + { + SA1.WaitAddress = 0x8084e5; + } + /* PANIC BOMBER WORLD */ + if (strcmp (ROMId, "APBJ") == 0) + { + SA1.WaitAddress = 0x00857a; + } + /* PEBBLE BEACH NEW */ + if (strcmp (ROMId, "AONJ") == 0) + { + SA1.WaitAddress = 0x00df33; + SA1.WaitByteAddress1 = FillRAM + 0x37b4; + } + /* PGA EUROPEAN TOUR */ + if (strcmp (ROMId, "AEPE") == 0) + { + SA1.WaitAddress = 0x003700; + SA1.WaitByteAddress1 = FillRAM + 0x3102; + } + /* PGA TOUR 96 */ + if (strcmp (ROMId, "A3GE") == 0) + { + SA1.WaitAddress = 0x003700; + SA1.WaitByteAddress1 = FillRAM + 0x3102; + } + /* POWER RANGERS 4 */ + if (strcmp (ROMId, "A4RE") == 0) + { + SA1.WaitAddress = 0x009899; + SA1.WaitByteAddress1 = FillRAM + 0x3000; + } + /* PACHISURO PALUSUPE */ + if (strcmp (ROMId, "AGFJ") == 0) + { + // Never seems to turn on the SA-1! + } + /* SD F1 GRAND PRIX */ + if (strcmp (ROMId, "AGFJ") == 0) + { + SA1.WaitAddress = 0x0181bc; + } + /* SHOUGI MARJONG */ + if (strcmp (ROMId, "ASYJ") == 0) + { + SA1.WaitAddress = 0x00f2cc; + SA1.WaitByteAddress1 = SRAM + 0x7ffe; + SA1.WaitByteAddress2 = SRAM + 0x7ffc; + } + /* shogisai2 */ + if (strcmp (ROMId, "AX2J") == 0) + { + SA1.WaitAddress = 0x00d675; + } + + /* SHINING SCORPION */ + if (strcmp (ROMId, "A4WJ") == 0) + { + SA1.WaitAddress = 0xc048be; + } + /* SHIN SHOUGI CLUB */ + if (strcmp (ROMId, "AHJJ") == 0) + { + SA1.WaitAddress = 0xc1002a; + SA1.WaitByteAddress1 = SRAM + 0x0806; + SA1.WaitByteAddress2 = SRAM + 0x0808; + } + + + //Other + + // Additional game fixes by sanmaiwashi ... + if (strcmp (ROMName, "SFX \xC5\xB2\xC4\xB6\xDE\xDD\xC0\xDE\xD1\xD3\xC9\xB6\xDE\xC0\xD8 1") == 0) // Gundam Knight Story + { +// bytes0x2000 [0xb18] = 0x4c; +// bytes0x2000 [0xb19] = 0x4b; +// bytes0x2000 [0xb1a] = 0xea; + SNESGameFixes.SRAMInitialValue = 0x6b; + } + + + // HITOMI3 + if (strcmp (ROMName, "HITOMI3") == 0) + { + Memory.SRAMSize = 1; + SRAMMask = Memory.SRAMSize ? + ((1 << (Memory.SRAMSize + 3)) * 128) - 1 : 0; + } + + //sram value fixes + if (strcmp (Memory.ROMName, "SUPER DRIFT OUT") == 0 || + strcmp(Memory.ROMName, "SATAN IS OUR FATHER!") == 0 || + strcmp (ROMName, "goemon 4") == 0) + SNESGameFixes.SRAMInitialValue = 0x00; + +#if 0 + if(strcmp (ROMName, "XBAND JAPANESE MODEM") == 0) + { + for (c = 0x200; c < 0x400; c += 16) + { + for (int i = c; i < c + 16; i++) + { + Map [i + 0x400] = Map [i + 0xc00] = &ROM[c * 0x1000]; + BlockIsRAM [i + 0x400] = BlockIsRAM [i + 0xc00] = TRUE; + BlockIsROM [i + 0x400] = BlockIsROM [i + 0xc00] = FALSE; + } + } + WriteProtectROM (); + } +#endif + +#if 0 +// XXX: wait-and-see... +#define RomPatch(adr,ov,nv) \ + if (ROM [adr] == ov) \ + ROM [adr] = nv + + // Love Quest + if (strcmp (ROMName, "LOVE QUEST") == 0) + { + RomPatch (0x1385ec, 0xd0, 0xea); + RomPatch (0x1385ed, 0xb2, 0xea); + } + //BNE D0 into nops + + //this is a cmp on $00:2140 + // Super Batter Up + if (strcmp (ROMName, "Super Batter Up") == 0) + { + RomPatch (0x27ae0, 0xd0, 0xea); + RomPatch (0x27ae1, 0xfa, 0xea); + } + //BNE +#endif +} + +#ifndef NGC +// Read variable size MSB int from a file +static long ReadInt (Reader *r, unsigned nbytes) +{ + long v = 0; + while (nbytes--) + { + int c = r->get_char(); + if (c == EOF) + return -1; + v = (v << 8) | (c & 0xFF); + } + return (v); +} +#endif + +#define IPS_EOF 0x00454F46l + +#ifndef NGC +static bool8 ReadIPSPatch(Reader *r, long offset, int32 &rom_size) +{ + char fname[6]; + for(int i=0; i<5; i++){ + int c=r->get_char(); + if(c==EOF) return 0; + fname[i]=(char) c; + } + fname[5]=0; + if (strncmp (fname, "PATCH", 5) != 0) + { + return 0; + } + + int32 ofs; + + for (;;) + { + long len; + long rlen; + int rchar; + + ofs = ReadInt (r, 3); + if (ofs == -1) + goto err_eof; + + if (ofs == IPS_EOF) + break; + + ofs -= offset; + + len = ReadInt (r, 2); + if (len == -1) + goto err_eof; + + /* Apply patch block */ + if (len) + { + if (ofs + len > CMemory::MAX_ROM_SIZE) + goto err_eof; + + while (len--) + { + rchar = r->get_char(); + if (rchar == EOF) + goto err_eof; + ROM [ofs++] = (uint8) rchar; + } + if (ofs > rom_size) + rom_size = ofs; + } + else + { + rlen = ReadInt (r, 2); + if (rlen == -1) + goto err_eof; + + rchar = r->get_char(); + if (rchar == EOF) + goto err_eof; + + if (ofs + rlen > CMemory::MAX_ROM_SIZE) + goto err_eof; + + while (rlen--) + ROM [ofs++] = (uint8) rchar; + + if (ofs > rom_size) + rom_size = ofs; + } + } + + // Check if ROM image needs to be truncated + ofs = ReadInt (r, 3); + if (ofs != -1 && ofs - offset < rom_size) + { + // Need to truncate ROM image + rom_size = ofs - offset; + } + return 1; + +err_eof: + return 0; +} + +#endif + +#ifndef NGC +static int unzFindExtension(unzFile &file, const char *ext, bool restart=true, bool print=true){ + int port; + int l=strlen(ext); + + if(restart){ + port=unzGoToFirstFile(file); + } else { + port=unzGoToNextFile(file); + } + unz_file_info info; + while(port==UNZ_OK){ + char name[132]; + unzGetCurrentFileInfo(file, &info, name,128, NULL,0, NULL,0); + int len=strlen(name); + if(len>=l+1 && name[len-l-1]=='.' && strcasecmp(name+len-l, ext)==0 && + unzOpenCurrentFile(file)==UNZ_OK){ + if(print) printf("Using IPS patch %s", name); + return port; + } + port = unzGoToNextFile(file); + } + return port; +} + +#endif + +#ifndef NGC +void CMemory::CheckForIPSPatch (const char *rom_filename, bool8 header, + int32 &rom_size) +{ + if(Settings.NoPatch) return; + + char dir [_MAX_DIR + 1]; + char drive [_MAX_DRIVE + 1]; + char name [_MAX_FNAME + 1]; + char ext [_MAX_EXT + 1]; + char ips [_MAX_EXT + 3]; + char fname [_MAX_PATH + 1]; + STREAM patch_file = NULL; + long offset = header ? 512 : 0; + int ret; + bool8 flag; + uint32 i; + + _splitpath (rom_filename, drive, dir, name, ext); + _makepath (fname, drive, dir, name, "ips"); + if ((patch_file = OPEN_STREAM (fname, "rb"))) + { + printf ("Using IPS patch %s", fname); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + printf("!\n"); + return; + } else printf(" failed!\n"); + } + if(_MAX_EXT>6){ + i=0; + flag=0; + do { + snprintf(ips, 8, "%03d.ips", i); + _makepath(fname, drive, dir, name, ips); + if(!(patch_file = OPEN_STREAM (fname, "rb"))) break; + printf ("Using IPS patch %s", fname); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i<1000); + if(flag) return; + } + if(_MAX_EXT>3){ + i=0; + flag=0; + do { + snprintf(ips, _MAX_EXT+2, "ips%d", i); + if(strlen(ips)>_MAX_EXT) break; + _makepath(fname, drive, dir, name, ips); + if(!(patch_file = OPEN_STREAM (fname, "rb"))) break; + printf ("Using IPS patch %s", fname); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i!=0); + if(flag) return; + } + if(_MAX_EXT>2){ + i=0; + flag=0; + do { + snprintf(ips, 4, "ip%d", i); + _makepath(fname, drive, dir, name, ips); + if(!(patch_file = OPEN_STREAM (fname, "rb"))) break; + printf ("Using IPS patch %s", fname); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i<10); + if(flag) return; + } + +#ifdef UNZIP_SUPPORT + if (strcasecmp(ext, "zip")==0) { + unzFile file=unzOpen(rom_filename); + if(file!=NULL){ + int port=unzFindExtension(file, "ips"); + while(port==UNZ_OK){ + printf(" in %s", rom_filename); + ret=ReadIPSPatch(new unzReader(file), offset, rom_size); + unzCloseCurrentFile(file); + if(ret){ + printf("!\n"); + flag=1; + } else printf (" failed!\n"); + port = unzFindExtension(file, "ips", false); + } + if(!flag){ + i=0; + do { + snprintf(ips, _MAX_EXT+2, "ips%d", i); + if(strlen(ips)>_MAX_EXT) break; + if(unzFindExtension(file, ips)!=UNZ_OK) break; + printf(" in %s", rom_filename); + ret=ReadIPSPatch(new unzReader(file), offset, rom_size); + unzCloseCurrentFile(file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + if(unzFindExtension(file, ips, false, false)==UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips); + } while(++i!=0); + } + if(!flag){ + i=0; + do { + snprintf(ips, 4, "ip%d", i); + if(unzFindExtension(file, ips)!=UNZ_OK) break; + printf(" in %s", rom_filename); + ret=ReadIPSPatch(new unzReader(file), offset, rom_size); + unzCloseCurrentFile(file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + if(unzFindExtension(file, ips, false, false)==UNZ_OK) printf("WARNING: Ignoring extra .%s files!\n", ips); + } while(++i<10); + } + assert(unzClose(file)==UNZ_OK); + if(flag) return; + } + } +#endif + + const char *n; + n=S9xGetFilename(".ips", PATCH_DIR); + if((patch_file=OPEN_STREAM(n, "rb"))) { + printf("Using IPS patch %s", n); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + printf("!\n"); + return; + } else printf(" failed!\n"); + } + if(_MAX_EXT>6){ + i=0; + flag=0; + do { + snprintf(ips, 9, ".%03d.ips", i); + n=S9xGetFilename(ips, PATCH_DIR); + if(!(patch_file = OPEN_STREAM(n, "rb"))) break; + printf ("Using IPS patch %s", n); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i<1000); + if(flag) return; + } + if(_MAX_EXT>3){ + i=0; + flag=0; + do { + snprintf(ips, _MAX_EXT+3, ".ips%d", i); + if(strlen(ips)>_MAX_EXT+1) break; + n=S9xGetFilename(ips, PATCH_DIR); + if(!(patch_file = OPEN_STREAM(n, "rb"))) break; + printf ("Using IPS patch %s", n); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i!=0); + if(flag) return; + } + if(_MAX_EXT>2){ + i=0; + flag=0; + do { + snprintf(ips, 5, ".ip%d", i); + n=S9xGetFilename(ips, PATCH_DIR); + if(!(patch_file = OPEN_STREAM(n, "rb"))) break; + printf ("Using IPS patch %s", n); + ret=ReadIPSPatch(new fReader(patch_file), offset, rom_size); + CLOSE_STREAM(patch_file); + if(ret){ + flag=1; + printf("!\n"); + } else { + printf(" failed!\n"); + break; + } + } while(++i<10); + if(flag) return; + } +} + +#endif + +void CMemory::ParseSNESHeader(uint8 *RomHeader) +{ + bool8 bs = Settings.BS & !Settings.BSXItself; + + strncpy(ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1); + if (bs) + memset(ROMName + 16, 0x20, ROM_NAME_LEN - 17); + + if (bs) + { + if (!(((RomHeader[0x29] & 0x20) && CalculatedSize < 0x100000) || + (!(RomHeader[0x29] & 0x20) && CalculatedSize == 0x100000))) + printf("BS: Size mismatch\n"); + + // FIXME + int p = 0; + while ((1 << p) < (int) CalculatedSize) + p++; + ROMSize = p - 10; + } + else + ROMSize = RomHeader[0x27]; + + Memory.SRAMSize = bs ? 5 /* BS-X */: RomHeader[0x28]; + + ROMSpeed = bs ? RomHeader[0x28] : RomHeader[0x25]; + ROMType = bs ? 0xE5 /* BS-X */ : RomHeader[0x26]; + ROMRegion = bs ? 0 : RomHeader[0x29]; + + ROMChecksum = RomHeader[0x2E] + (RomHeader[0x2F] << 8); + ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8); + + memmove(ROMId, &RomHeader[0x02], 4); + + if (RomHeader[0x2A] == 0x33) + memmove(CompanyId, &RomHeader[0x00], 2); + else + sprintf(CompanyId, "%02X", RomHeader[0x2A]); +} + +#undef INLINE +#define INLINE +#include "getset.h" + diff --git a/source/snes9x/memmap.h b/source/snes9x/memmap.h new file mode 100644 index 0000000..f4d3ddf --- /dev/null +++ b/source/snes9x/memmap.h @@ -0,0 +1,332 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _memmap_h_ +#define _memmap_h_ + +#include "snes9x.h" + +#define MEMMAP_BLOCK_SIZE (0x1000) +#define MEMMAP_NUM_BLOCKS (0x1000000 / MEMMAP_BLOCK_SIZE) +#define MEMMAP_BLOCKS_PER_BANK (0x10000 / MEMMAP_BLOCK_SIZE) +#define MEMMAP_SHIFT 12 +#define MEMMAP_MASK (MEMMAP_BLOCK_SIZE - 1) +#define MEMMAP_MAX_SDD1_LOGGED_ENTRIES (0x10000 / 8) + +//Extended ROM Formats +#define NOPE 0 +#define YEAH 1 +#define BIGFIRST 2 +#define SMALLFIRST 3 + +//File Formats go here +enum file_formats { FILE_ZIP, FILE_RAR, FILE_JMA, FILE_DEFAULT }; + +class CMemory { +public: + bool8 LoadROM (const char *); + uint32 FileLoader (uint8* buffer, const char* filename, int32 maxsize); + void InitROM (bool8); + bool8 LoadSRAM (const char *); + bool8 SaveSRAM (const char *); + bool8 Init (); + void Deinit (); + void FreeSDD1Data (); + + void WriteProtectROM (); + void FixROMSpeed (); + void MapRAM (); + void MapExtraRAM (); + char *Safe (const char *); + char *SafeANK (const char *); + + void JumboLoROMMap (bool8); + void LoROMMap (); + void LoROM24MBSMap (); + void SRAM512KLoROMMap (); +// void SRAM1024KLoROMMap (); + void SufamiTurboLoROMMap (); + void HiROMMap (); + void SuperFXROMMap (); + void TalesROMMap (bool8); + void AlphaROMMap (); + void SA1ROMMap (); + void SPC7110HiROMMap(); + void SPC7110Sram(uint8); + void SetaDSPMap(); + bool8 AllASCII (uint8 *b, int size); + int ScoreHiROM (bool8 skip_header, int32 offset=0); + int ScoreLoROM (bool8 skip_header, int32 offset=0); +#if 0 + void SufamiTurboAltROMMap(); +#endif + void ApplyROMFixes (); + void CheckForIPSPatch (const char *rom_filename, bool8 header, + int32 &rom_size); + + const char *TVStandard (); + const char *Speed (); + const char *StaticRAMSize (); + const char *MapType (); + const char *MapMode (); + const char *KartContents (); + const char *Size (); + const char *Headers (); + const char *ROMID (); + const char *CompanyID (); + void ParseSNESHeader(uint8*); + enum { + MAP_PPU, MAP_CPU, MAP_DSP, MAP_LOROM_SRAM, MAP_HIROM_SRAM, + MAP_NONE, MAP_DEBUG, MAP_C4, MAP_BWRAM, MAP_BWRAM_BITMAP, + MAP_BWRAM_BITMAP2, MAP_SA1RAM, MAP_SPC7110_ROM, MAP_SPC7110_DRAM, + MAP_RONLY_SRAM, MAP_OBC_RAM, MAP_SETA_DSP, MAP_SETA_RISC, MAP_BSX, MAP_LAST + }; + enum { MAX_ROM_SIZE = 0x800000 }; + + uint8 *RAM; + uint8 *ROM; + uint8 *VRAM; + uint8 *SRAM; + uint8 *BWRAM; + uint8 *FillRAM; + uint8 *C4RAM; + bool8 HiROM; + bool8 LoROM; + uint32 SRAMMask; + uint8 SRAMSize; + uint8 *Map [MEMMAP_NUM_BLOCKS]; + uint8 *WriteMap [MEMMAP_NUM_BLOCKS]; + uint8 MemorySpeed [MEMMAP_NUM_BLOCKS]; + uint8 BlockIsRAM [MEMMAP_NUM_BLOCKS]; + uint8 BlockIsROM [MEMMAP_NUM_BLOCKS]; + char ROMName [ROM_NAME_LEN]; + char RawROMName [ROM_NAME_LEN]; + char ROMId [5]; + char CompanyId [3]; + uint8 ROMSpeed; + uint8 ROMType; + uint8 ROMSize; + int32 ROMFramesPerSecond; + int32 HeaderCount; + uint32 CalculatedSize; + uint32 CalculatedChecksum; + uint32 ROMChecksum; + uint32 ROMComplementChecksum; + uint8 *SDD1Index; + uint8 *SDD1Data; + uint32 SDD1Entries; + uint32 SDD1LoggedDataCountPrev; + uint32 SDD1LoggedDataCount; + uint8 SDD1LoggedData [MEMMAP_MAX_SDD1_LOGGED_ENTRIES]; + char ROMFilename [_MAX_PATH]; + uint8 ROMRegion; + uint32 ROMCRC32; + uint8 ExtendedFormat; +#if 0 + bool8 SufamiTurbo; + char Slot1Filename [_MAX_PATH]; + char Slot2Filename [_MAX_PATH]; + uint8* ROMOffset1; + uint8* ROMOffset2; + uint8* SRAMOffset1; + uint8* SRAMOffset2; + uint32 Slot1Size; + uint32 Slot2Size; + uint32 Slot1SRAMSize; + uint32 Slot2SRAMSize; + uint8 SlotContents; +#endif + uint8 *BSRAM; + uint8 *BIOSROM; + void ResetSpeedMap(); +#if 0 + bool8 LoadMulti (const char *,const char *,const char *); +#endif +}; + +START_EXTERN_C +extern CMemory Memory; +extern uint8 *SRAM; +extern uint8 *ROM; +extern uint8 *RegRAM; +void S9xDeinterleaveMode2 (); +bool8 LoadZip(const char* zipname, + int32 *TotalFileSize, + int32 *headers, + uint8 *buffer); +END_EXTERN_C + +void S9xAutoSaveSRAM (); + + +enum s9xwrap_t { + WRAP_NONE, + WRAP_BANK, + WRAP_PAGE +}; + +enum s9xwriteorder_t { + WRITE_01, + WRITE_10 +}; + +#ifdef NO_INLINE_SET_GET +uint8 S9xGetByte (uint32 Address); +uint16 S9xGetWord (uint32 Address, enum s9xwrap_t w=WRAP_NONE); +void S9xSetByte (uint8 Byte, uint32 Address); +void S9xSetWord (uint16 Word, uint32 Address, enum s9xwrap_t w=WRAP_NONE, enum s9xwriteorder_t o=WRITE_01); +void S9xSetPCBase (uint32 Address); +uint8 *S9xGetMemPointer (uint32 Address); +uint8 *GetBasePointer (uint32 Address); + +START_EXTERN_C +extern uint8 OpenBus; +END_EXTERN_C +#else +#define INLINE inline +#include "getset.h" +#endif // NO_INLINE_SET_GET + +#endif // _memmap_h_ + diff --git a/source/snes9x/messages.h b/source/snes9x/messages.h new file mode 100644 index 0000000..b2230e1 --- /dev/null +++ b/source/snes9x/messages.h @@ -0,0 +1,193 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _messages_h_ +#define _messages_h_ + +/* Types of message sent to S9xMessage routine */ +enum { + S9X_TRACE, + S9X_DEBUG, + S9X_WARNING, + S9X_INFO, + S9X_ERROR, + S9X_FATAL_ERROR +}; + +/* Individual message numbers */ +enum { + S9X_ROM_INFO, + S9X_HEADERS_INFO, + S9X_CONFIG_INFO, + S9X_ROM_CONFUSING_FORMAT_INFO, + S9X_ROM_INTERLEAVED_INFO, + S9X_SOUND_DEVICE_OPEN_FAILED, + S9X_APU_STOPPED, + S9X_USAGE, + S9X_GAME_GENIE_CODE_ERROR, + S9X_ACTION_REPLY_CODE_ERROR, + S9X_GOLD_FINGER_CODE_ERROR, + S9X_DEBUG_OUTPUT, + S9X_DMA_TRACE, + S9X_HDMA_TRACE, + S9X_WRONG_FORMAT, + S9X_WRONG_VERSION, + S9X_ROM_NOT_FOUND, + S9X_FREEZE_FILE_NOT_FOUND, + S9X_PPU_TRACE, + S9X_TRACE_DSP1, + S9X_FREEZE_ROM_NAME, + S9X_HEADER_WARNING, + S9X_NETPLAY_NOT_SERVER, + S9X_FREEZE_FILE_INFO, + S9X_TURBO_MODE, + S9X_SOUND_NOT_BUILT, + S9X_MOVIE_INFO, + S9X_WRONG_MOVIE_SNAPSHOT, + S9X_NOT_A_MOVIE_SNAPSHOT, + S9X_AVI_INFO +}; + +#endif + diff --git a/source/snes9x/missing.h b/source/snes9x/missing.h new file mode 100644 index 0000000..98dc6a4 --- /dev/null +++ b/source/snes9x/missing.h @@ -0,0 +1,219 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _MISSING_H_ +#define _MISSING_H_ + +struct HDMA +{ + uint8 used; + uint8 bbus_address; + uint8 abus_bank; + uint16 abus_address; + uint8 indirect_address; + uint8 force_table_address_write; + uint8 force_table_address_read; + uint8 line_count_write; + uint8 line_count_read; +}; + +struct Missing +{ + uint8 emulate6502; + uint8 decimal_mode; + uint8 mv_8bit_index; + uint8 mv_8bit_acc; + uint8 interlace; + uint8 lines_239; + uint8 pseudo_512; + struct HDMA hdma [8]; + uint8 modes [8]; + uint8 mode7_fx; + uint8 mode7_flip; + uint8 mode7_bgmode; + uint8 direct; + uint8 matrix_multiply; + uint8 oam_read; + uint8 vram_read; + uint8 cgram_read; + uint8 wram_read; + uint8 dma_read; + uint8 vram_inc; + uint8 vram_full_graphic_inc; + uint8 virq; + uint8 hirq; + uint16 virq_pos; + uint16 hirq_pos; + uint8 h_v_latch; + uint8 h_counter_read; + uint8 v_counter_read; + uint8 fast_rom; + uint8 window1 [6]; + uint8 window2 [6]; + uint8 sprite_priority_rotation; + uint8 subscreen; + uint8 subscreen_add; + uint8 subscreen_sub; + uint8 fixed_colour_add; + uint8 fixed_colour_sub; + uint8 mosaic; + uint8 sprite_double_height; + uint8 dma_channels; + uint8 dma_this_frame; + uint8 oam_address_read; + uint8 bg_offset_read; + uint8 matrix_read; + uint8 hdma_channels; + uint8 hdma_this_frame; + uint16 unknownppu_read; + uint16 unknownppu_write; + uint16 unknowncpu_read; + uint16 unknowncpu_write; + uint16 unknowndsp_read; + uint16 unknowndsp_write; +}; + +EXTERN_C struct Missing missing; +#endif + diff --git a/source/snes9x/movie.h b/source/snes9x/movie.h new file mode 100644 index 0000000..4f4d47a --- /dev/null +++ b/source/snes9x/movie.h @@ -0,0 +1,203 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +// Input recording/playback code +// (c) Copyright 2004 blip + +#ifndef _MOVIE_H_ +#define _MOVIE_H_ + +#include +#include +#include "snes9x.h" + +#ifndef SUCCESS +# define SUCCESS 1 +# define WRONG_FORMAT (-1) +# define WRONG_VERSION (-2) +# define FILE_NOT_FOUND (-3) +#endif + +#define MOVIE_OPT_FROM_SNAPSHOT 0 +#define MOVIE_OPT_FROM_RESET (1<<0) +#define MOVIE_OPT_PAL (1<<1) +#define MOVIE_MAX_METADATA 512 + +START_EXTERN_C +struct MovieInfo +{ + time_t TimeCreated; + uint32 LengthFrames; + uint32 RerecordCount; + wchar_t Metadata[MOVIE_MAX_METADATA]; // really should be wchar_t + uint8 Opts; + uint8 ControllersMask; + bool8 ReadOnly; +}; + +// methods used by the user-interface code +int S9xMovieOpen (const char* filename, bool8 read_only); +int S9xMovieCreate (const char* filename, uint8 controllers_mask, uint8 opts, const wchar_t* metadata, int metadata_length); +int S9xMovieGetInfo (const char* filename, struct MovieInfo* info); +void S9xMovieStop (bool8 suppress_message); +void S9xMovieToggleFrameDisplay (); +const char *S9xChooseMovieFilename(bool8 read_only); + +// methods used by the emulation +void S9xMovieInit (); +void S9xMovieUpdate (); +//bool8 S9xMovieRewind (uint32 at_frame); +void S9xMovieFreeze (uint8** buf, uint32* size); +bool8 S9xMovieUnfreeze (const uint8* buf, uint32 size); + +// accessor functions +bool8 S9xMovieActive (); +// the following accessors return 0/false if !S9xMovieActive() +bool8 S9xMovieReadOnly (); +uint32 S9xMovieGetId (); +uint32 S9xMovieGetLength (); +uint32 S9xMovieGetFrameCounter (); + +END_EXTERN_C + +#endif diff --git a/source/snes9x/obc1.cpp b/source/snes9x/obc1.cpp new file mode 100644 index 0000000..06da2f5 --- /dev/null +++ b/source/snes9x/obc1.cpp @@ -0,0 +1,265 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include "memmap.h" +#include "obc1.h" + +static uint8 *OBC1_RAM = NULL; + +int OBC1_Address; +int OBC1_BasePtr; +int OBC1_Shift; + +extern "C" +{ +uint8 GetOBC1 (uint16 Address) +{ + switch(Address) { + case 0x7ff0: + return OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2)]; + + case 0x7ff1: + return OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 1]; + + case 0x7ff2: + return OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 2]; + + case 0x7ff3: + return OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 3]; + + case 0x7ff4: + return OBC1_RAM[OBC1_BasePtr + (OBC1_Address >> 2) + 0x200]; + } + + return OBC1_RAM[Address & 0x1fff]; +} + +void SetOBC1 (uint8 Byte, uint16 Address) +{ + switch(Address) { + case 0x7ff0: + { + OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2)] = Byte; + break; + } + + case 0x7ff1: + { + OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 1] = Byte; + break; + } + + case 0x7ff2: + { + OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 2] = Byte; + break; + } + + case 0x7ff3: + { + OBC1_RAM[OBC1_BasePtr + (OBC1_Address << 2) + 3] = Byte; + break; + } + + case 0x7ff4: + { + unsigned char Temp; + + Temp = OBC1_RAM[OBC1_BasePtr + (OBC1_Address >> 2) + 0x200]; + Temp = (Temp & ~(3 << OBC1_Shift)) | ((Byte & 3) << OBC1_Shift); + OBC1_RAM[OBC1_BasePtr + (OBC1_Address >> 2) + 0x200] = Temp; + break; + } + + case 0x7ff5: + { + if (Byte & 1) + OBC1_BasePtr = 0x1800; + else + OBC1_BasePtr = 0x1c00; + + break; + } + + case 0x7ff6: + { + OBC1_Address = Byte & 0x7f; + OBC1_Shift = (Byte & 3) << 1; + break; + } + } + + OBC1_RAM[Address & 0x1fff] = Byte; +} + +uint8 *GetBasePointerOBC1(uint32 Address) +{ + Address=Address&0xffff; + if((Address&~MEMMAP_MASK)>=(0x7ff0&~MEMMAP_MASK) && + (Address&~MEMMAP_MASK)<=(0x7ff6&~MEMMAP_MASK)) return NULL; + return OBC1_RAM + (Address & 0x1fff); +} + +uint8 *GetMemPointerOBC1(uint32 Address) +{ + Address=Address&0xffff; + if((Address&~MEMMAP_MASK)>=(0x7ff0&~MEMMAP_MASK) && + (Address&~MEMMAP_MASK)<=(0x7ff6&~MEMMAP_MASK)) return NULL; + return OBC1_RAM + (Address & 0x1fff); +} + +void ResetOBC1() +{ + OBC1_RAM = &Memory.FillRAM[0x6000]; + + if (OBC1_RAM[0x1ff5] & 1) + OBC1_BasePtr = 0x1800; + else + OBC1_BasePtr = 0x1c00; + + OBC1_Address = OBC1_RAM[0x1ff6] & 0x7f; + OBC1_Shift = (OBC1_RAM[0x1ff6] & 3) << 1; +} + +} diff --git a/source/snes9x/obc1.h b/source/snes9x/obc1.h new file mode 100644 index 0000000..2b4c5c4 --- /dev/null +++ b/source/snes9x/obc1.h @@ -0,0 +1,157 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _OBC1_H_ +#define _OBC1_H_ + +START_EXTERN_C +uint8 GetOBC1 (uint16 Address); +void SetOBC1 (uint8 Byte, uint16 Address); +uint8 *GetBasePointerOBC1(uint32 Address); +uint8 *GetMemPointerOBC1(uint32 Address); +void ResetOBC1();//bool8 full); +END_EXTERN_C + +#endif + diff --git a/source/snes9x/pixform.h b/source/snes9x/pixform.h new file mode 100644 index 0000000..5f42ad2 --- /dev/null +++ b/source/snes9x/pixform.h @@ -0,0 +1,377 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _PIXFORM_H_ +#define _PIXFORM_H_ + +#ifdef GFX_MULTI_FORMAT + +enum { RGB565, RGB555, BGR565, BGR555, GBR565, GBR555, RGB5551 }; + +#define BUILD_PIXEL(R,G,B) ((*GFX.BuildPixel) (R, G, B)) +#define BUILD_PIXEL2(R,G,B) ((*GFX.BuildPixel2) (R, G, B)) +#define DECOMPOSE_PIXEL(Pixel,R,G,B) ((*GFX.DecomposePixel) (Pixel, R,G,B)) + +extern uint32 RED_LOW_BIT_MASK; +extern uint32 GREEN_LOW_BIT_MASK; +extern uint32 BLUE_LOW_BIT_MASK; +extern uint32 RED_HI_BIT_MASK; +extern uint32 GREEN_HI_BIT_MASK; +extern uint32 BLUE_HI_BIT_MASK; +extern uint32 MAX_RED; +extern uint32 MAX_GREEN; +extern uint32 MAX_BLUE; +extern uint32 SPARE_RGB_BIT_MASK; +extern uint32 GREEN_HI_BIT; +extern uint32 RGB_LOW_BITS_MASK; +extern uint32 RGB_HI_BITS_MASK; +extern uint32 RGB_HI_BITS_MASKx2; +extern uint32 RGB_REMOVE_LOW_BITS_MASK; +extern uint32 FIRST_COLOR_MASK; +extern uint32 SECOND_COLOR_MASK; +extern uint32 THIRD_COLOR_MASK; +extern uint32 ALPHA_BITS_MASK; +extern uint32 FIRST_THIRD_COLOR_MASK; +extern uint32 TWO_LOW_BITS_MASK; +extern uint32 HIGH_BITS_SHIFTED_TWO_MASK; + +#endif + +/* RGB565 format */ +#define BUILD_PIXEL_RGB565(R,G,B) (((int) (R) << 11) | ((int) (G) << 6) | (int) (B)) +#define BUILD_PIXEL2_RGB565(R,G,B) (((int) (R) << 11) | ((int) (G) << 5) | (int) (B)) +#define DECOMPOSE_PIXEL_RGB565(PIX,R,G,B) {(R) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (B) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_RGB565 (1 << 5) + +#define MAX_RED_RGB565 31 +#define MAX_GREEN_RGB565 63 +#define MAX_BLUE_RGB565 31 +#define RED_LOW_BIT_MASK_RGB565 0x0800 +#define GREEN_LOW_BIT_MASK_RGB565 0x0020 +#define BLUE_LOW_BIT_MASK_RGB565 0x0001 +#define RED_HI_BIT_MASK_RGB565 0x8000 +#define GREEN_HI_BIT_MASK_RGB565 0x0400 +#define BLUE_HI_BIT_MASK_RGB565 0x0010 +#define FIRST_COLOR_MASK_RGB565 0xF800 +#define SECOND_COLOR_MASK_RGB565 0x07E0 +#define THIRD_COLOR_MASK_RGB565 0x001F +#define ALPHA_BITS_MASK_RGB565 0x0000 + +/* RGB555 format */ +#define BUILD_PIXEL_RGB555(R,G,B) (((int) (R) << 10) | ((int) (G) << 5) | (int) (B)) +#define BUILD_PIXEL2_RGB555(R,G,B) (((int) (R) << 10) | ((int) (G) << 5) | (int) (B)) +#define DECOMPOSE_PIXEL_RGB555(PIX,R,G,B) {(R) = (PIX) >> 10; (G) = ((PIX) >> 5) & 0x1f; (B) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_RGB555 (1 << 15) + +#define MAX_RED_RGB555 31 +#define MAX_GREEN_RGB555 31 +#define MAX_BLUE_RGB555 31 +#define RED_LOW_BIT_MASK_RGB555 0x0400 +#define GREEN_LOW_BIT_MASK_RGB555 0x0020 +#define BLUE_LOW_BIT_MASK_RGB555 0x0001 +#define RED_HI_BIT_MASK_RGB555 0x4000 +#define GREEN_HI_BIT_MASK_RGB555 0x0200 +#define BLUE_HI_BIT_MASK_RGB555 0x0010 +#define FIRST_COLOR_MASK_RGB555 0x7C00 +#define SECOND_COLOR_MASK_RGB555 0x03E0 +#define THIRD_COLOR_MASK_RGB555 0x001F +#define ALPHA_BITS_MASK_RGB555 0x0000 + +/* BGR565 format */ +#define BUILD_PIXEL_BGR565(R,G,B) (((int) (B) << 11) | ((int) (G) << 6) | (int) (R)) +#define BUILD_PIXEL2_BGR565(R,G,B) (((int) (B) << 11) | ((int) (G) << 5) | (int) (R)) +#define DECOMPOSE_PIXEL_BGR565(PIX,R,G,B) {(B) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (R) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_BGR565 (1 << 5) + +#define MAX_RED_BGR565 31 +#define MAX_GREEN_BGR565 63 +#define MAX_BLUE_BGR565 31 +#define RED_LOW_BIT_MASK_BGR565 0x0001 +#define GREEN_LOW_BIT_MASK_BGR565 0x0040 +#define BLUE_LOW_BIT_MASK_BGR565 0x0800 +#define RED_HI_BIT_MASK_BGR565 0x0010 +#define GREEN_HI_BIT_MASK_BGR565 0x0400 +#define BLUE_HI_BIT_MASK_BGR565 0x8000 +#define FIRST_COLOR_MASK_BGR565 0xF800 +#define SECOND_COLOR_MASK_BGR565 0x07E0 +#define THIRD_COLOR_MASK_BGR565 0x001F +#define ALPHA_BITS_MASK_BGR565 0x0000 + +/* BGR555 format */ +#define BUILD_PIXEL_BGR555(R,G,B) (((int) (B) << 10) | ((int) (G) << 5) | (int) (R)) +#define BUILD_PIXEL2_BGR555(R,G,B) (((int) (B) << 10) | ((int) (G) << 5) | (int) (R)) +#define DECOMPOSE_PIXEL_BGR555(PIX,R,G,B) {(B) = (PIX) >> 10; (G) = ((PIX) >> 5) & 0x1f; (R) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_BGR555 (1 << 15) + +#define MAX_RED_BGR555 31 +#define MAX_GREEN_BGR555 31 +#define MAX_BLUE_BGR555 31 +#define RED_LOW_BIT_MASK_BGR555 0x0001 +#define GREEN_LOW_BIT_MASK_BGR555 0x0020 +#define BLUE_LOW_BIT_MASK_BGR555 0x0400 +#define RED_HI_BIT_MASK_BGR555 0x0010 +#define GREEN_HI_BIT_MASK_BGR555 0x0200 +#define BLUE_HI_BIT_MASK_BGR555 0x4000 +#define FIRST_COLOR_MASK_BGR555 0x7C00 +#define SECOND_COLOR_MASK_BGR555 0x03E0 +#define THIRD_COLOR_MASK_BGR555 0x001F +#define ALPHA_BITS_MASK_BGR555 0x0000 + +/* GBR565 format */ +#define BUILD_PIXEL_GBR565(R,G,B) (((int) (G) << 11) | ((int) (B) << 6) | (int) (R)) +#define BUILD_PIXEL2_GBR565(R,G,B) (((int) (G) << 11) | ((int) (B) << 5) | (int) (R)) +#define DECOMPOSE_PIXEL_GBR565(PIX,R,G,B) {(G) = (PIX) >> 11; (B) = ((PIX) >> 6) & 0x1f; (R) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_GBR565 (1 << 5) + +#define MAX_RED_GBR565 31 +#define MAX_BLUE_GBR565 63 +#define MAX_GREEN_GBR565 31 +#define RED_LOW_BIT_MASK_GBR565 0x0001 +#define BLUE_LOW_BIT_MASK_GBR565 0x0040 +#define GREEN_LOW_BIT_MASK_GBR565 0x0800 +#define RED_HI_BIT_MASK_GBR565 0x0010 +#define BLUE_HI_BIT_MASK_GBR565 0x0400 +#define GREEN_HI_BIT_MASK_GBR565 0x8000 +#define FIRST_COLOR_MASK_GBR565 0xF800 +#define SECOND_COLOR_MASK_GBR565 0x07E0 +#define THIRD_COLOR_MASK_GBR565 0x001F +#define ALPHA_BITS_MASK_GBR565 0x0000 + +/* GBR555 format */ +#define BUILD_PIXEL_GBR555(R,G,B) (((int) (G) << 10) | ((int) (B) << 5) | (int) (R)) +#define BUILD_PIXEL2_GBR555(R,G,B) (((int) (G) << 10) | ((int) (B) << 5) | (int) (R)) +#define DECOMPOSE_PIXEL_GBR555(PIX,R,G,B) {(G) = (PIX) >> 10; (B) = ((PIX) >> 5) & 0x1f; (R) = (PIX) & 0x1f; } +#define SPARE_RGB_BIT_MASK_GBR555 (1 << 15) + +#define MAX_RED_GBR555 31 +#define MAX_BLUE_GBR555 31 +#define MAX_GREEN_GBR555 31 +#define RED_LOW_BIT_MASK_GBR555 0x0001 +#define BLUE_LOW_BIT_MASK_GBR555 0x0020 +#define GREEN_LOW_BIT_MASK_GBR555 0x0400 +#define RED_HI_BIT_MASK_GBR555 0x0010 +#define BLUE_HI_BIT_MASK_GBR555 0x0200 +#define GREEN_HI_BIT_MASK_GBR555 0x4000 +#define FIRST_COLOR_MASK_GBR555 0x7C00 +#define SECOND_COLOR_MASK_GBR555 0x03E0 +#define THIRD_COLOR_MASK_GBR555 0x001F +#define ALPHA_BITS_MASK_GBR555 0x0000 + +/* RGB5551 format */ +#define BUILD_PIXEL_RGB5551(R,G,B) (((int) (R) << 11) | ((int) (G) << 6) | (int) ((B) << 1) | 1) +#define BUILD_PIXEL2_RGB5551(R,G,B) (((int) (R) << 11) | ((int) (G) << 6) | (int) ((B) << 1) | 1) +#define DECOMPOSE_PIXEL_RGB5551(PIX,R,G,B) {(R) = (PIX) >> 11; (G) = ((PIX) >> 6) & 0x1f; (B) = ((PIX) >> 1) & 0x1f; } +#define SPARE_RGB_BIT_MASK_RGB5551 (1) + +#define MAX_RED_RGB5551 31 +#define MAX_GREEN_RGB5551 31 +#define MAX_BLUE_RGB5551 31 +#define RED_LOW_BIT_MASK_RGB5551 0x0800 +#define GREEN_LOW_BIT_MASK_RGB5551 0x0040 +#define BLUE_LOW_BIT_MASK_RGB5551 0x0002 +#define RED_HI_BIT_MASK_RGB5551 0x8000 +#define GREEN_HI_BIT_MASK_RGB5551 0x0400 +#define BLUE_HI_BIT_MASK_RGB5551 0x0020 +#define FIRST_COLOR_MASK_RGB5551 0xf800 +#define SECOND_COLOR_MASK_RGB5551 0x07c0 +#define THIRD_COLOR_MASK_RGB5551 0x003e +#define ALPHA_BITS_MASK_RGB5551 0x0001 + +#ifndef GFX_MULTI_FORMAT +#define CONCAT(X,Y) X##Y + +/* C pre-processor needs a two stage macro define to enable it to concat + * to macro names together to form the name of another macro. */ +#define BUILD_PIXEL_D(F,R,G,B) CONCAT(BUILD_PIXEL_,F) (R,G,B) +#define BUILD_PIXEL2_D(F,R,G,B) CONCAT(BUILD_PIXEL2_,F) (R,G,B) +#define DECOMPOSE_PIXEL_D(F,PIX,R,G,B) CONCAT(DECOMPOSE_PIXEL_,F) (PIX,R,G,B) + +#define BUILD_PIXEL(R,G,B) BUILD_PIXEL_D(PIXEL_FORMAT,R,G,B) +#define BUILD_PIXEL2(R,G,B) BUILD_PIXEL2_D(PIXEL_FORMAT,R,G,B) +#define DECOMPOSE_PIXEL(PIX,R,G,B) DECOMPOSE_PIXEL_D(PIXEL_FORMAT,PIX,R,G,B) + +#define MAX_RED_D(F) CONCAT(MAX_RED_,F) +#define MAX_BLUE_D(F) CONCAT(MAX_BLUE_,F) +#define MAX_GREEN_D(F) CONCAT(MAX_GREEN_,F) +#define RED_LOW_BIT_MASK_D(F) CONCAT(RED_LOW_BIT_MASK_,F) +#define BLUE_LOW_BIT_MASK_D(F) CONCAT(BLUE_LOW_BIT_MASK_,F) +#define GREEN_LOW_BIT_MASK_D(F) CONCAT(GREEN_LOW_BIT_MASK_,F) +#define RED_HI_BIT_MASK_D(F) CONCAT(RED_HI_BIT_MASK_,F) +#define BLUE_HI_BIT_MASK_D(F) CONCAT(BLUE_HI_BIT_MASK_,F) +#define GREEN_HI_BIT_MASK_D(F) CONCAT(GREEN_HI_BIT_MASK_,F) +#define FIRST_COLOR_MASK_D(F) CONCAT(FIRST_COLOR_MASK_,F) +#define SECOND_COLOR_MASK_D(F) CONCAT(SECOND_COLOR_MASK_,F) +#define THIRD_COLOR_MASK_D(F) CONCAT(THIRD_COLOR_MASK_,F) +#define ALPHA_BITS_MASK_D(F) CONCAT(ALPHA_BITS_MASK_,F) + +#define MAX_RED MAX_RED_D(PIXEL_FORMAT) +#define MAX_BLUE MAX_BLUE_D(PIXEL_FORMAT) +#define MAX_GREEN MAX_GREEN_D(PIXEL_FORMAT) +#define RED_LOW_BIT_MASK RED_LOW_BIT_MASK_D(PIXEL_FORMAT) +#define BLUE_LOW_BIT_MASK BLUE_LOW_BIT_MASK_D(PIXEL_FORMAT) +#define GREEN_LOW_BIT_MASK GREEN_LOW_BIT_MASK_D(PIXEL_FORMAT) +#define RED_HI_BIT_MASK RED_HI_BIT_MASK_D(PIXEL_FORMAT) +#define BLUE_HI_BIT_MASK BLUE_HI_BIT_MASK_D(PIXEL_FORMAT) +#define GREEN_HI_BIT_MASK GREEN_HI_BIT_MASK_D(PIXEL_FORMAT) +#define FIRST_COLOR_MASK FIRST_COLOR_MASK_D(PIXEL_FORMAT) +#define SECOND_COLOR_MASK SECOND_COLOR_MASK_D(PIXEL_FORMAT) +#define THIRD_COLOR_MASK THIRD_COLOR_MASK_D(PIXEL_FORMAT) +#define ALPHA_BITS_MASK ALPHA_BITS_MASK_D(PIXEL_FORMAT) + +#define GREEN_HI_BIT ((MAX_GREEN + 1) >> 1) +#define RGB_LOW_BITS_MASK (RED_LOW_BIT_MASK | GREEN_LOW_BIT_MASK | \ + BLUE_LOW_BIT_MASK) +#define RGB_HI_BITS_MASK (RED_HI_BIT_MASK | GREEN_HI_BIT_MASK | \ + BLUE_HI_BIT_MASK) +#define RGB_HI_BITS_MASKx2 ((RED_HI_BIT_MASK | GREEN_HI_BIT_MASK | \ + BLUE_HI_BIT_MASK) << 1) +#define RGB_REMOVE_LOW_BITS_MASK (~RGB_LOW_BITS_MASK) +#define FIRST_THIRD_COLOR_MASK (FIRST_COLOR_MASK | THIRD_COLOR_MASK) +#define TWO_LOW_BITS_MASK (RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1)) +#define HIGH_BITS_SHIFTED_TWO_MASK (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \ + ~TWO_LOW_BITS_MASK ) >> 2) +#endif + +#endif + diff --git a/source/snes9x/port.h b/source/snes9x/port.h new file mode 100644 index 0000000..c5b204c --- /dev/null +++ b/source/snes9x/port.h @@ -0,0 +1,408 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _PORT_H_ +#define _PORT_H_ + +#include + +#ifndef STORM +//#include +#include +#else +#include +#include +#endif + +#ifndef ACCEPT_SIZE_T +#ifdef __WIN32__ +#define ACCEPT_SIZE_T int +#else +#define ACCEPT_SIZE_T unsigned int +#endif +#endif + +#include + +/* #define PIXEL_FORMAT RGB565 */ +#define GFX_MULTI_FORMAT + +#ifndef NOASM +//#define USE_X86_ASM +#endif + +#ifdef __MACOSX__ + + #ifdef _C + #undef _C + #endif + + #ifdef _D + #undef _D + #endif + + #define CHECK_SOUND() + #define PIXEL_FORMAT RGB555 + #undef GFX_MULTI_FORMAT + #undef USE_X86_ASM + #undef _MAX_PATH + + #define SET_UI_COLOR(r,g,b) SetInfoDlgColor(r,g,b) + void SetInfoDlgColor(unsigned char, unsigned char, unsigned char); + +#endif /* __MACOSX__ */ + +#ifndef snes9x_types_defined +#define snes9x_types_defined + +typedef unsigned char bool8; + +#ifdef HAVE_STDINT_H +#include + +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; +typedef intptr_t pint; + +#else /* Don't have stdint.h */ + +#ifdef PTR_NOT_INT +typedef long pint; +#else /* pointer is int */ +typedef int pint; +#endif /* PTR_NOT_INT */ + +/* FIXME: Refactor this by moving out the BORLAND part and unifying typedefs */ +#ifndef __WIN32__ +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed char int8; +typedef short int16; +typedef int int32; +typedef unsigned int uint32; +# ifdef __GNUC__ /* long long is not part of ISO C++ */ +__extension__ +# endif +typedef long long int64; +typedef unsigned long long uint64; +#else /* __WIN32__ */ + +# ifdef __BORLANDC__ +# include +# else + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed char int8; +typedef short int16; + +# ifndef WSAAPI +/* winsock2.h typedefs int32 as well. */ +typedef long int32; + +# define PLAT_SOUND_BUFFER SoundBuffer +# define RIGHTSHIFT_IS_SAR +# endif + +typedef unsigned int uint32; + +# endif /* __BORLANDC__ */ + +typedef __int64 int64; +typedef unsigned __int64 uint64; + +#endif /* __WIN32__ */ +#endif /* HAVE_STDINT_H */ +#endif /* snes9x_types_defined */ + + +#include "pixform.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef STORM +#define EXTERN_C +#define START_EXTERN_C +#define END_EXTERN_C +#else +#if defined(__cplusplus) || defined(c_plusplus) +#define EXTERN_C extern "C" +#define START_EXTERN_C extern "C" { +#define END_EXTERN_C } +#else +#define EXTERN_C extern +#define START_EXTERN_C +#define END_EXTERN_C +#endif +#endif + +#ifndef __WIN32__ + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#define _MAX_DIR PATH_MAX +#define _MAX_DRIVE 1 +#define _MAX_FNAME PATH_MAX +#define _MAX_EXT PATH_MAX +#define _MAX_PATH PATH_MAX + +#define ZeroMemory(a,b) memset((a),0,(b)) + +void _makepath (char *path, const char *drive, const char *dir, + const char *fname, const char *ext); +void _splitpath (const char *path, char *drive, char *dir, char *fname, + char *ext); +#else /* __WIN32__ */ +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +EXTERN_C void S9xGenerateSound (); + +#ifdef STORM +EXTERN_C int soundsignal; +EXTERN_C void MixSound(void); +/* Yes, CHECK_SOUND is getting defined correctly! */ +#define CHECK_SOUND if (Settings.APUEnabled) if(SetSignalPPC(0L, soundsignal) & soundsignal) MixSound +#else +#define CHECK_SOUND() +#endif + +#ifdef __DJGPP +#define SLASH_STR "\\" +#define SLASH_CHAR '\\' +#else +#define SLASH_STR "/" +#define SLASH_CHAR '/' +#endif + +/* Taken care of in signal.h on Linux. + * #ifdef __linux + * typedef void (*SignalHandler)(int); + * #define SIG_PF SignalHandler + * #endif + */ + +/* If including signal.h, do it before snes9.h and port.h to avoid clashes. */ +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +#if defined(__i386__) || defined(__i486__) || defined(__i586__) || \ + defined(__x86_64__) || defined(__WIN32__) || defined(__alpha__) +//#define LSB_FIRST +//#define FAST_LSB_WORD_ACCESS +#else +#define MSB_FIRST +#endif + +#ifndef MSB_FIRST +#define MSB_FIRST +#endif + +#ifdef __sun +#define TITLE "Snes9X: Solaris" +#endif + +#ifdef __linux +#define TITLE "Snes9X: Linux" +#define SYS_CONFIG_FILE "/etc/snes9x/snes9x.conf" +#endif + +#ifndef TITLE +#define TITLE "Snes9x" +#endif + +#ifdef STORM +#define STATIC +#define strncasecmp strnicmp +#else +#define STATIC static +#endif + +#ifdef FAST_LSB_WORD_ACCESS +#define READ_WORD(s) (*(uint16 *) (s)) +#define READ_3WORD(s) (0x00ffffff & *(uint32 *) (s)) +#define READ_DWORD(s) (*(uint32 *) (s)) +#define WRITE_WORD(s, d) (*(uint16 *) (s)) = (d) +#define WRITE_3WORD(s, d) *(uint16 *) (s) = (uint16)(d),\ + *((uint8 *) (s) + 2) = (uint8) ((d) >> 16) +#define WRITE_DWORD(s, d) (*(uint32 *) (s)) = (d) +#else +#define READ_WORD(s) ( *(uint8 *) (s) |\ + (*((uint8 *) (s) + 1) << 8)) +#define READ_3WORD(s) ( *(uint8 *) (s) |\ + (*((uint8 *) (s) + 1) << 8) |\ + (*((uint8 *) (s) + 2) << 16)) +#define READ_DWORD(s) ( *(uint8 *) (s) |\ + (*((uint8 *) (s) + 1) << 8) |\ + (*((uint8 *) (s) + 2) << 16) |\ + (*((uint8 *) (s) + 3) << 24)) +#define WRITE_WORD(s, d) *(uint8 *) (s) = (d), \ + *((uint8 *) (s) + 1) = (d) >> 8 +#define WRITE_3WORD(s, d) *(uint8 *) (s) = (uint8) (d), \ + *((uint8 *) (s) + 1) = (uint8) ((d) >> 8),\ + *((uint8 *) (s) + 2) = (uint8) ((d) >> 16) +#define WRITE_DWORD(s, d) *(uint8 *) (s) = (uint8) (d), \ + *((uint8 *) (s) + 1) = (uint8) ((d) >> 8),\ + *((uint8 *) (s) + 2) = (uint8) ((d) >> 16),\ + *((uint8 *) (s) + 3) = (uint8) ((d) >> 24) +#endif + +#endif + diff --git a/source/snes9x/ppu.cpp b/source/snes9x/ppu.cpp new file mode 100644 index 0000000..20684e5 --- /dev/null +++ b/source/snes9x/ppu.cpp @@ -0,0 +1,3013 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" +#include "cpuexec.h" +#include "missing.h" +#include "apu.h" +#include "dma.h" +#include "gfx.h" +#include "display.h" +#include "sa1.h" + +#ifndef NGC +#include "netplay.h" +#endif + +#include "sdd1.h" +#include "srtc.h" +#include "spc7110.h" +#include "bsx.h" +#include "movie.h" +#include "controls.h" + +#ifndef ZSNES_FX +#include "fxemu.h" +#include "fxinst.h" +extern struct FxInit_s SuperFX; +#else +EXTERN_C void S9xSuperFXWriteReg (uint8, uint32); +EXTERN_C uint8 S9xSuperFXReadReg (uint32); +#endif + +uint32 justifiers=0xFFFF00AA; +uint8 in_bit=0; + +extern uint8 *HDMAMemPointers [8]; + +static inline void S9xLatchCounters (bool force) +{ + if (force || (Memory.FillRAM[0x4213] & 0x80)) + { + // Latch h and v counters, like the gun +#ifdef DEBUGGER + missing.h_v_latch = 1; +#endif +#if 0 +# ifdef CPU_SHUTDOWN + CPU.WaitAddress = CPU.PCAtOpcodeStart; +# endif +#endif + PPU.HVBeamCounterLatched = 1; + PPU.VBeamPosLatched = (uint16) CPU.V_Counter; + + // From byuu: + // All dots are 4 cycles long, except dots 322 and 326. dots 322 and 326 are 6 cycles long. + // This holds true for all scanlines except scanline 240 on non-interlace odd frames. + // The reason for this is because this scanline is only 1360 cycles long, + // instead of 1364 like all other scanlines. + // This makes the effective range of hscan_pos 0-339 at all times. + int32 hc = CPU.Cycles; + + if (Timings.H_Max == Timings.H_Max_Master) // 1364 + { + if (hc >= 1292) + hc -= (ONE_DOT_CYCLE / 2); + if (hc >= 1308) + hc -= (ONE_DOT_CYCLE / 2); + } + + PPU.HBeamPosLatched = (uint16) (hc / ONE_DOT_CYCLE); + + // Causes screen flicker for Yoshi's Island if uncommented + //CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE); + + Memory.FillRAM [0x213F] |= 0x40; + + } + + if (CPU.V_Counter > PPU.GunVLatch || + (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE)) + { + PPU.GunVLatch = 1000; + } +} + +static inline void S9xTryGunLatch (bool force) +{ + if (CPU.V_Counter > PPU.GunVLatch || + (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE)) + { + if (force || (Memory.FillRAM[0x4213] & 0x80)) + { + #ifdef DEBUGGER + missing.h_v_latch = 1; + #endif + #if 0 + # ifdef CPU_SHUTDOWN + CPU.WaitAddress = CPU.PCAtOpcodeStart; + # endif + #endif + PPU.HVBeamCounterLatched = 1; + PPU.VBeamPosLatched = (uint16) PPU.GunVLatch; + PPU.HBeamPosLatched = (uint16) PPU.GunHLatch; + + // Causes screen flicker for Yoshi's Island if uncommented + //CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE); + + Memory.FillRAM [0x213F] |= 0x40; + } + + PPU.GunVLatch = 1000; + } +} + +void S9xCheckMissingHTimerPosition (int32 hc) +{ + if (PPU.HTimerPosition == hc) + { + if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition))) + S9xSetIRQ(PPU_H_BEAM_IRQ_SOURCE); + else + if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition)) + S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE); + } +} + +void S9xCheckMissingHTimerPositionRange (int32 hc_from, int32 range) +{ + if ((PPU.HTimerPosition >= hc_from) && (PPU.HTimerPosition < (hc_from + range))) + { + if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || (CPU.V_Counter == PPU.VTimerPosition))) + S9xSetIRQ(PPU_H_BEAM_IRQ_SOURCE); + else + if (PPU.VTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition)) + S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE); + } +} + +void S9xCheckMissingVTimerPosition (void) +{ + if (PPU.VTimerEnabled && !PPU.HTimerEnabled && (CPU.V_Counter == PPU.VTimerPosition) && (CPU.Cycles >= PPU.HTimerPosition)) + S9xSetIRQ(PPU_V_BEAM_IRQ_SOURCE); +} + +void S9xUpdateHVTimerPosition (void) +{ + if (PPU.HTimerEnabled) + { +#ifdef DEBUGGER + missing.hirq_pos = PPU.IRQHBeamPos; +#endif + if (PPU.IRQHBeamPos != 0) + { + // IRQ_read + PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE; + if (Timings.H_Max == Timings.H_Max_Master) // 1364 + { + if (PPU.IRQHBeamPos > 322) + PPU.HTimerPosition += (ONE_DOT_CYCLE / 2); + if (PPU.IRQHBeamPos > 326) + PPU.HTimerPosition += (ONE_DOT_CYCLE / 2); + } + PPU.HTimerPosition += 14; + // /IRQ + PPU.HTimerPosition += 4; + // after CPU executing + PPU.HTimerPosition += 6; + } + else + PPU.HTimerPosition = 10 + 4 + 6; + } + else + PPU.HTimerPosition = 10 + 4 + 6; + + PPU.VTimerPosition = PPU.IRQVBeamPos; + + if ((PPU.HTimerPosition >= Timings.H_Max) && (PPU.IRQHBeamPos < 340)) + { + PPU.HTimerPosition -= Timings.H_Max; + PPU.VTimerPosition++; + // FIXME + if (PPU.VTimerPosition >= Timings.V_Max) + PPU.VTimerPosition = 0; + } + + if (PPU.HTimerPosition < CPU.Cycles) + { + switch (CPU.WhichEvent) + { + case HC_IRQ_1_3_EVENT: + CPU.WhichEvent = HC_HDMA_START_EVENT; + CPU.NextEvent = Timings.HDMAStart; + break; + + case HC_IRQ_3_5_EVENT: + CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; + CPU.NextEvent = Timings.H_Max; + break; + + case HC_IRQ_5_7_EVENT: + CPU.WhichEvent = HC_HDMA_INIT_EVENT; + CPU.NextEvent = Timings.HDMAInit; + break; + + case HC_IRQ_7_9_EVENT: + CPU.WhichEvent = HC_RENDER_EVENT; + CPU.NextEvent = Timings.RenderPos; + break; + + case HC_IRQ_9_A_EVENT: + CPU.WhichEvent = HC_WRAM_REFRESH_EVENT; + CPU.NextEvent = Timings.WRAMRefreshPos; + break; + + case HC_IRQ_A_1_EVENT: + CPU.WhichEvent = HC_HBLANK_START_EVENT; + CPU.NextEvent = Timings.HBlankStart; + break; + } + } + else + if (PPU.HTimerPosition < CPU.NextEvent) + { + CPU.NextEvent = PPU.HTimerPosition; + + switch (CPU.WhichEvent) + { + case HC_HDMA_START_EVENT: + CPU.WhichEvent = HC_IRQ_1_3_EVENT; + break; + + case HC_HCOUNTER_MAX_EVENT: + CPU.WhichEvent = HC_IRQ_3_5_EVENT; + break; + + case HC_HDMA_INIT_EVENT: + CPU.WhichEvent = HC_IRQ_5_7_EVENT; + break; + + case HC_RENDER_EVENT: + CPU.WhichEvent = HC_IRQ_7_9_EVENT; + break; + + case HC_WRAM_REFRESH_EVENT: + CPU.WhichEvent = HC_IRQ_9_A_EVENT; + break; + + case HC_HBLANK_START_EVENT: + CPU.WhichEvent = HC_IRQ_A_1_EVENT; + break; + } + } + else + { + switch (CPU.WhichEvent) + { + case HC_IRQ_1_3_EVENT: + CPU.WhichEvent = HC_HDMA_START_EVENT; + CPU.NextEvent = Timings.HDMAStart; + break; + + case HC_IRQ_3_5_EVENT: + CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT; + CPU.NextEvent = Timings.H_Max; + break; + + case HC_IRQ_5_7_EVENT: + CPU.WhichEvent = HC_HDMA_INIT_EVENT; + CPU.NextEvent = Timings.HDMAInit; + break; + + case HC_IRQ_7_9_EVENT: + CPU.WhichEvent = HC_RENDER_EVENT; + CPU.NextEvent = Timings.RenderPos; + break; + + case HC_IRQ_9_A_EVENT: + CPU.WhichEvent = HC_WRAM_REFRESH_EVENT; + CPU.NextEvent = Timings.WRAMRefreshPos; + break; + + case HC_IRQ_A_1_EVENT: + CPU.WhichEvent = HC_HBLANK_START_EVENT; + CPU.NextEvent = Timings.HBlankStart; + break; + } + } +} + +void S9xFixColourBrightness () +{ + IPPU.XB = mul_brightness [PPU.Brightness]; + for (int i = 0; i < 256; i++) + { + IPPU.Red [i] = IPPU.XB [PPU.CGDATA [i] & 0x1f]; + IPPU.Green [i] = IPPU.XB [(PPU.CGDATA [i] >> 5) & 0x1f]; + IPPU.Blue [i] = IPPU.XB [(PPU.CGDATA [i] >> 10) & 0x1f]; + IPPU.ScreenColors [i] = BUILD_PIXEL (IPPU.Red [i], IPPU.Green [i], + IPPU.Blue [i]); + } +} + +/******************************************************************************/ +/* S9xSetPPU() */ +/* This function sets a PPU Register to a specific byte */ +/******************************************************************************/ +void S9xSetPPU (uint8 Byte, uint16 Address) +{ +// fprintf(stderr, "%03d: %02x to %04x\n", CPU.V_Counter, Byte, Address); + + // Take care of DMA wrapping + if(CPU.InDMA && Address>0x21ff) Address=0x2100+(Address&0xff); + + if (Address <= 0x219F) + { + switch (Address) + { + case 0x2100: + // Brightness and screen blank bit + if (Byte != Memory.FillRAM [0x2100]) + { + FLUSH_REDRAW (); + if (PPU.Brightness != (Byte & 0xF)) + { + IPPU.ColorsChanged = TRUE; + IPPU.DirectColourMapsNeedRebuild = TRUE; + PPU.Brightness = Byte & 0xF; + S9xFixColourBrightness (); + if (PPU.Brightness > IPPU.MaxBrightness) + IPPU.MaxBrightness = PPU.Brightness; + } + if ((Memory.FillRAM[0x2100] & 0x80) != (Byte & 0x80)) + { + IPPU.ColorsChanged = TRUE; + PPU.ForcedBlanking = (Byte >> 7) & 1; + } + } + break; + + case 0x2101: + // Sprite (OBJ) tile address + if (Byte != Memory.FillRAM [0x2101]) + { + FLUSH_REDRAW (); + PPU.OBJNameBase = (Byte & 3) << 14; + PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13; + PPU.OBJSizeSelect = (Byte >> 5) & 7; + IPPU.OBJChanged = TRUE; + } + break; + + case 0x2102: + // Sprite write address (low) + PPU.OAMAddr = ((Memory.FillRAM[0x2103]&1)<<8) | Byte; + PPU.OAMFlip = 2; + PPU.OAMReadFlip = 0; + PPU.SavedOAMAddr = PPU.OAMAddr; + if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; +#ifdef DEBUGGER + missing.sprite_priority_rotation = 1; +#endif + } + break; + + case 0x2103: + // Sprite register write address (high), sprite priority rotation + // bit. + PPU.OAMAddr = ((Byte&1)<<8) | Memory.FillRAM[0x2102]; + + PPU.OAMPriorityRotation=(Byte & 0x80)? 1 : 0; + if (PPU.OAMPriorityRotation) + { + if (PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; +#ifdef DEBUGGER + missing.sprite_priority_rotation = 1; +#endif + } + } else { + if (PPU.FirstSprite != 0) + { + PPU.FirstSprite = 0; + IPPU.OBJChanged = TRUE; +#ifdef DEBUGGER + missing.sprite_priority_rotation = 1; +#endif + } + } + PPU.OAMFlip = 0; + PPU.OAMReadFlip = 0; + PPU.SavedOAMAddr = PPU.OAMAddr; + break; + + case 0x2104: + // Sprite register write + REGISTER_2104(Byte); + break; + + case 0x2105: + // Screen mode (0 - 7), background tile sizes and background 3 + // priority + if (Byte != Memory.FillRAM [0x2105]) + { + FLUSH_REDRAW (); + PPU.BG[0].BGSize = (Byte >> 4) & 1; + PPU.BG[1].BGSize = (Byte >> 5) & 1; + PPU.BG[2].BGSize = (Byte >> 6) & 1; + PPU.BG[3].BGSize = (Byte >> 7) & 1; + PPU.BGMode = Byte & 7; + // BJ: BG3Priority only takes effect if BGMode==1 and the bit is set + PPU.BG3Priority = ((Byte & 0x0f) == 0x09); +#ifdef DEBUGGER + missing.modes[PPU.BGMode] = 1; +#endif + if(PPU.BGMode==5||PPU.BGMode==6) + IPPU.Interlace = Memory.FillRAM[0x2133]&1; + else + IPPU.Interlace = 0; + } + break; + + case 0x2106: + if (Byte != Memory.FillRAM [0x2106]) + { + // Mosaic pixel size and enable + FLUSH_REDRAW(); + PPU.MosaicStart=CPU.V_Counter; + if(PPU.MosaicStart>PPU.ScreenHeight) PPU.MosaicStart=0; +#ifdef DEBUGGER + if ((Byte & 0xf0) && (Byte & 0x0f)) + missing.mosaic = 1; +#endif + PPU.Mosaic = (Byte >> 4) + 1; + PPU.BGMosaic [0] = (Byte & 1); + PPU.BGMosaic [1] = (Byte & 2); + PPU.BGMosaic [2] = (Byte & 4); + PPU.BGMosaic [3] = (Byte & 8); + } + break; + case 0x2107: // [BG0SC] + if (Byte != Memory.FillRAM [0x2107]) + { + FLUSH_REDRAW (); + PPU.BG[0].SCSize = Byte & 3; + PPU.BG[0].SCBase = (Byte & 0x7c) << 8; + } + break; + + case 0x2108: // [BG1SC] + if (Byte != Memory.FillRAM [0x2108]) + { + FLUSH_REDRAW (); + PPU.BG[1].SCSize = Byte & 3; + PPU.BG[1].SCBase = (Byte & 0x7c) << 8; + } + break; + + case 0x2109: // [BG2SC] + if (Byte != Memory.FillRAM [0x2109]) + { + FLUSH_REDRAW (); + PPU.BG[2].SCSize = Byte & 3; + PPU.BG[2].SCBase = (Byte & 0x7c) << 8; + } + break; + + case 0x210A: // [BG3SC] + if (Byte != Memory.FillRAM [0x210a]) + { + FLUSH_REDRAW (); + PPU.BG[3].SCSize = Byte & 3; + PPU.BG[3].SCBase = (Byte & 0x7c) << 8; + } + break; + + case 0x210B: // [BG01NBA] + if (Byte != Memory.FillRAM [0x210b]) + { + FLUSH_REDRAW (); + PPU.BG[0].NameBase = (Byte & 7) << 12; + PPU.BG[1].NameBase = ((Byte >> 4) & 7) << 12; + } + break; + + case 0x210C: // [BG23NBA] + if (Byte != Memory.FillRAM [0x210c]) + { + FLUSH_REDRAW (); + PPU.BG[2].NameBase = (Byte & 7) << 12; + PPU.BG[3].NameBase = ((Byte >> 4) & 7) << 12; + } + break; + + + case 0x210D: + // Yes, the two formulas are supposed to be different. + PPU.BG[0].HOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[0].HOffset>>8)&7); + PPU.M7HOFS = (Byte<<8) | PPU.M7byte; + PPU.BGnxOFSbyte = Byte; + PPU.M7byte = Byte; + break; + + case 0x210E: + // Yes, the two formulas are supposed to be different. + PPU.BG[0].VOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[0].VOffset>>8)&7); + PPU.M7VOFS = (Byte<<8) | PPU.M7byte; + PPU.BGnxOFSbyte = Byte; + PPU.M7byte = Byte; + break; + + case 0x210F: + PPU.BG[1].HOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[1].HOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2110: + PPU.BG[1].VOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[1].VOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2111: + PPU.BG[2].HOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[2].HOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2112: + PPU.BG[2].VOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[2].VOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2113: + PPU.BG[3].HOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[3].HOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2114: + PPU.BG[3].VOffset = (Byte<<8) | (PPU.BGnxOFSbyte&~7) | ((PPU.BG[3].VOffset>>8)&7); + PPU.BGnxOFSbyte = Byte; + break; + + case 0x2115: + // VRAM byte/word access flag and increment + PPU.VMA.High = (Byte & 0x80) == 0 ? FALSE : TRUE; + switch (Byte & 3) + { + case 0: + PPU.VMA.Increment = 1; + break; + case 1: + PPU.VMA.Increment = 32; + break; + case 2: + PPU.VMA.Increment = 128; + break; + case 3: + PPU.VMA.Increment = 128; + break; + } +#ifdef DEBUGGER + if ((Byte & 3) != 0) + missing.vram_inc = Byte & 3; +#endif + if (Byte & 0x0c) + { + static uint16 IncCount [4] = { 0, 32, 64, 128 }; + static uint16 Shift [4] = { 0, 5, 6, 7 }; +#ifdef DEBUGGER + missing.vram_full_graphic_inc = (Byte & 0x0c) >> 2; +#endif +// PPU.VMA.Increment = 1; + uint8 i = (Byte & 0x0c) >> 2; + PPU.VMA.FullGraphicCount = IncCount [i]; + PPU.VMA.Mask1 = IncCount [i] * 8 - 1; + PPU.VMA.Shift = Shift [i]; + } + else + PPU.VMA.FullGraphicCount = 0; + break; + + case 0x2116: + // VRAM read/write address (low) + PPU.VMA.Address &= 0xFF00; + PPU.VMA.Address |= Byte; +#ifdef CORRECT_VRAM_READS + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((address << 1) & 0xFFFF)); + } else + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((PPU.VMA.Address << 1) & 0xffff)); +#else + IPPU.FirstVRAMRead = TRUE; +#endif + break; + + case 0x2117: + // VRAM read/write address (high) + PPU.VMA.Address &= 0x00FF; + PPU.VMA.Address |= Byte << 8; +#ifdef CORRECT_VRAM_READS + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((address << 1) & 0xFFFF)); + } else + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((PPU.VMA.Address << 1) & 0xffff)); +#else + IPPU.FirstVRAMRead = TRUE; +#endif + break; + + case 0x2118: + // VRAM write data (low) +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = TRUE; +#endif + REGISTER_2118(Byte); + break; + + case 0x2119: + // VRAM write data (high) +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = TRUE; +#endif + REGISTER_2119(Byte); + break; + + case 0x211a: + // Mode 7 outside rotation area display mode and flipping + if (Byte != Memory.FillRAM [0x211a]) + { + FLUSH_REDRAW (); + PPU.Mode7Repeat = Byte >> 6; + if (PPU.Mode7Repeat == 1) + PPU.Mode7Repeat = 0; + PPU.Mode7VFlip = (Byte & 2) >> 1; + PPU.Mode7HFlip = Byte & 1; + } + break; + case 0x211b: + // Mode 7 matrix A (low & high) + PPU.MatrixA = PPU.M7byte | (Byte << 8); + PPU.Need16x8Mulitply = TRUE; + PPU.M7byte = Byte; + break; + case 0x211c: + // Mode 7 matrix B (low & high) + PPU.MatrixB = PPU.M7byte | (Byte << 8); + PPU.Need16x8Mulitply = TRUE; + PPU.M7byte = Byte; + break; + case 0x211d: + // Mode 7 matrix C (low & high) + PPU.MatrixC = PPU.M7byte | (Byte << 8); + PPU.M7byte = Byte; + break; + case 0x211e: + // Mode 7 matrix D (low & high) + PPU.MatrixD = PPU.M7byte | (Byte << 8); + PPU.M7byte = Byte; + break; + case 0x211f: + // Mode 7 centre of rotation X (low & high) + PPU.CentreX = PPU.M7byte | (Byte << 8); + PPU.M7byte = Byte; + break; + case 0x2120: + // Mode 7 centre of rotation Y (low & high) + PPU.CentreY = PPU.M7byte | (Byte << 8); + PPU.M7byte = Byte; + break; + + case 0x2121: + // CG-RAM address + PPU.CGFLIP = 0; + PPU.CGFLIPRead = 0; + PPU.CGADD = Byte; + break; + + case 0x2122: + REGISTER_2122(Byte); + break; + + case 0x2123: + // Window 1 and 2 enable for backgrounds 1 and 2 + if (Byte != Memory.FillRAM [0x2123]) + { + FLUSH_REDRAW (); + PPU.ClipWindow1Enable [0] = !!(Byte & 0x02); + PPU.ClipWindow1Enable [1] = !!(Byte & 0x20); + PPU.ClipWindow2Enable [0] = !!(Byte & 0x08); + PPU.ClipWindow2Enable [1] = !!(Byte & 0x80); + PPU.ClipWindow1Inside [0] = !(Byte & 0x01); + PPU.ClipWindow1Inside [1] = !(Byte & 0x10); + PPU.ClipWindow2Inside [0] = !(Byte & 0x04); + PPU.ClipWindow2Inside [1] = !(Byte & 0x40); + PPU.RecomputeClipWindows = TRUE; +#ifdef DEBUGGER + if (Byte & 0x80) + missing.window2[1] = 1; + if (Byte & 0x20) + missing.window1[1] = 1; + if (Byte & 0x08) + missing.window2[0] = 1; + if (Byte & 0x02) + missing.window1[0] = 1; +#endif + } + break; + case 0x2124: + // Window 1 and 2 enable for backgrounds 3 and 4 + if (Byte != Memory.FillRAM [0x2124]) + { + FLUSH_REDRAW (); + PPU.ClipWindow1Enable [2] = !!(Byte & 0x02); + PPU.ClipWindow1Enable [3] = !!(Byte & 0x20); + PPU.ClipWindow2Enable [2] = !!(Byte & 0x08); + PPU.ClipWindow2Enable [3] = !!(Byte & 0x80); + PPU.ClipWindow1Inside [2] = !(Byte & 0x01); + PPU.ClipWindow1Inside [3] = !(Byte & 0x10); + PPU.ClipWindow2Inside [2] = !(Byte & 0x04); + PPU.ClipWindow2Inside [3] = !(Byte & 0x40); + PPU.RecomputeClipWindows = TRUE; +#ifdef DEBUGGER + if (Byte & 0x80) + missing.window2[3] = 1; + if (Byte & 0x20) + missing.window1[3] = 1; + if (Byte & 0x08) + missing.window2[2] = 1; + if (Byte & 0x02) + missing.window1[2] = 1; +#endif + } + break; + case 0x2125: + // Window 1 and 2 enable for objects and colour window + if (Byte != Memory.FillRAM [0x2125]) + { + FLUSH_REDRAW (); + PPU.ClipWindow1Enable [4] = !!(Byte & 0x02); + PPU.ClipWindow1Enable [5] = !!(Byte & 0x20); + PPU.ClipWindow2Enable [4] = !!(Byte & 0x08); + PPU.ClipWindow2Enable [5] = !!(Byte & 0x80); + PPU.ClipWindow1Inside [4] = !(Byte & 0x01); + PPU.ClipWindow1Inside [5] = !(Byte & 0x10); + PPU.ClipWindow2Inside [4] = !(Byte & 0x04); + PPU.ClipWindow2Inside [5] = !(Byte & 0x40); + PPU.RecomputeClipWindows = TRUE; +#ifdef DEBUGGER + if (Byte & 0x80) + missing.window2[5] = 1; + if (Byte & 0x20) + missing.window1[5] = 1; + if (Byte & 0x08) + missing.window2[4] = 1; + if (Byte & 0x02) + missing.window1[4] = 1; +#endif + } + break; + case 0x2126: + // Window 1 left position + if (Byte != Memory.FillRAM [0x2126]) + { + FLUSH_REDRAW (); + PPU.Window1Left = Byte; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x2127: + // Window 1 right position + if (Byte != Memory.FillRAM [0x2127]) + { + FLUSH_REDRAW (); + PPU.Window1Right = Byte; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x2128: + // Window 2 left position + if (Byte != Memory.FillRAM [0x2128]) + { + FLUSH_REDRAW (); + PPU.Window2Left = Byte; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x2129: + // Window 2 right position + if (Byte != Memory.FillRAM [0x2129]) + { + FLUSH_REDRAW (); + PPU.Window2Right = Byte; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x212a: + // Windows 1 & 2 overlap logic for backgrounds 1 - 4 + if (Byte != Memory.FillRAM [0x212a]) + { + FLUSH_REDRAW (); + PPU.ClipWindowOverlapLogic [0] = (Byte & 0x03); + PPU.ClipWindowOverlapLogic [1] = (Byte & 0x0c) >> 2; + PPU.ClipWindowOverlapLogic [2] = (Byte & 0x30) >> 4; + PPU.ClipWindowOverlapLogic [3] = (Byte & 0xc0) >> 6; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x212b: + // Windows 1 & 2 overlap logic for objects and colour window + if (Byte != Memory.FillRAM [0x212b]) + { + FLUSH_REDRAW (); + PPU.ClipWindowOverlapLogic [4] = Byte & 0x03; + PPU.ClipWindowOverlapLogic [5] = (Byte & 0x0c) >> 2; + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x212c: + // Main screen designation (backgrounds 1 - 4 and objects) + if (Byte != Memory.FillRAM [0x212c]) + { + FLUSH_REDRAW (); + PPU.RecomputeClipWindows = TRUE; + Memory.FillRAM [Address] = Byte; + return; + } + break; + case 0x212d: + // Sub-screen designation (backgrounds 1 - 4 and objects) + if (Byte != Memory.FillRAM [0x212d]) + { + FLUSH_REDRAW (); +#ifdef DEBUGGER + if (Byte & 0x1f) + missing.subscreen = 1; +#endif + PPU.RecomputeClipWindows = TRUE; + Memory.FillRAM [Address] = Byte; + return; + } + break; + case 0x212e: + // Window mask designation for main screen ? + if (Byte != Memory.FillRAM [0x212e]) + { + FLUSH_REDRAW (); + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x212f: + // Window mask designation for sub-screen ? + if (Byte != Memory.FillRAM [0x212f]) + { + FLUSH_REDRAW (); + PPU.RecomputeClipWindows = TRUE; + } + break; + case 0x2130: + // Fixed colour addition or screen addition + if (Byte != Memory.FillRAM [0x2130]) + { + FLUSH_REDRAW (); + PPU.RecomputeClipWindows = TRUE; +#ifdef DEBUGGER + if ((Byte & 1) && (PPU.BGMode == 3 || PPU.BGMode == 4 || PPU.BGMode == 7)) + missing.direct = 1; +#endif + } + break; + case 0x2131: + // Colour addition or subtraction select + if (Byte != Memory.FillRAM[0x2131]) + { + FLUSH_REDRAW (); + // Backgrounds 1 - 4, objects and backdrop colour add/sub enable +#ifdef DEBUGGER + if (Byte & 0x80) + { + // Subtract + if (Memory.FillRAM[0x2130] & 0x02) + missing.subscreen_sub = 1; + else + missing.fixed_colour_sub = 1; + } + else + { + // Addition + if (Memory.FillRAM[0x2130] & 0x02) + missing.subscreen_add = 1; + else + missing.fixed_colour_add = 1; + } +#endif + Memory.FillRAM[0x2131] = Byte; + } + break; + case 0x2132: + if (Byte != Memory.FillRAM [0x2132]) + { + FLUSH_REDRAW (); + // Colour data for fixed colour addition/subtraction + if (Byte & 0x80) + PPU.FixedColourBlue = Byte & 0x1f; + if (Byte & 0x40) + PPU.FixedColourGreen = Byte & 0x1f; + if (Byte & 0x20) + PPU.FixedColourRed = Byte & 0x1f; + } + break; + case 0x2133: + // Screen settings + if (Byte != Memory.FillRAM [0x2133]) + { +#ifdef DEBUGGER + if (Byte & 0x40) + missing.mode7_bgmode = 1; + if (Byte & 0x08) + missing.pseudo_512 = 1; +#endif + if((Memory.FillRAM [0x2133] ^ Byte)&8) + { + FLUSH_REDRAW (); + IPPU.PseudoHires = Byte&8; + } + if (Byte & 0x04) + { + PPU.ScreenHeight = SNES_HEIGHT_EXTENDED; + if(IPPU.DoubleHeightPixels) + IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; + else + IPPU.RenderedScreenHeight = PPU.ScreenHeight; +#ifdef DEBUGGER + missing.lines_239 = 1; +#endif + } + else PPU.ScreenHeight = SNES_HEIGHT; + +#ifdef DEBUGGER + if (Byte & 0x02) + missing.sprite_double_height = 1; + + if (Byte & 1) + missing.interlace = 1; +#endif + if((Memory.FillRAM [0x2133] ^ Byte)&3) + { + FLUSH_REDRAW (); + if((Memory.FillRAM [0x2133] ^ Byte)&2) + IPPU.OBJChanged = TRUE; + if(PPU.BGMode==5 || PPU.BGMode==6) + IPPU.Interlace = Byte&1; + IPPU.InterlaceOBJ = Byte&2; + } + + } + break; + case 0x2134: + case 0x2135: + case 0x2136: + // Matrix 16bit x 8bit multiply result (read-only) + return; + + case 0x2137: + // Software latch for horizontal and vertical timers (read-only) + return; + case 0x2138: + // OAM read data (read-only) + return; + case 0x2139: + case 0x213a: + // VRAM read data (read-only) + return; + case 0x213b: + // CG-RAM read data (read-only) + return; + case 0x213c: + case 0x213d: + // Horizontal and vertical (low/high) read counter (read-only) + return; + case 0x213e: + // PPU status (time over and range over) + return; + case 0x213f: + // NTSC/PAL select and field (read-only) + return; + case 0x2140: case 0x2141: case 0x2142: case 0x2143: + case 0x2144: case 0x2145: case 0x2146: case 0x2147: + case 0x2148: case 0x2149: case 0x214a: case 0x214b: + case 0x214c: case 0x214d: case 0x214e: case 0x214f: + case 0x2150: case 0x2151: case 0x2152: case 0x2153: + case 0x2154: case 0x2155: case 0x2156: case 0x2157: + case 0x2158: case 0x2159: case 0x215a: case 0x215b: + case 0x215c: case 0x215d: case 0x215e: case 0x215f: + case 0x2160: case 0x2161: case 0x2162: case 0x2163: + case 0x2164: case 0x2165: case 0x2166: case 0x2167: + case 0x2168: case 0x2169: case 0x216a: case 0x216b: + case 0x216c: case 0x216d: case 0x216e: case 0x216f: + case 0x2170: case 0x2171: case 0x2172: case 0x2173: + case 0x2174: case 0x2175: case 0x2176: case 0x2177: + case 0x2178: case 0x2179: case 0x217a: case 0x217b: + case 0x217c: case 0x217d: case 0x217e: case 0x217f: +#ifdef SPCTOOL + _SPCInPB (Address & 3, Byte); +#else + // CPU.Flags |= DEBUG_MODE_FLAG; + Memory.FillRAM [Address] = Byte; + IAPU.RAM [(Address & 3) + 0xf4] = Byte; +#ifdef SPC700_SHUTDOWN + IAPU.APUExecuting = Settings.APUEnabled; + IAPU.WaitCounter++; +#endif +#endif // SPCTOOL + break; + case 0x2180: + if(!CPU.InWRAM_DMA){ + REGISTER_2180(Byte); + } + break; + case 0x2181: + if(!CPU.InWRAM_DMA){ + PPU.WRAM &= 0x1FF00; + PPU.WRAM |= Byte; + } + break; + case 0x2182: + if(!CPU.InWRAM_DMA){ + PPU.WRAM &= 0x100FF; + PPU.WRAM |= Byte << 8; + } + break; + case 0x2183: + if(!CPU.InWRAM_DMA){ + PPU.WRAM &= 0x0FFFF; + PPU.WRAM |= Byte << 16; + PPU.WRAM &= 0x1FFFF; + } + break; + + case 0x2188: + case 0x2189: + case 0x218a: + case 0x218b: + case 0x218c: + case 0x218d: + case 0x218e: + case 0x218f: + case 0x2190: + case 0x2191: + case 0x2192: + case 0x2193: + case 0x2194: + case 0x2195: + case 0x2196: + case 0x2197: + case 0x2198: + case 0x2199: + case 0x219a: + case 0x219b: + case 0x219c: + case 0x219d: + case 0x219e: + case 0x219f: + if (Settings.BS) + S9xSetBSXPPU(Byte, Address); + break; + } + } + else + { + if (Settings.SA1) + { + if (Address >= 0x2200 && Address <0x23ff) + S9xSetSA1 (Byte, Address); + else + Memory.FillRAM [Address] = Byte; + + return; + } + else + // Dai Kaijyu Monogatari II + if (Address == 0x2801 && Settings.SRTC) + S9xSetSRTC (Byte, Address); + else + if (Address < 0x3000 || Address >= 0x3000 + 768) + { +#ifdef DEBUGGER + missing.unknownppu_write = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register write: $%02X->$%04X\n", + Byte, Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } +#endif + } + else + { + if (!Settings.SuperFX) + { + return; + } + +#ifdef ZSNES_FX + Memory.FillRAM [Address] = Byte; + if (Address < 0x3040) + S9xSuperFXWriteReg (Byte, Address); +#else + switch (Address) + { + case 0x3030: + if ((Memory.FillRAM [0x3030] ^ Byte) & FLG_G) + { + Memory.FillRAM [Address] = Byte; + // Go flag has been changed + if (Byte & FLG_G) + { + if (!SuperFX.oneLineDone) + { + S9xSuperFXExec (); + SuperFX.oneLineDone = TRUE; + } + } + else + FxFlushCache (); + } + else + Memory.FillRAM [Address] = Byte; + break; + + case 0x3031: + Memory.FillRAM [Address] = Byte; + break; + case 0x3033: + Memory.FillRAM [Address] = Byte; + break; + case 0x3034: + Memory.FillRAM [Address] = Byte & 0x7f; + break; + case 0x3036: + Memory.FillRAM [Address] = Byte & 0x7f; + break; + case 0x3037: + Memory.FillRAM [Address] = Byte; + break; + case 0x3038: + Memory.FillRAM [Address] = Byte; + fx_dirtySCBR(); + break; + case 0x3039: + Memory.FillRAM [Address] = Byte; + break; + case 0x303a: + Memory.FillRAM [Address] = Byte; + break; + case 0x303b: + break; + case 0x303c: + Memory.FillRAM [Address] = Byte; + fx_updateRamBank(Byte); + break; + case 0x303f: + Memory.FillRAM [Address] = Byte; + break; + case 0x301f: + Memory.FillRAM [Address] = Byte; + Memory.FillRAM [0x3000 + GSU_SFR] |= FLG_G; + if (!SuperFX.oneLineDone) + { + S9xSuperFXExec (); + SuperFX.oneLineDone = TRUE; + } + return; + + default: + Memory.FillRAM[Address] = Byte; + if (Address >= 0x3100) + { + FxCacheWriteAccess (Address); + } + break; + } +#endif + return; + } + } + Memory.FillRAM[Address] = Byte; + +} + +/******************************************************************************/ +/* S9xGetPPU() */ +/* This function retrieves a PPU Register */ +/******************************************************************************/ +uint8 S9xGetPPU (uint16 Address) +{ + uint8 byte = OpenBus; + + if(Address<0x2100)//not a real PPU reg + return OpenBus; //treat as unmapped memory returning last byte on the bus + + // Take care of DMA wrapping + if(CPU.InDMA && Address>0x21ff) Address=0x2100+(Address&0xff); + + if (Address <= 0x219F) + { + switch (Address) + { + case 0x2100: + case 0x2101: + case 0x2102: + case 0x2103: + #ifdef DEBUGGER + missing.oam_address_read = 1; + #endif + return OpenBus; + + case 0x2104: + case 0x2105: + case 0x2106: + return PPU.OpenBus1; + case 0x2107: + return OpenBus; + case 0x2108: + case 0x2109: + case 0x210a: + return PPU.OpenBus1; + case 0x210b: + case 0x210c: + case 0x210d: + case 0x210e: + case 0x210f: + case 0x2110: + case 0x2111: + case 0x2112: + case 0x2113: + missing.bg_offset_read = 1; + return OpenBus; + + case 0x2114: +#ifdef DEBUGGER + missing.bg_offset_read = 1; +#endif + case 0x2115: + case 0x2116: + return PPU.OpenBus1; + + case 0x2117: + return OpenBus; + + case 0x2118: + case 0x2119: + case 0x211a: + return PPU.OpenBus1; + + case 0x211b: + case 0x211c: + case 0x211d: + case 0x211e: + case 0x211f: + case 0x2120: +#ifdef DEBUGGER + missing.matrix_read = 1; +#endif + return OpenBus; + + case 0x2121: + case 0x2122: + case 0x2123: + return OpenBus; + + case 0x2124: + case 0x2125: + case 0x2126: + return PPU.OpenBus1; + + case 0x2127: + return OpenBus; + + case 0x2128: + case 0x2129: + case 0x212a: + return PPU.OpenBus1; + + case 0x212b: + case 0x212c: + case 0x212d: + case 0x212e: + case 0x212f: + case 0x2130: + case 0x2131: + case 0x2132: + case 0x2133: + return OpenBus; + + case 0x2134: + case 0x2135: + case 0x2136: + // 16bit x 8bit multiply read result. + if (PPU.Need16x8Mulitply) + { + int32 r = (int32) PPU.MatrixA * (int32) (PPU.MatrixB >> 8); + + Memory.FillRAM[0x2134] = (uint8) r; + Memory.FillRAM[0x2135] = (uint8)(r >> 8); + Memory.FillRAM[0x2136] = (uint8)(r >> 16); + PPU.Need16x8Mulitply = FALSE; + } +#ifdef DEBUGGER + missing.matrix_multiply = 1; +#endif + return (PPU.OpenBus1 = Memory.FillRAM[Address]); + case 0x2137: + S9xLatchCounters(0); + return OpenBus; + + case 0x2138: + // Read OAM (sprite) control data + if(PPU.OAMAddr&0x100){ + if (!(PPU.OAMFlip&1)) + { + byte = PPU.OAMData [(PPU.OAMAddr&0x10f) << 1]; + } + else + { + byte = PPU.OAMData [((PPU.OAMAddr&0x10f) << 1) + 1]; + PPU.OAMAddr=(PPU.OAMAddr+1)&0x1ff; + if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; +#ifdef DEBUGGER + missing.sprite_priority_rotation = 1; +#endif + } + } + } else { + if (!(PPU.OAMFlip&1)) + { + byte = PPU.OAMData [PPU.OAMAddr << 1]; + } + else + { + byte = PPU.OAMData [(PPU.OAMAddr << 1) + 1]; + ++PPU.OAMAddr; + if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; +#ifdef DEBUGGER + missing.sprite_priority_rotation = 1; +#endif + } + } + } + PPU.OAMFlip ^= 1; +#ifdef DEBUGGER + missing.oam_read = 1; +#endif + return (PPU.OpenBus1 = byte); + + case 0x2139: + // Read vram low byte +#ifdef DEBUGGER + missing.vram_read = 1; +#endif +#ifdef CORRECT_VRAM_READS + byte = IPPU.VRAMReadBuffer & 0xff; + if (!PPU.VMA.High) + { + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((address << 1) & 0xFFFF)); + } else + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((PPU.VMA.Address << 1) & 0xffff)); + PPU.VMA.Address += PPU.VMA.Increment; + } +#else + if (IPPU.FirstVRAMRead) + byte = Memory.VRAM[(PPU.VMA.Address << 1)&0xFFFF]; + else + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address - 1; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + byte = Memory.VRAM [((address << 1) - 2) & 0xFFFF]; + } + else + byte = Memory.VRAM[((PPU.VMA.Address << 1) - 2) & 0xffff]; + + if (!PPU.VMA.High) + { + PPU.VMA.Address += PPU.VMA.Increment; + IPPU.FirstVRAMRead = FALSE; + } +#endif + PPU.OpenBus1 = byte; + break; + case 0x213A: + // Read vram high byte +#ifdef DEBUGGER + missing.vram_read = 1; +#endif +#ifdef CORRECT_VRAM_READS + byte = (IPPU.VRAMReadBuffer>>8) & 0xff; + if (PPU.VMA.High) + { + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((address << 1) & 0xFFFF)); + } else + IPPU.VRAMReadBuffer = READ_WORD(Memory.VRAM+((PPU.VMA.Address << 1) & 0xffff)); + PPU.VMA.Address += PPU.VMA.Increment; + } +#else + if (IPPU.FirstVRAMRead) + byte = Memory.VRAM[((PPU.VMA.Address << 1) + 1) & 0xffff]; + else + if (PPU.VMA.FullGraphicCount) + { + uint32 addr = PPU.VMA.Address - 1; + uint32 rem = addr & PPU.VMA.Mask1; + uint32 address = (addr & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3); + byte = Memory.VRAM [((address << 1) - 1) & 0xFFFF]; + } + else + byte = Memory.VRAM[((PPU.VMA.Address << 1) - 1) & 0xFFFF]; + if (PPU.VMA.High) + { + PPU.VMA.Address += PPU.VMA.Increment; + IPPU.FirstVRAMRead = FALSE; + } +#endif + PPU.OpenBus1 = byte; + break; + + case 0x213B: + // Read palette data +#ifdef DEBUGGER + missing.cgram_read = 1; +#endif + if (PPU.CGFLIPRead) + byte = PPU.CGDATA [PPU.CGADD++] >> 8; + else + byte = PPU.CGDATA [PPU.CGADD] & 0xff; + + PPU.CGFLIPRead ^= 1; + return (PPU.OpenBus2 = byte); + + case 0x213C: + // Horizontal counter value 0-339 +#ifdef DEBUGGER + missing.h_counter_read = 1; +#endif + S9xTryGunLatch(false); + if (PPU.HBeamFlip) + byte = (PPU.OpenBus2 & 0xfe) | ((PPU.HBeamPosLatched >> 8) & 0x01); + else + byte = (uint8)PPU.HBeamPosLatched; + PPU.OpenBus2 = byte; + PPU.HBeamFlip ^= 1; + break; + + case 0x213D: + // Vertical counter value 0-262 +#ifdef DEBUGGER + missing.v_counter_read = 1; +#endif + S9xTryGunLatch(false); + if (PPU.VBeamFlip) + byte = (PPU.OpenBus2 & 0xfe) | ((PPU.VBeamPosLatched >> 8) & 0x01); + else + byte = (uint8)PPU.VBeamPosLatched; + PPU.OpenBus2 = byte; + PPU.VBeamFlip ^= 1; + break; + + case 0x213E: + // PPU time and range over flags + FLUSH_REDRAW (); + + //so far, 5c77 version is always 1. + return (PPU.OpenBus1 = (Model->_5C77 | PPU.RangeTimeOver)); + + case 0x213F: + // NTSC/PAL and which field flags + S9xTryGunLatch(false); + PPU.VBeamFlip = PPU.HBeamFlip = 0; + //neviksti found a 2 and a 3 here. SNEeSe uses a 3. + byte=((Settings.PAL ? 0x10 : 0) | (Memory.FillRAM[0x213f] & 0xc0) | Model->_5C78) | (PPU.OpenBus2 & 0x20); + Memory.FillRAM[0x213f] &= ~0x40; + return byte; + + case 0x2140: case 0x2141: case 0x2142: case 0x2143: + case 0x2144: case 0x2145: case 0x2146: case 0x2147: + case 0x2148: case 0x2149: case 0x214a: case 0x214b: + case 0x214c: case 0x214d: case 0x214e: case 0x214f: + case 0x2150: case 0x2151: case 0x2152: case 0x2153: + case 0x2154: case 0x2155: case 0x2156: case 0x2157: + case 0x2158: case 0x2159: case 0x215a: case 0x215b: + case 0x215c: case 0x215d: case 0x215e: case 0x215f: + case 0x2160: case 0x2161: case 0x2162: case 0x2163: + case 0x2164: case 0x2165: case 0x2166: case 0x2167: + case 0x2168: case 0x2169: case 0x216a: case 0x216b: + case 0x216c: case 0x216d: case 0x216e: case 0x216f: + case 0x2170: case 0x2171: case 0x2172: case 0x2173: + case 0x2174: case 0x2175: case 0x2176: case 0x2177: + case 0x2178: case 0x2179: case 0x217a: case 0x217b: + case 0x217c: case 0x217d: case 0x217e: case 0x217f: +#ifdef SPCTOOL + return ((uint8) _SPCOutP [Address & 3]); +#else + // CPU.Flags |= DEBUG_MODE_FLAG; +#ifdef SPC700_SHUTDOWN + IAPU.APUExecuting = Settings.APUEnabled; + IAPU.WaitCounter++; +#endif + if (Settings.APUEnabled) + { +#ifdef CPU_SHUTDOWN +// CPU.WaitAddress = CPU.PCAtOpcodeStart; +#endif + if (SNESGameFixes.APU_OutPorts_ReturnValueFix && + Address >= 0x2140 && Address <= 0x2143 && !CPU.V_Counter) + { + return (uint8)((Address & 1) ? ((rand() & 0xff00) >> 8) : + (rand() & 0xff)); + } + + return (APU.OutPorts [Address & 3]); + } + + switch (Settings.SoundSkipMethod) + { + case 0: + case 1: + CPU.BranchSkip = TRUE; + break; + case 2: + break; + case 3: + CPU.BranchSkip = TRUE; + break; + } + if ((Address & 3) < 2) + { + int r = rand (); + if (r & 2) + { + if (r & 4) + return ((Address & 3) == 1 ? 0xaa : 0xbb); + else + return ((r >> 3) & 0xff); + } + } + else + { + int r = rand (); + if (r & 2) + return ((r >> 3) & 0xff); + } + return (Memory.FillRAM[Address]); +#endif // SPCTOOL + + case 0x2180: + // Read WRAM +#ifdef DEBUGGER + missing.wram_read = 1; +#endif + if(!CPU.InWRAM_DMA){ + byte = Memory.RAM [PPU.WRAM++]; + PPU.WRAM &= 0x1FFFF; + } else { + byte=OpenBus; + } + break; + case 0x2181: + case 0x2182: + case 0x2183: + case 0x2184: + case 0x2185: + case 0x2186: + case 0x2187: + return OpenBus; + + case 0x2188: + case 0x2189: + case 0x218a: + case 0x218b: + case 0x218c: + case 0x218d: + case 0x218e: + case 0x218f: + case 0x2190: + case 0x2191: + case 0x2192: + case 0x2193: + case 0x2194: + case 0x2195: + case 0x2196: + case 0x2197: + case 0x2198: + case 0x2199: + case 0x219a: + case 0x219b: + case 0x219c: + case 0x219d: + case 0x219e: + case 0x219f: + if (Settings.BS) + return S9xGetBSXPPU(Address); + else + return OpenBus; + + default: + return OpenBus; + } + } + else + { + if (Settings.SA1) + return (S9xGetSA1 (Address)); + + if (Address <= 0x2fff || Address >= 0x3000 + 768) + { + switch (Address) + { + case 0x21c2: + if(Model->_5C77 ==2) + return (0x20); + + // fprintf(stderr, "Read from $21c2!\n"); + return OpenBus; + case 0x21c3: + if(Model->_5C77 ==2) + return (0); + // fprintf(stderr, "Read from $21c3!\n"); + return OpenBus; + case 0x2800: + // For Dai Kaijyu Monogatari II + if (Settings.SRTC) + return (S9xGetSRTC (Address)); + /*FALL*/ + + default: +#ifdef DEBUGGER + missing.unknownppu_read = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register read: $%04X\n", Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } +#endif + return OpenBus; + } + } + + if (!Settings.SuperFX) + return OpenBus; +#ifdef ZSNES_FX + if (Address < 0x3040) + byte = S9xSuperFXReadReg (Address); + else + byte = Memory.FillRAM [Address]; + +#ifdef CPU_SHUTDOWN + if (Address == 0x3030) + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; +#endif + if (Address == 0x3031) + CLEAR_IRQ_SOURCE (GSU_IRQ_SOURCE); +#else + byte = Memory.FillRAM [Address]; + +//if (Address != 0x3030 && Address != 0x3031) +//printf ("%04x\n", Address); +#ifdef CPU_SHUTDOWN + if (Address == 0x3030) + { + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; + } + else +#endif + if (Address == 0x3031) + { + CLEAR_IRQ_SOURCE (GSU_IRQ_SOURCE); + Memory.FillRAM [0x3031] = byte & 0x7f; + } + return (byte); +#endif + } +// fprintf(stderr, "%03d: %02x from %04x\n", CPU.V_Counter, byte, Address); + return (byte); +} + +/******************************************************************************/ +/* S9xSetCPU() */ +/* This function sets a CPU/DMA Register to a specific byte */ +/******************************************************************************/ +void S9xSetCPU (uint8 byte, uint16 Address) +{ + int d; + bool8 pV; +// fprintf(stderr, "%03d: %02x to %04x\n", CPU.V_Counter, byte, Address); + + if (Address < 0x4200) + { + CPU.Cycles += ONE_CYCLE; + switch (Address) + { + case 0x4016: + S9xSetJoypadLatch(byte&1); + break; + case 0x4017: + break; + default: +#ifdef DEBUGGER + missing.unknowncpu_write = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register register write: $%02X->$%04X\n", + byte, Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } +#endif + break; + } + } + else + switch (Address) + { + case 0x4200: + // NMI, V & H IRQ and joypad reading enable flags + pV = PPU.VTimerEnabled; + + if (byte & 0x20) + { + PPU.VTimerEnabled = TRUE; +#ifdef DEBUGGER + missing.virq = 1; + missing.virq_pos = PPU.IRQVBeamPos; +#endif + } + else + PPU.VTimerEnabled = FALSE; + + if (byte & 0x10) + { + PPU.HTimerEnabled = TRUE; +#ifdef DEBUGGER + missing.hirq = 1; + missing.hirq_pos = PPU.IRQHBeamPos; +#endif + } + else + PPU.HTimerEnabled = FALSE; + + S9xUpdateHVTimerPosition(); + // FIXME + if (pV != PPU.VTimerEnabled) + S9xCheckMissingVTimerPosition(); + + if (!(byte & 0x30)) + CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE); + + if ((byte & 0x80) && + !(Memory.FillRAM [0x4200] & 0x80) && + // NMI can trigger during VBlank as long as NMI_read ($4210) wasn't cleard. + // Panic Bomberman clears the NMI pending flag @ scanline 230 before enabling + // NMIs again. The NMI routine crashes the CPU if it is called without the NMI + // pending flag being set...*/ + CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE && (Memory.FillRAM [0x4210] & 0x80)) + { + // FIXME: triggered at HC=6, checked just before the final CPU cycle, + // then, when to call S9xOpcode_NMI()? + CPU.Flags |= NMI_FLAG; + Timings.NMITriggerPos = CPU.Cycles + 6 + 6; + } + break; + case 0x4201: + if((byte&0x80)==0 && (Memory.FillRAM[0x4213]&0x80)==0x80) + S9xLatchCounters(1); + else + S9xTryGunLatch((byte&0x80)?true:false); + Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = byte; + break; + case 0x4202: + // Multiplier (for multply) + break; + case 0x4203: + { + // Multiplicand + uint32 res = Memory.FillRAM[0x4202] * byte; + + Memory.FillRAM[0x4216] = (uint8) res; + Memory.FillRAM[0x4217] = (uint8) (res >> 8); + break; + } + case 0x4204: + case 0x4205: + // Low and high muliplier (for divide) + break; + case 0x4206: + { + // Divisor + uint16 a = Memory.FillRAM[0x4204] + (Memory.FillRAM[0x4205] << 8); + uint16 div = byte ? a / byte : 0xffff; + uint16 rem = byte ? a % byte : a; + + Memory.FillRAM[0x4214] = (uint8)div; + Memory.FillRAM[0x4215] = div >> 8; + Memory.FillRAM[0x4216] = (uint8)rem; + Memory.FillRAM[0x4217] = rem >> 8; + break; + } + + case 0x4207: + d = PPU.IRQHBeamPos; + PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xFF00) | byte; + + if (PPU.IRQHBeamPos != d) + S9xUpdateHVTimerPosition(); + + break; + + case 0x4208: + d = PPU.IRQHBeamPos; + PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xFF) | ((byte & 1) << 8); + + if (PPU.IRQHBeamPos != d) + S9xUpdateHVTimerPosition(); + + break; + + case 0x4209: + d = PPU.IRQVBeamPos; + PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xFF00) | byte; +#ifdef DEBUGGER + missing.virq_pos = PPU.IRQVBeamPos; +#endif + if (PPU.IRQVBeamPos != d) + { + S9xUpdateHVTimerPosition(); + // FIXME + S9xCheckMissingVTimerPosition(); + } + + break; + + case 0x420A: + d = PPU.IRQVBeamPos; + PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xFF) | ((byte & 1) << 8); +#ifdef DEBUGGER + missing.virq_pos = PPU.IRQVBeamPos; +#endif + if (PPU.IRQVBeamPos != d) + { + S9xUpdateHVTimerPosition(); + // FIXME + S9xCheckMissingVTimerPosition(); + } + + break; + + case 0x420B: + if(CPU.InDMA) return; +#ifdef DEBUGGER + missing.dma_this_frame = byte; + missing.dma_channels = byte; +#endif + // XXX: Not quite right... + if(byte) CPU.Cycles += 18; + if ((byte & 0x01) != 0) + S9xDoDMA (0); + if ((byte & 0x02) != 0) + S9xDoDMA (1); + if ((byte & 0x04) != 0) + S9xDoDMA (2); + if ((byte & 0x08) != 0) + S9xDoDMA (3); + if ((byte & 0x10) != 0) + S9xDoDMA (4); + if ((byte & 0x20) != 0) + S9xDoDMA (5); + if ((byte & 0x40) != 0) + S9xDoDMA (6); + if ((byte & 0x80) != 0) + S9xDoDMA (7); + break; + case 0x420C: + if(CPU.InDMA) return; +#ifdef DEBUGGER + missing.hdma_this_frame |= byte; + missing.hdma_channels |= byte; +#endif + if (Settings.DisableHDMA) + byte = 0; + Memory.FillRAM[0x420c] = byte; + //printf("$%02x is written to $420c at HC:%d, V:%d, IPPU.HDMA:$%02x, IPPU.HDMAEnded:$%02x\n", byte, CPU.Cycles, CPU.V_Counter, IPPU.HDMA, IPPU.HDMAEnded); + // FIXME + // Yoshi's Island / Genjyu Ryodan, Mortal Kombat, Tales of Phantasia + IPPU.HDMA = byte&~IPPU.HDMAEnded; + break; + + case 0x420d: + // Cycle speed 0 - 2.68Mhz, 1 - 3.58Mhz (banks 0x80 +) + if ((byte & 1) != (Memory.FillRAM [0x420d] & 1)) + { + if (byte & 1) + { + CPU.FastROMSpeed = ONE_CYCLE; +#ifdef DEBUGGER + missing.fast_rom = 1; +#endif + } + else CPU.FastROMSpeed = SLOW_ONE_CYCLE; + + Memory.FixROMSpeed (); + } + break; + + case 0x420e: + case 0x420f: + // --->>> Unknown + break; + case 0x4210: + // NMI ocurred flag (reset on read or write) + Memory.FillRAM[0x4210] = Model->_5A22; + return; + case 0x4211: + // IRQ ocurred flag (reset on read or write) + CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE); + break; + case 0x4212: + // v-blank, h-blank and joypad being scanned flags (read-only) + case 0x4213: + // I/O Port (read-only) + case 0x4214: + case 0x4215: + // Quotent of divide (read-only) + case 0x4216: + case 0x4217: + // Multiply product (read-only) + return; + case 0x4218: + case 0x4219: + case 0x421a: + case 0x421b: + case 0x421c: + case 0x421d: + case 0x421e: + case 0x421f: + // Joypad values (read-only) + return; + + case 0x4300: + case 0x4310: + case 0x4320: + case 0x4330: + case 0x4340: + case 0x4350: + case 0x4360: + case 0x4370: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].TransferDirection = (byte&0x80)?1:0; + DMA[d].HDMAIndirectAddressing = (byte&0x40)?1:0; + DMA[d].UnusedBit43x0 = (byte&0x20)?1:0; + DMA[d].AAddressDecrement = (byte&0x10)?1:0; + DMA[d].AAddressFixed = (byte&0x08)?1:0; + DMA[d].TransferMode = (byte & 7); + return; + + case 0x4301: + case 0x4311: + case 0x4321: + case 0x4331: + case 0x4341: + case 0x4351: + case 0x4361: + case 0x4371: + if(CPU.InDMA) return; + DMA[((Address >> 4) & 0x7)].BAddress = byte; + return; + + case 0x4302: + case 0x4312: + case 0x4322: + case 0x4332: + case 0x4342: + case 0x4352: + case 0x4362: + case 0x4372: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].AAddress &= 0xFF00; + DMA[d].AAddress |= byte; + return; + + case 0x4303: + case 0x4313: + case 0x4323: + case 0x4333: + case 0x4343: + case 0x4353: + case 0x4363: + case 0x4373: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].AAddress &= 0xFF; + DMA[d].AAddress |= byte << 8; + return; + + case 0x4304: + case 0x4314: + case 0x4324: + case 0x4334: + case 0x4344: + case 0x4354: + case 0x4364: + case 0x4374: + if(CPU.InDMA) return; + DMA[d=((Address >> 4) & 0x7)].ABank = byte; + HDMAMemPointers[d]=NULL; + return; + + case 0x4305: + case 0x4315: + case 0x4325: + case 0x4335: + case 0x4345: + case 0x4355: + case 0x4365: + case 0x4375: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff00; + DMA[d].DMACount_Or_HDMAIndirectAddress |= byte; + HDMAMemPointers[d]=NULL; + return; + + case 0x4306: + case 0x4316: + case 0x4326: + case 0x4336: + case 0x4346: + case 0x4356: + case 0x4366: + case 0x4376: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff; + DMA[d].DMACount_Or_HDMAIndirectAddress |= byte << 8; + HDMAMemPointers[d]=NULL; + return; + + case 0x4307: + case 0x4317: + case 0x4327: + case 0x4337: + case 0x4347: + case 0x4357: + case 0x4367: + case 0x4377: + if(CPU.InDMA) return; + DMA[d = ((Address >> 4) & 0x7)].IndirectBank = byte; + HDMAMemPointers[d]=NULL; + return; + + case 0x4308: + case 0x4318: + case 0x4328: + case 0x4338: + case 0x4348: + case 0x4358: + case 0x4368: + case 0x4378: + if(CPU.InDMA) return; + d = (Address >> 4) & 7; + DMA[d].Address &= 0xff00; + DMA[d].Address |= byte; + HDMAMemPointers[d] = NULL; + return; + + case 0x4309: + case 0x4319: + case 0x4329: + case 0x4339: + case 0x4349: + case 0x4359: + case 0x4369: + case 0x4379: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + DMA[d].Address &= 0xff; + DMA[d].Address |= byte << 8; + HDMAMemPointers[d] = NULL; + return; + + case 0x430A: + case 0x431A: + case 0x432A: + case 0x433A: + case 0x434A: + case 0x435A: + case 0x436A: + case 0x437A: + if(CPU.InDMA) return; + d = (Address >> 4) & 0x7; + if(byte&0x7f){ + DMA[d].LineCount = byte & 0x7f; + DMA[d].Repeat = !(byte & 0x80); + } else { + DMA[d].LineCount = 128; + DMA[d].Repeat = !!(byte & 0x80); + } + //printf("$%02x is written to $43%da at HC:%d, V:%d, IPPU.HDMA:$%02x, IPPU.HDMAEnded:$%02x\n", byte, d, CPU.Cycles, CPU.V_Counter, IPPU.HDMA, IPPU.HDMAEnded); + return; + + case 0x430B: + case 0x431B: + case 0x432B: + case 0x433B: + case 0x434B: + case 0x435B: + case 0x436B: + case 0x437B: + case 0x430F: + case 0x431F: + case 0x432F: + case 0x433F: + case 0x434F: + case 0x435F: + case 0x436F: + case 0x437F: + if(CPU.InDMA) return; + DMA[((Address >> 4) & 0x7)].UnknownByte = byte; + return; + + //These registers are used by both the S-DD1 and the SPC7110 + case 0x4800: + case 0x4801: + case 0x4802: + case 0x4803: + if(Settings.SPC7110) + S9xSetSPC7110(byte, Address); + //printf ("%02x->%04x\n", byte, Address); + break; + + case 0x4804: + case 0x4805: + case 0x4806: + case 0x4807: + //printf ("%02x->%04x\n", byte, Address); + if(Settings.SPC7110) + S9xSetSPC7110(byte, Address); + else S9xSetSDD1MemoryMap (Address - 0x4804, byte & 7); + break; + + //these are used by the SPC7110 + case 0x4808: + case 0x4809: + case 0x480A: + case 0x480B: + case 0x480C: + case 0x4810: + case 0x4811: + case 0x4812: + case 0x4813: + case 0x4814: + case 0x4815: + case 0x4816: + case 0x4817: + case 0x4818: + case 0x481A: + case 0x4820: + case 0x4821: + case 0x4822: + case 0x4823: + case 0x4824: + case 0x4825: + case 0x4826: + case 0x4827: + case 0x4828: + case 0x4829: + case 0x482A: + case 0x482B: + case 0x482C: + case 0x482D: + case 0x482E: + case 0x482F: + case 0x4830: + case 0x4831: + case 0x4832: + case 0x4833: + case 0x4834: + case 0x4840: + case 0x4841: + case 0x4842: + if(Settings.SPC7110) + { + S9xSetSPC7110(byte, Address); + break; + } + + default: +#ifdef DEBUGGER + missing.unknowncpu_write = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register write: $%02X->$%04X\n", + byte, Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } +#endif + break; + } + Memory.FillRAM [Address] = byte; +} + +/******************************************************************************/ +/* S9xGetCPU() */ +/* This function retrieves a CPU/DMA Register */ +/******************************************************************************/ +uint8 S9xGetCPU (uint16 Address) +{ + int d; + uint8 byte; +// fprintf(stderr, "read from %04x\n", Address); + + if (Address < 0x4200) + { + CPU.Cycles += ONE_CYCLE; + switch (Address) + { + case 0x4016: + case 0x4017: + return S9xReadJOYSERn(Address); + default: +#ifdef DEBUGGER + missing.unknowncpu_read = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register read: $%04X\n", Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } +#endif + return OpenBus; + + } +// return (Memory.FillRAM [Address]); + } + else + switch (Address) + { + case 0x4200: + case 0x4201: + case 0x4202: + case 0x4203: + case 0x4204: + case 0x4205: + case 0x4206: + case 0x4207: + case 0x4208: + case 0x4209: + case 0x420a: + case 0x420b: + case 0x420c: + case 0x420d: + case 0x420e: + case 0x420f: + return OpenBus; + + case 0x4210: +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; +#endif + byte = Memory.FillRAM[0x4210]; + Memory.FillRAM[0x4210] = Model->_5A22; + //SNEeSe returns 2 for 5A22 version. + return ((byte&0x80)|(OpenBus&0x70)|Model->_5A22); + + case 0x4211: + byte = (CPU.IRQActive & (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE)) ? 0x80 : 0; +// // Super Robot Wars Ex ROM bug requires this. +// Let's try without, now that we have Open Bus emulation? +// byte |= CPU.Cycles >= Timings.HBlankStart ? 0x40 : 0; + CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE); + byte |= OpenBus&0x7f; + + return (byte); + + case 0x4212: + // V-blank, h-blank and joypads being read flags (read-only) +#ifdef CPU_SHUTDOWN + CPU.WaitAddress = CPU.PBPCAtOpcodeStart; +#endif + return (REGISTER_4212()|(OpenBus&0x3E)); + + case 0x4213: + // I/O port input - returns 0 wherever $4201 is 0, and 1 elsewhere + // unless something else pulls it down (i.e. a gun) + return Memory.FillRAM[0x4213]; + + case 0x4214: + case 0x4215: + // Quotient of divide result + case 0x4216: + case 0x4217: + // Multiplcation result (for multiply) or remainder of + // divison. + return (Memory.FillRAM[Address]); + case 0x4218: + case 0x4219: + case 0x421a: + case 0x421b: + case 0x421c: + case 0x421d: + case 0x421e: + case 0x421f: + // Joypads 1-4 button and direction state. + return (Memory.FillRAM [Address]); + + case 0x4300: + case 0x4310: + case 0x4320: + case 0x4330: + case 0x4340: + case 0x4350: + case 0x4360: + case 0x4370: + if(CPU.InDMA) return OpenBus; + d = (Address >> 4) & 0x7; + return ((DMA[d].TransferDirection?0x80:0x00) | + (DMA[d].HDMAIndirectAddressing?0x40:0x00) | + (DMA[d].UnusedBit43x0?0x20:0x00) | + (DMA[d].AAddressDecrement?0x10:0x00) | + (DMA[d].AAddressFixed?0x08:0x00) | + (DMA[d].TransferMode & 7)); + + case 0x4301: + case 0x4311: + case 0x4321: + case 0x4331: + case 0x4341: + case 0x4351: + case 0x4361: + case 0x4371: + if(CPU.InDMA) return OpenBus; + return DMA[((Address >> 4) & 0x7)].BAddress; + + case 0x4302: + case 0x4312: + case 0x4322: + case 0x4332: + case 0x4342: + case 0x4352: + case 0x4362: + case 0x4372: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].AAddress & 0xFF); + + case 0x4303: + case 0x4313: + case 0x4323: + case 0x4333: + case 0x4343: + case 0x4353: + case 0x4363: + case 0x4373: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].AAddress >> 8); + + case 0x4304: + case 0x4314: + case 0x4324: + case 0x4334: + case 0x4344: + case 0x4354: + case 0x4364: + case 0x4374: + if(CPU.InDMA) return OpenBus; + return DMA[((Address >> 4) & 0x7)].ABank; + + case 0x4305: + case 0x4315: + case 0x4325: + case 0x4335: + case 0x4345: + case 0x4355: + case 0x4365: + case 0x4375: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].DMACount_Or_HDMAIndirectAddress & 0xff); + + case 0x4306: + case 0x4316: + case 0x4326: + case 0x4336: + case 0x4346: + case 0x4356: + case 0x4366: + case 0x4376: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].DMACount_Or_HDMAIndirectAddress >> 8); + + case 0x4307: + case 0x4317: + case 0x4327: + case 0x4337: + case 0x4347: + case 0x4357: + case 0x4367: + case 0x4377: + if(CPU.InDMA) return OpenBus; + return DMA[((Address >> 4) & 0x7)].IndirectBank; + + case 0x4308: + case 0x4318: + case 0x4328: + case 0x4338: + case 0x4348: + case 0x4358: + case 0x4368: + case 0x4378: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].Address & 0xFF); + + case 0x4309: + case 0x4319: + case 0x4329: + case 0x4339: + case 0x4349: + case 0x4359: + case 0x4369: + case 0x4379: + if(CPU.InDMA) return OpenBus; + return (DMA[((Address >> 4) & 0x7)].Address >> 8); + + case 0x430A: + case 0x431A: + case 0x432A: + case 0x433A: + case 0x434A: + case 0x435A: + case 0x436A: + case 0x437A: + if(CPU.InDMA) return OpenBus; + d = (Address >> 4) & 0x7; + return (DMA[d].LineCount ^ (DMA[d].Repeat?0x00:0x80)); + + case 0x430B: + case 0x431B: + case 0x432B: + case 0x433B: + case 0x434B: + case 0x435B: + case 0x436B: + case 0x437B: + case 0x430F: + case 0x431F: + case 0x432F: + case 0x433F: + case 0x434F: + case 0x435F: + case 0x436F: + case 0x437F: + if(CPU.InDMA) return OpenBus; + return DMA[((Address >> 4) & 0x7)].UnknownByte; + + default: +#ifdef DEBUGGER + missing.unknowncpu_read = Address; + if (Settings.TraceUnknownRegisters) + { + sprintf (String, "Unknown register read: $%04X\n", Address); + S9xMessage (S9X_TRACE, S9X_PPU_TRACE, String); + } + +#endif + + if(Address>= 0x4800&&Settings.SPC7110) + return S9xGetSPC7110(Address); + + if(Address>=0x4800&&Address<=0x4807&&Settings.SDD1) + { + return Memory.FillRAM[Address]; + } + + return OpenBus; + } +} + +void S9xResetPPU () +{ + S9xSoftResetPPU(); + S9xControlsReset(); + IPPU.PreviousLine = IPPU.CurrentLine = 0; +} + +void S9xSoftResetPPU () +{ + S9xControlsSoftReset(); + PPU.BGMode = 0; + PPU.BG3Priority = 0; + PPU.Brightness = 0; + PPU.VMA.High = 0; + PPU.VMA.Increment = 1; + PPU.VMA.Address = 0; + PPU.VMA.FullGraphicCount = 0; + PPU.VMA.Shift = 0; + + for (uint8 B = 0; B != 4; B++) + { + PPU.BG[B].SCBase = 0; + PPU.BG[B].VOffset = 0; + PPU.BG[B].HOffset = 0; + PPU.BG[B].BGSize = 0; + PPU.BG[B].NameBase = 0; + PPU.BG[B].SCSize = 0; + + PPU.ClipCounts[B] = 0; + PPU.ClipWindowOverlapLogic [B] = CLIP_OR; + PPU.ClipWindow1Enable[B] = FALSE; + PPU.ClipWindow2Enable[B] = FALSE; + PPU.ClipWindow1Inside[B] = TRUE; + PPU.ClipWindow2Inside[B] = TRUE; + } + + PPU.ClipCounts[4] = 0; + PPU.ClipCounts[5] = 0; + PPU.ClipWindowOverlapLogic[4] = PPU.ClipWindowOverlapLogic[5] = CLIP_OR; + PPU.ClipWindow1Enable[4] = PPU.ClipWindow1Enable[5] = FALSE; + PPU.ClipWindow2Enable[4] = PPU.ClipWindow2Enable[5] = FALSE; + PPU.ClipWindow1Inside[4] = PPU.ClipWindow1Inside[5] = TRUE; + PPU.ClipWindow2Inside[4] = PPU.ClipWindow2Inside[5] = TRUE; + + PPU.CGFLIP = 0; + int c; + for (c = 0; c < 256; c++) + { + IPPU.Red [c] = (c & 7) << 2; + IPPU.Green [c] = ((c >> 3) & 7) << 2; + IPPU.Blue [c] = ((c >> 6) & 2) << 3; + PPU.CGDATA [c] = IPPU.Red [c] | (IPPU.Green [c] << 5) | + (IPPU.Blue [c] << 10); + } + + PPU.FirstSprite = 0; + PPU.LastSprite = 127; + for (int Sprite = 0; Sprite < 128; Sprite++) + { + PPU.OBJ[Sprite].HPos = 0; + PPU.OBJ[Sprite].VPos = 0; + PPU.OBJ[Sprite].VFlip = 0; + PPU.OBJ[Sprite].HFlip = 0; + PPU.OBJ[Sprite].Priority = 0; + PPU.OBJ[Sprite].Palette = 0; + PPU.OBJ[Sprite].Name = 0; + PPU.OBJ[Sprite].Size = 0; + } + PPU.OAMPriorityRotation = 0; + PPU.OAMWriteRegister = 0; + PPU.RangeTimeOver = 0; + PPU.OpenBus1 = 0; + PPU.OpenBus2 = 0; + + PPU.OAMFlip = 0; + PPU.OAMTileAddress = 0; + PPU.OAMAddr = 0; + PPU.IRQVBeamPos = 0; + PPU.IRQHBeamPos = 0; + PPU.VBeamPosLatched = 0; + PPU.HBeamPosLatched = 0; + + PPU.HBeamFlip = 0; + PPU.VBeamFlip = 0; + PPU.HVBeamCounterLatched = 0; + PPU.GunVLatch=1000; + PPU.GunHLatch=0; + + PPU.MatrixA = PPU.MatrixB = PPU.MatrixC = PPU.MatrixD = 0; + PPU.CentreX = PPU.CentreY = 0; + PPU.CGADD = 0; + PPU.FixedColourRed = PPU.FixedColourGreen = PPU.FixedColourBlue = 0; + PPU.SavedOAMAddr = 0; + PPU.ScreenHeight = SNES_HEIGHT; + PPU.WRAM = 0; + PPU.BG_Forced = 0; + PPU.ForcedBlanking = TRUE; + PPU.OBJThroughMain = FALSE; + PPU.OBJThroughSub = FALSE; + PPU.OBJSizeSelect = 0; + PPU.OBJNameSelect = 0; + PPU.OBJNameBase = 0; + PPU.OBJAddition = FALSE; + PPU.OAMReadFlip = 0; + PPU.BGnxOFSbyte = 0; + ZeroMemory (PPU.OAMData, 512 + 32); + + PPU.VTimerEnabled = FALSE; + PPU.HTimerEnabled = FALSE; + PPU.HTimerPosition = Timings.H_Max + 1; + PPU.VTimerPosition = Timings.V_Max + 1; + PPU.Mosaic = 0; + PPU.BGMosaic [0] = PPU.BGMosaic [1] = FALSE; + PPU.BGMosaic [2] = PPU.BGMosaic [3] = FALSE; + PPU.Mode7HFlip = FALSE; + PPU.Mode7VFlip = FALSE; + PPU.Mode7Repeat = 0; + PPU.Window1Left = 1; + PPU.Window1Right = 0; + PPU.Window2Left = 1; + PPU.Window2Right = 0; + PPU.RecomputeClipWindows = TRUE; + PPU.CGFLIPRead = 0; + PPU.Need16x8Mulitply = FALSE; + + IPPU.ColorsChanged = TRUE; + IPPU.HDMA = 0; + IPPU.HDMAEnded = 0; + IPPU.MaxBrightness = 0; + IPPU.LatchedBlanking = 0; + IPPU.OBJChanged = TRUE; + IPPU.RenderThisFrame = TRUE; + IPPU.DirectColourMapsNeedRebuild = TRUE; + IPPU.FrameCount = 0; + IPPU.RenderedFramesCount = 0; + IPPU.DisplayedRenderedFrameCount = 0; + IPPU.SkippedFrames = 0; + IPPU.FrameSkip = 0; + ZeroMemory (IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_2BIT_EVEN], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_2BIT_ODD], MAX_2BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT_EVEN], MAX_4BIT_TILES); + ZeroMemory (IPPU.TileCached [TILE_4BIT_ODD], MAX_4BIT_TILES); +#ifdef CORRECT_VRAM_READS + IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better? +#else + IPPU.FirstVRAMRead = FALSE; +#endif + IPPU.Interlace = FALSE; + IPPU.InterlaceOBJ = FALSE; + IPPU.DoubleWidthPixels = FALSE; + IPPU.DoubleHeightPixels = FALSE; + IPPU.RenderedScreenWidth = SNES_WIDTH; + IPPU.RenderedScreenHeight = SNES_HEIGHT; + IPPU.XB = NULL; + for (c = 0; c < 256; c++) + IPPU.ScreenColors [c] = c; + S9xFixColourBrightness (); + IPPU.PreviousLine = IPPU.CurrentLine = 0; + + for (c = 0; c < 2; c++) + memset (&IPPU.Clip [c], 0, sizeof (struct ClipData)); + + for (c = 0; c < 0x8000; c += 0x100) + memset (&Memory.FillRAM [c], c >> 8, 0x100); + + ZeroMemory (&Memory.FillRAM [0x2100], 0x100); + ZeroMemory (&Memory.FillRAM [0x4200], 0x100); + ZeroMemory (&Memory.FillRAM [0x4000], 0x100); + // For BS Suttehakkun 2... + ZeroMemory (&Memory.FillRAM [0x1000], 0x1000); + + Memory.FillRAM[0x4201]=Memory.FillRAM[0x4213]=0xFF; +} + +#ifndef ZSNES_FX +void S9xSuperFXExec () +{ +#if 1 + if (Settings.SuperFX) + { + if ((Memory.FillRAM [0x3000 + GSU_SFR] & FLG_G) && + (Memory.FillRAM [0x3000 + GSU_SCMR] & 0x18) == 0x18) + { + FxEmulate ((Memory.FillRAM [0x3000 + GSU_CLSR] & 1) ? SuperFX.speedPerLine * 2 : SuperFX.speedPerLine); + int GSUStatus = Memory.FillRAM [0x3000 + GSU_SFR] | + (Memory.FillRAM [0x3000 + GSU_SFR + 1] << 8); + if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ) + { + // Trigger a GSU IRQ. + S9xSetIRQ (GSU_IRQ_SOURCE); + } + } + } +#else + uint32 tmp = (Memory.FillRAM[0x3034] << 16) + *(uint16 *) &Memory.FillRAM [0x301e]; + +#if 0 + if (tmp == 0x018428) + { + *(uint16 *) &SRAM [0x0064] = 0xbc00; + *(uint16 *) &SRAM [0x002c] = 0x8000; + } +#endif + if (tmp == -1)//0x018428) //0x01bfc3) //0x09edaf) //-1) //0x57edaf) + { + while (Memory.FillRAM [0x3030] & 0x20) + { + int i; + int32 vError; + uint8 avReg[0x40]; + char tmp[128]; + uint8 vPipe; + uint8 vColr; + uint8 vPor; + + FxPipeString (tmp); + /* Make the string 32 chars long */ + if(strlen(tmp) < 32) { memset(&tmp[strlen(tmp)],' ',32-strlen(tmp)); tmp[32] = 0; } + + /* Copy registers (so we can see if any changed) */ + vColr = FxGetColorRegister(); + vPor = FxGetPlotOptionRegister(); + memcpy(avReg,SuperFX.pvRegisters,0x40); + + /* Print the pipe string */ + printf(tmp); + + /* Execute the instruction in the pipe */ + vPipe = FxPipe(); + vError = FxEmulate(1); + + /* Check if any registers changed (and print them if they did) */ + for(i=0; i<16; i++) + { + uint32 a = 0; + uint32 r1 = ((uint32)avReg[i*2]) | (((uint32)avReg[(i*2)+1])<<8); + uint32 r2 = (uint32)(SuperFX.pvRegisters[i*2]) | (((uint32)SuperFX.pvRegisters[(i*2)+1])<<8); + if(i==15) + a = OPCODE_BYTES(vPipe); + if(((r1+a)&0xffff) != r2) + printf(" r%d=$%04x",i,r2); + } + { + /* Check SFR */ + uint32 r1 = ((uint32)avReg[0x30]) | (((uint32)avReg[0x31])<<8); + uint32 r2 = (uint32)(SuperFX.pvRegisters[0x30]) | (((uint32)SuperFX.pvRegisters[0x31])<<8); + if((r1&(1<<1)) != (r2&(1<<1))) + printf(" Z=%d",(uint32)(!!(r2&(1<<1)))); + if((r1&(1<<2)) != (r2&(1<<2))) + printf(" CY=%d",(uint32)(!!(r2&(1<<2)))); + if((r1&(1<<3)) != (r2&(1<<3))) + printf(" S=%d",(uint32)(!!(r2&(1<<3)))); + if((r1&(1<<4)) != (r2&(1<<4))) + printf(" OV=%d",(uint32)(!!(r2&(1<<4)))); + if((r1&(1<<5)) != (r2&(1<<5))) + printf(" G=%d",(uint32)(!!(r2&(1<<5)))); + if((r1&(1<<6)) != (r2&(1<<6))) + printf(" R=%d",(uint32)(!!(r2&(1<<6)))); + if((r1&(1<<8)) != (r2&(1<<8))) + printf(" ALT1=%d",(uint32)(!!(r2&(1<<8)))); + if((r1&(1<<9)) != (r2&(1<<9))) + printf(" ALT2=%d",(uint32)(!!(r2&(1<<9)))); + if((r1&(1<<10)) != (r2&(1<<10))) + printf(" IL=%d",(uint32)(!!(r2&(1<<10)))); + if((r1&(1<<11)) != (r2&(1<<11))) + printf(" IH=%d",(uint32)(!!(r2&(1<<11)))); + if((r1&(1<<12)) != (r2&(1<<12))) + printf(" B=%d",(uint32)(!!(r2&(1<<12)))); + if((r1&(1<<15)) != (r2&(1<<15))) + printf(" IRQ=%d",(uint32)(!!(r2&(1<<15)))); + } + { + /* Check PBR */ + uint32 r1 = ((uint32)avReg[0x34]); + uint32 r2 = (uint32)(SuperFX.pvRegisters[0x34]); + if(r1 != r2) + printf(" PBR=$%02x",r2); + } + { + /* Check ROMBR */ + uint32 r1 = ((uint32)avReg[0x36]); + uint32 r2 = (uint32)(SuperFX.pvRegisters[0x36]); + if(r1 != r2) + printf(" ROMBR=$%02x",r2); + } + { + /* Check RAMBR */ + uint32 r1 = ((uint32)avReg[0x3c]); + uint32 r2 = (uint32)(SuperFX.pvRegisters[0x3c]); + if(r1 != r2) + printf(" RAMBR=$%02x",r2); + } + { + /* Check CBR */ + uint32 r1 = ((uint32)avReg[0x3e]) | (((uint32)avReg[0x3f])<<8); + uint32 r2 = (uint32)(SuperFX.pvRegisters[0x3e]) | (((uint32)SuperFX.pvRegisters[0x3f])<<8); + if(r1 != r2) + printf(" CBR=$%04x",r2); + } + { + /* Check COLR */ + if(vColr != FxGetColorRegister()) + printf(" COLR=$%02x",FxGetColorRegister()); + } + { + /* Check POR */ + if(vPor != FxGetPlotOptionRegister()) + printf(" POR=$%02x",FxGetPlotOptionRegister()); + } + printf ("\n"); + } + S9xExit (); + } + else + { + uint32 t = (Memory.FillRAM [0x3034] << 16) + + (Memory.FillRAM [0x301f] << 8) + + (Memory.FillRAM [0x301e] << 0); + +printf ("%06x: %d\n", t, FxEmulate (2000000)); +// FxEmulate (2000000); + } +#if 0 + if (!(CPU.Flags & TRACE_FLAG)) + { + static int z = 1; + if (z == 0) + { + extern FILE *trace; + CPU.Flags |= TRACE_FLAG; + trace = fopen ("trace.log", "wb"); + } + else + z--; + } +#endif + Memory.FillRAM [0x3030] &= ~0x20; + if (Memory.FillRAM [0x3031] & 0x80) + { + S9xSetIRQ (GSU_IRQ_SOURCE); + } +#endif +} +#endif + diff --git a/source/snes9x/ppu.h b/source/snes9x/ppu.h new file mode 100644 index 0000000..5da6a60 --- /dev/null +++ b/source/snes9x/ppu.h @@ -0,0 +1,744 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _PPU_H_ +#define _PPU_H_ + +#define FIRST_VISIBLE_LINE 1 + +extern uint8 GetBank; +extern uint16 SignExtend [2]; + +#define TILE_2BIT 0 +#define TILE_4BIT 1 +#define TILE_8BIT 2 +#define TILE_2BIT_EVEN 3 +#define TILE_2BIT_ODD 4 +#define TILE_4BIT_EVEN 5 +#define TILE_4BIT_ODD 6 + +#define MAX_2BIT_TILES 4096 +#define MAX_4BIT_TILES 2048 +#define MAX_8BIT_TILES 1024 + +#define PPU_H_BEAM_IRQ_SOURCE (1 << 0) +#define PPU_V_BEAM_IRQ_SOURCE (1 << 1) +#define GSU_IRQ_SOURCE (1 << 2) +#define SA1_IRQ_SOURCE (1 << 7) +#define SA1_DMA_IRQ_SOURCE (1 << 5) + +struct ClipData { + uint8 Count; + uint8 DrawMode[6]; + uint16 Left[6]; + uint16 Right[6]; +}; + +struct InternalPPU { + bool8 ColorsChanged; + uint8 HDMA; + uint8 HDMAEnded; + uint8 MaxBrightness; + bool8 LatchedBlanking; + bool8 OBJChanged; + bool8 RenderThisFrame; + bool8 DirectColourMapsNeedRebuild; + uint32 FrameCount; + uint32 RenderedFramesCount; + uint32 DisplayedRenderedFrameCount; + uint32 SkippedFrames; + uint32 FrameSkip; + uint8 *TileCache [7]; + uint8 *TileCached [7]; +#ifdef CORRECT_VRAM_READS + uint16 VRAMReadBuffer; +#else + bool8 FirstVRAMRead; +#endif + bool8 Interlace; + bool8 InterlaceOBJ; + bool8 PseudoHires; + bool8 DoubleWidthPixels; + bool8 DoubleHeightPixels; + int RenderedScreenHeight; + int RenderedScreenWidth; + uint32 Red [256]; + uint32 Green [256]; + uint32 Blue [256]; + uint8 *XB; + uint16 ScreenColors [256]; + int PreviousLine; + int CurrentLine; + struct ClipData Clip[2][6]; +}; + +struct SOBJ +{ + short HPos; + uint16 VPos; + uint16 Name; + uint8 VFlip; + uint8 HFlip; + uint8 Priority; + uint8 Palette; + uint8 Size; +}; + +struct SPPU { + uint8 BGMode; + uint8 BG3Priority; + uint8 Brightness; + + struct { + bool8 High; + uint8 Increment; + uint16 Address; + uint16 Mask1; + uint16 FullGraphicCount; + uint16 Shift; + } VMA; + + struct { + uint16 SCBase; + uint16 VOffset; + uint16 HOffset; + uint8 BGSize; + uint16 NameBase; + uint16 SCSize; + } BG [4]; + + bool8 CGFLIP; + uint16 CGDATA [256]; + uint8 FirstSprite; + uint8 LastSprite; + struct SOBJ OBJ [128]; + uint8 OAMPriorityRotation; + uint16 OAMAddr; + uint8 RangeTimeOver; + + uint8 OAMFlip; + uint16 OAMTileAddress; + uint16 IRQVBeamPos; + uint16 IRQHBeamPos; + uint16 VBeamPosLatched; + uint16 HBeamPosLatched; + + uint8 HBeamFlip; + uint8 VBeamFlip; + uint8 HVBeamCounterLatched; + + short MatrixA; + short MatrixB; + short MatrixC; + short MatrixD; + short CentreX; + short CentreY; + short M7HOFS; + short M7VOFS; + + uint8 CGADD; + uint8 FixedColourRed; + uint8 FixedColourGreen; + uint8 FixedColourBlue; + uint16 SavedOAMAddr; + uint16 ScreenHeight; + uint32 WRAM; + uint8 BG_Forced; + bool8 ForcedBlanking; + bool8 OBJThroughMain; + bool8 OBJThroughSub; + uint8 OBJSizeSelect; + uint16 OBJNameBase; + bool8 OBJAddition; + uint8 OAMReadFlip; + uint8 OAMData [512 + 32]; + bool8 VTimerEnabled; + bool8 HTimerEnabled; + short HTimerPosition; + uint8 Mosaic; + uint8 MosaicStart; + bool8 BGMosaic [4]; + bool8 Mode7HFlip; + bool8 Mode7VFlip; + uint8 Mode7Repeat; + uint8 Window1Left; + uint8 Window1Right; + uint8 Window2Left; + uint8 Window2Right; + uint8 ClipCounts [6]; + uint8 ClipWindowOverlapLogic [6]; + uint8 ClipWindow1Enable [6]; + uint8 ClipWindow2Enable [6]; + bool8 ClipWindow1Inside [6]; + bool8 ClipWindow2Inside [6]; + bool8 RecomputeClipWindows; + uint8 CGFLIPRead; + uint16 OBJNameSelect; + bool8 Need16x8Mulitply; + + uint16 OAMWriteRegister; + uint8 BGnxOFSbyte; + uint8 M7byte; + uint8 OpenBus1; + uint8 OpenBus2; + uint16 GunVLatch; + uint16 GunHLatch; + short VTimerPosition; +}; + +#define CLIP_OR 0 +#define CLIP_AND 1 +#define CLIP_XOR 2 +#define CLIP_XNOR 3 + +struct SDMA { + /* $43x0 */ + bool8 TransferDirection; + bool8 HDMAIndirectAddressing; + bool8 UnusedBit43x0; + bool8 AAddressFixed; + bool8 AAddressDecrement; + uint8 TransferMode; + + /* $43x1 */ + uint8 BAddress; + + /* $43x2-4 */ + uint16 AAddress; + uint8 ABank; + + /* $43x5-6 */ + uint16 DMACount_Or_HDMAIndirectAddress; + + /* $43x7 */ + uint8 IndirectBank; + + /* $43x8-9 */ + uint16 Address; + + /* $43xA */ + uint8 Repeat; + uint8 LineCount; + + /* $43xB/F */ + uint8 UnknownByte; + + /* internal */ + uint8 DoTransfer; +}; +#define TransferBytes DMACount_Or_HDMAIndirectAddress +#define IndirectAddress DMACount_Or_HDMAIndirectAddress + +START_EXTERN_C +void S9xUpdateScreen (); +void S9xResetPPU (); +void S9xSoftResetPPU (); +void S9xFixColourBrightness (); +void S9xDoAutoJoypad (); +void S9xSuperFXExec (); + +void S9xSetPPU (uint8 Byte, uint16 Address); +uint8 S9xGetPPU (uint16 Address); +void S9xSetCPU (uint8 Byte, uint16 Address); +uint8 S9xGetCPU (uint16 Address); + +void S9xInitC4 (); +void S9xSetC4 (uint8 Byte, uint16 Address); +uint8 S9xGetC4 (uint16 Address); +void S9xSetC4RAM (uint8 Byte, uint16 Address); +uint8 S9xGetC4RAM (uint16 Address); +uint8 *S9xGetBasePointerC4 (uint16 Address); + +void S9xUpdateHVTimerPosition (void); +void S9xCheckMissingHTimerPosition (int32); +void S9xCheckMissingHTimerPositionRange (int32, int32); +void S9xCheckMissingVTimerPosition (void); + +extern struct SPPU PPU; +extern struct SDMA DMA [8]; +extern struct InternalPPU IPPU; +END_EXTERN_C + +#include "gfx.h" +#include "memmap.h" + +typedef struct{ + uint8 _5C77; + uint8 _5C78; + uint8 _5A22; +} SnesModel; + +extern SnesModel* Model; +extern SnesModel M1SNES; +extern SnesModel M2SNES; + +#define MAX_5C77_VERSION 0x01 +#define MAX_5C78_VERSION 0x03 +#define MAX_5A22_VERSION 0x02 + +STATIC inline uint8 REGISTER_4212() +{ + GetBank = 0; + if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE && + CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3) + GetBank = 1; + + GetBank |= CPU.Cycles >= Timings.HBlankStart ? 0x40 : 0; + if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE) + GetBank |= 0x80; /* XXX: 0x80 or 0xc0 ? */ + + return (GetBank); +} + +STATIC inline void FLUSH_REDRAW () +{ + if (IPPU.PreviousLine != IPPU.CurrentLine) + S9xUpdateScreen (); +} + +STATIC inline void REGISTER_2104 (uint8 byte) +{ + if (PPU.OAMAddr & 0x100) + { + int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1); + if (byte != PPU.OAMData [addr]){ + FLUSH_REDRAW (); + PPU.OAMData [addr] = byte; + IPPU.OBJChanged = TRUE; + + // X position high bit, and sprite size (x4) + struct SOBJ *pObj = &PPU.OBJ [(addr & 0x1f) * 4]; + + pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 0) & 1]; + pObj++->Size = byte & 2; + pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 2) & 1]; + pObj++->Size = byte & 8; + pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 4) & 1]; + pObj++->Size = byte & 32; + pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(byte >> 6) & 1]; + pObj->Size = byte & 128; + } + PPU.OAMFlip ^= 1; + if(!(PPU.OAMFlip & 1)){ + ++PPU.OAMAddr; + PPU.OAMAddr &= 0x1ff; + if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; + } + } else { + if (PPU.OAMPriorityRotation && (PPU.OAMAddr&1)) IPPU.OBJChanged = TRUE; + } + } else if(!(PPU.OAMFlip & 1)){ + PPU.OAMWriteRegister &= 0xff00; + PPU.OAMWriteRegister |= byte; + PPU.OAMFlip |= 1; + if (PPU.OAMPriorityRotation && (PPU.OAMAddr&1)) IPPU.OBJChanged = TRUE; + } else { + PPU.OAMWriteRegister &= 0x00ff; + uint8 lowbyte = (uint8)(PPU.OAMWriteRegister); + uint8 highbyte = byte; + PPU.OAMWriteRegister |= byte << 8; + + int addr = (PPU.OAMAddr << 1); + + if (lowbyte != PPU.OAMData [addr] || + highbyte != PPU.OAMData [addr+1]) + { + FLUSH_REDRAW (); + PPU.OAMData [addr] = lowbyte; + PPU.OAMData [addr+1] = highbyte; + IPPU.OBJChanged = TRUE; + if (addr & 2) + { + // Tile + PPU.OBJ[addr = PPU.OAMAddr >> 1].Name = PPU.OAMWriteRegister & 0x1ff; + + // priority, h and v flip. + PPU.OBJ[addr].Palette = (highbyte >> 1) & 7; + PPU.OBJ[addr].Priority = (highbyte >> 4) & 3; + PPU.OBJ[addr].HFlip = (highbyte >> 6) & 1; + PPU.OBJ[addr].VFlip = (highbyte >> 7) & 1; + } + else + { + // X position (low) + PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xFF00; + PPU.OBJ[addr].HPos |= lowbyte; + + // Sprite Y position + PPU.OBJ[addr].VPos = highbyte; + } + } + PPU.OAMFlip &= ~1; + ++PPU.OAMAddr; + if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1)) + { + PPU.FirstSprite = (PPU.OAMAddr&0xFE) >> 1; + IPPU.OBJChanged = TRUE; + } + } + + Memory.FillRAM [0x2104] = byte; +} + +STATIC inline void REGISTER_2118 (uint8 Byte) +{ + uint32 address; + if (PPU.VMA.FullGraphicCount) + { + uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; + address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff; + Memory.VRAM [address] = Byte; + } + else + { + Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte; + } + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (!PPU.VMA.High) + { +#ifdef DEBUGGER + if (Settings.TraceVRAM && !CPU.InDMA) + { + printf ("VRAM write byte: $%04X (%d,%d)\n", PPU.VMA.Address, + Memory.FillRAM[0x2115] & 3, + (Memory.FillRAM [0x2115] & 0x0c) >> 2); + } +#endif + PPU.VMA.Address += PPU.VMA.Increment; + } +// Memory.FillRAM [0x2118] = Byte; +} + +STATIC inline void REGISTER_2118_tile (uint8 Byte) +{ + uint32 address; + uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; + address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff; + Memory.VRAM [address] = Byte; + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (!PPU.VMA.High) + PPU.VMA.Address += PPU.VMA.Increment; +// Memory.FillRAM [0x2118] = Byte; +} + +STATIC inline void REGISTER_2118_linear (uint8 Byte) +{ + uint32 address; + Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xFFFF] = Byte; + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (!PPU.VMA.High) + PPU.VMA.Address += PPU.VMA.Increment; +// Memory.FillRAM [0x2118] = Byte; +} + +STATIC inline void REGISTER_2119 (uint8 Byte) +{ + uint32 address; + if (PPU.VMA.FullGraphicCount) + { + uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; + address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF; + Memory.VRAM [address] = Byte; + } + else + { + Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte; + } + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (PPU.VMA.High) + { +#ifdef DEBUGGER + if (Settings.TraceVRAM && !CPU.InDMA) + { + printf ("VRAM write word: $%04X (%d,%d)\n", PPU.VMA.Address, + Memory.FillRAM[0x2115] & 3, + (Memory.FillRAM [0x2115] & 0x0c) >> 2); + } +#endif + PPU.VMA.Address += PPU.VMA.Increment; + } +// Memory.FillRAM [0x2119] = Byte; +} + +STATIC inline void REGISTER_2119_tile (uint8 Byte) +{ + uint32 rem = PPU.VMA.Address & PPU.VMA.Mask1; + uint32 address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) + + (rem >> PPU.VMA.Shift) + + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xFFFF; + Memory.VRAM [address] = Byte; + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (PPU.VMA.High) + PPU.VMA.Address += PPU.VMA.Increment; +// Memory.FillRAM [0x2119] = Byte; +} + +STATIC inline void REGISTER_2119_linear (uint8 Byte) +{ + uint32 address; + Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xFFFF] = Byte; + IPPU.TileCached [TILE_2BIT][address >> 4] = FALSE; + IPPU.TileCached [TILE_4BIT][address >> 5] = FALSE; + IPPU.TileCached [TILE_8BIT][address >> 6] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_EVEN][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][address >> 4] = FALSE; + IPPU.TileCached [TILE_2BIT_ODD][((address >> 4)-1)&(MAX_2BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_EVEN][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][address >> 5] = FALSE; + IPPU.TileCached [TILE_4BIT_ODD][((address >> 5)-1)&(MAX_4BIT_TILES-1)] = FALSE; + if (PPU.VMA.High) + PPU.VMA.Address += PPU.VMA.Increment; +// Memory.FillRAM [0x2119] = Byte; +} + +STATIC inline void REGISTER_2122(uint8 Byte) +{ + // CG-RAM (palette) write + + if (PPU.CGFLIP) + { + if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8)) + { + FLUSH_REDRAW (); + PPU.CGDATA[PPU.CGADD] &= 0x00FF; + PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8; + IPPU.ColorsChanged = TRUE; + IPPU.Blue [PPU.CGADD] = IPPU.XB [(Byte >> 2) & 0x1f]; + IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f]; + IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD], + IPPU.Green [PPU.CGADD], + IPPU.Blue [PPU.CGADD]); + } + PPU.CGADD++; + } + else + { + if (Byte != (uint8) (PPU.CGDATA[PPU.CGADD] & 0xff)) + { + FLUSH_REDRAW (); + PPU.CGDATA[PPU.CGADD] &= 0x7F00; + PPU.CGDATA[PPU.CGADD] |= Byte; + IPPU.ColorsChanged = TRUE; + IPPU.Red [PPU.CGADD] = IPPU.XB [Byte & 0x1f]; + IPPU.Green [PPU.CGADD] = IPPU.XB [(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f]; + IPPU.ScreenColors [PPU.CGADD] = (uint16) BUILD_PIXEL (IPPU.Red [PPU.CGADD], + IPPU.Green [PPU.CGADD], + IPPU.Blue [PPU.CGADD]); + } + } + PPU.CGFLIP ^= 1; +// Memory.FillRAM [0x2122] = Byte; +} + +STATIC inline void REGISTER_2180(uint8 Byte) +{ + Memory.RAM[PPU.WRAM++] = Byte; + PPU.WRAM &= 0x1FFFF; + Memory.FillRAM [0x2180] = Byte; +} + + +#endif + diff --git a/source/snes9x/sa1.cpp b/source/snes9x/sa1.cpp new file mode 100644 index 0000000..7389f9e --- /dev/null +++ b/source/snes9x/sa1.cpp @@ -0,0 +1,1033 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "ppu.h" +#include "cpuexec.h" + +#include "sa1.h" + +uint8 SA1OpenBus; + +static void S9xSA1CharConv2 (); +static void S9xSA1DMA (); +static void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift); + +void S9xSA1Init () +{ + SA1.NMIActive = FALSE; + SA1.IRQActive = FALSE; + SA1.WaitingForInterrupt = FALSE; + SA1.Waiting = FALSE; + SA1.Flags = 0; + SA1.Executing = FALSE; + memset (&Memory.FillRAM [0x2200], 0, 0x200); + Memory.FillRAM [0x2200] = 0x20; + Memory.FillRAM [0x2220] = 0x00; + Memory.FillRAM [0x2221] = 0x01; + Memory.FillRAM [0x2222] = 0x02; + Memory.FillRAM [0x2223] = 0x03; + Memory.FillRAM [0x2228] = 0xff; + SA1.op1 = 0; + SA1.op2 = 0; + SA1.arithmetic_op = 0; + SA1.sum = 0; + SA1.overflow = FALSE; + SA1.S9xOpcodes=NULL; +} + +void S9xSA1Reset () +{ + SA1Registers.PBPC = 0; + SA1Registers.PB = 0; + SA1Registers.PCw = Memory.FillRAM [0x2203] | + (Memory.FillRAM [0x2204] << 8); + SA1Registers.D.W = 0; + SA1Registers.DB = 0; + SA1Registers.SH = 1; + SA1Registers.SL = 0xFF; + SA1Registers.XH = 0; + SA1Registers.YH = 0; + SA1Registers.P.W = 0; + + SA1.ShiftedPB = 0; + SA1.ShiftedDB = 0; + SA1SetFlags (MemoryFlag | IndexFlag | IRQ | Emulation); + SA1ClearFlags (Decimal); + + SA1.WaitingForInterrupt = FALSE; + SA1.PCBase = NULL; + S9xSA1SetPCBase (SA1Registers.PBPC); + SA1.S9xOpcodes = S9xSA1OpcodesM1X1; + SA1.S9xOpLengths = S9xOpLengthsM1X1; + + S9xSA1UnpackStatus(); + S9xSA1FixCycles (); + SA1.Executing = TRUE; + SA1.BWRAM = Memory.SRAM; + Memory.FillRAM [0x2225] = 0; +} + +void S9xSA1SetBWRAMMemMap (uint8 val) +{ + int c; + + if (val & 0x80) + { + for (c = 0; c < 0x400; c += 16) + { + SA1.Map [c + 6] = SA1.Map [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; + SA1.Map [c + 7] = SA1.Map [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; + SA1.WriteMap [c + 6] = SA1.WriteMap [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; + SA1.WriteMap [c + 7] = SA1.WriteMap [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM_BITMAP2; + } + SA1.BWRAM = Memory.SRAM + (val & 0x7f) * 0x2000 / 4; + } + else + { + for (c = 0; c < 0x400; c += 16) + { + SA1.Map [c + 6] = SA1.Map [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM; + SA1.Map [c + 7] = SA1.Map [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM; + SA1.WriteMap [c + 6] = SA1.WriteMap [c + 0x806] = (uint8 *) CMemory::MAP_BWRAM; + SA1.WriteMap [c + 7] = SA1.WriteMap [c + 0x807] = (uint8 *) CMemory::MAP_BWRAM; + } + SA1.BWRAM = Memory.SRAM + (val & 7) * 0x2000; + } +} + +void S9xFixSA1AfterSnapshotLoad () +{ + SA1.ShiftedPB = (uint32) SA1Registers.PB << 16; + SA1.ShiftedDB = (uint32) SA1Registers.DB << 16; + + S9xSA1SetPCBase (SA1Registers.PBPC); + S9xSA1UnpackStatus (); + S9xSA1FixCycles (); + SA1.VirtualBitmapFormat = (Memory.FillRAM [0x223f] & 0x80) ? 2 : 4; + Memory.BWRAM = Memory.SRAM + (Memory.FillRAM [0x2224] & 7) * 0x2000; + S9xSA1SetBWRAMMemMap (Memory.FillRAM [0x2225]); + + SA1.Waiting = (Memory.FillRAM [0x2200] & 0x60) != 0; + SA1.Executing = !SA1.Waiting; +} + +uint8 S9xSA1GetByte (uint32 address) +{ + uint8 *GetAddress = SA1.Map [(address&0xffffff) >> MEMMAP_SHIFT]; + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + return (*(GetAddress + (address & 0xffff))); + + switch ((pint) GetAddress) + { + case CMemory::MAP_PPU: + return (S9xGetSA1 (address & 0xffff)); + case CMemory::MAP_LOROM_SRAM: + case CMemory::MAP_SA1RAM: + return (*(Memory.SRAM + (address & 0xffff))); + case CMemory::MAP_BWRAM: + return (*(SA1.BWRAM + ((address & 0x7fff) - 0x6000))); + case CMemory::MAP_BWRAM_BITMAP: + address -= 0x600000; + if (SA1.VirtualBitmapFormat == 2) + return ((Memory.SRAM [(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3); + else + return ((Memory.SRAM [(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15); + case CMemory::MAP_BWRAM_BITMAP2: + address = (address & 0xffff) - 0x6000; + if (SA1.VirtualBitmapFormat == 2) + return ((SA1.BWRAM [(address >> 2) & 0xffff] >> ((address & 3) << 1)) & 3); + else + return ((SA1.BWRAM [(address >> 1) & 0xffff] >> ((address & 1) << 2)) & 15); + + case CMemory::MAP_DEBUG: + default: +#ifdef DEBUGGER +// printf ("R(B) %06x\n", address); +#endif + return SA1OpenBus; + } +} + +uint16 S9xSA1GetWord (uint32 address, s9xwrap_t w) +{ + SA1OpenBus = S9xSA1GetByte (address); + switch(w){ + case WRAP_PAGE: + { + PC_t a; + a.xPBPC = address; + a.B.xPCl++; + return (SA1OpenBus | (S9xSA1GetByte (a.xPBPC) << 8)); + } + case WRAP_BANK: + { + PC_t a; + a.xPBPC = address; + a.W.xPC++; + return (SA1OpenBus | (S9xSA1GetByte (a.xPBPC) << 8)); + } + case WRAP_NONE: + default: + return (SA1OpenBus | (S9xSA1GetByte (address + 1) << 8)); + } +} + +void S9xSA1SetByte (uint8 byte, uint32 address) +{ + uint8 *Setaddress = SA1.WriteMap [(address&0xffffff) >> MEMMAP_SHIFT]; + + if (Setaddress >= (uint8 *) CMemory::MAP_LAST) + { + *(Setaddress + (address & 0xffff)) = byte; + return; + } + + switch ((pint) Setaddress) + { + case CMemory::MAP_PPU: + S9xSetSA1 (byte, address & 0xffff); + return; + case CMemory::MAP_SA1RAM: + case CMemory::MAP_LOROM_SRAM: + *(Memory.SRAM + (address & 0xffff)) = byte; + return; + case CMemory::MAP_BWRAM: + *(SA1.BWRAM + ((address & 0x7fff) - 0x6000)) = byte; + return; + case CMemory::MAP_BWRAM_BITMAP: + address -= 0x600000; + if (SA1.VirtualBitmapFormat == 2) + { + uint8 *ptr = &Memory.SRAM [(address >> 2) & 0xffff]; + *ptr &= ~(3 << ((address & 3) << 1)); + *ptr |= (byte & 3) << ((address & 3) << 1); + } + else + { + uint8 *ptr = &Memory.SRAM [(address >> 1) & 0xffff]; + *ptr &= ~(15 << ((address & 1) << 2)); + *ptr |= (byte & 15) << ((address & 1) << 2); + } + break; + case CMemory::MAP_BWRAM_BITMAP2: + address = (address & 0xffff) - 0x6000; + if (SA1.VirtualBitmapFormat == 2) + { + uint8 *ptr = &SA1.BWRAM [(address >> 2) & 0xffff]; + *ptr &= ~(3 << ((address & 3) << 1)); + *ptr |= (byte & 3) << ((address & 3) << 1); + } + else + { + uint8 *ptr = &SA1.BWRAM [(address >> 1) & 0xffff]; + *ptr &= ~(15 << ((address & 1) << 2)); + *ptr |= (byte & 15) << ((address & 1) << 2); + } + default: + return; + } +} + +void S9xSA1SetWord (uint16 Word, uint32 address, enum s9xwrap_t w, enum s9xwriteorder_t o) +{ + if(!o) S9xSA1SetByte ((uint8) Word, address); + switch(w){ + case WRAP_PAGE: + { + PC_t a; + a.xPBPC = address; + a.B.xPCl++; + S9xSA1SetByte (Word>>8, a.xPBPC); + } + case WRAP_BANK: + { + PC_t a; + a.xPBPC = address; + a.W.xPC++; + S9xSA1SetByte (Word>>8, a.xPBPC); + } + case WRAP_NONE: + default: + S9xSA1SetByte (Word>>8, address+1); + } + if(o) S9xSA1SetByte ((uint8) Word, address); +} + +void S9xSA1SetPCBase (uint32 address) +{ + SA1Registers.PBPC = address&0xffffff; + SA1.ShiftedPB = address&0xff0000; + + uint8 *GetAddress = SA1.Map [(address&0xffffff) >> MEMMAP_SHIFT]; + if (GetAddress >= (uint8 *) CMemory::MAP_LAST) + { + SA1.PCBase = GetAddress; + return; + } + + switch ((pint) GetAddress) + { + case CMemory::MAP_SA1RAM: + SA1.PCBase = Memory.SRAM; + return; + + case CMemory::MAP_LOROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK){ + SA1.PCBase = NULL; + } else { + SA1.PCBase = (Memory.SRAM + ((((address&0xFF0000)>>1)|(address&0x7FFF)) & Memory.SRAMMask)) - (address&0xffff); + } + return; + + case CMemory::MAP_BWRAM: + SA1.PCBase = SA1.BWRAM - 0x6000 - (address&0x8000); + return; + + case CMemory::MAP_HIROM_SRAM: + if((Memory.SRAMMask&MEMMAP_MASK)!=MEMMAP_MASK){ + SA1.PCBase = NULL; + } else { + SA1.PCBase = (Memory.SRAM + (((address&0x7fff) - 0x6000 + ((address & 0xf0000) >> 3)) & Memory.SRAMMask)) - (address&0xffff); + } + return; + + case CMemory::MAP_DEBUG: +#ifdef DEBUGGER + printf ("SBP %06x\n", address); +#endif + + default: + case CMemory::MAP_NONE: + SA1.PCBase = NULL; + return; + } +} + +void S9xSA1ExecuteDuringSleep () +{ +#if 0 + if (SA1.Executing) + { + while (CPU.Cycles < CPU.NextEvent) + { + S9xSA1MainLoop (); + CPU.Cycles += TWO_CYCLES * 2; + } + } +#endif +} + +void S9xSetSA1MemMap (uint32 which1, uint8 map) +{ + int c; + int start = which1 * 0x100 + 0xc00; + int start2 = which1 * 0x200; + + if (which1 >= 2) + start2 += 0x400; + + for (c = 0; c < 0x100; c += 16) + { + uint8 *block = &Memory.ROM [(map & 7) * 0x100000 + (c << 12)]; + int i; + + for (i = c; i < c + 16; i++) + Memory.Map [start + i] = SA1.Map [start + i] = block; + } + + for (c = 0; c < 0x200; c += 16) + { + uint8 *block = &Memory.ROM [(map & 7) * 0x100000 + (c << 11) - 0x8000]; + int i; + + for (i = c + 8; i < c + 16; i++) + Memory.Map [start2 + i] = SA1.Map [start2 + i] = block; + } +} + +uint8 S9xGetSA1 (uint32 address) +{ +// printf ("R: %04x\n", address); + switch (address) + { + case 0x2300: + return ((uint8) ((Memory.FillRAM [0x2209] & 0x5f) | + (CPU.IRQActive & (SA1_IRQ_SOURCE | SA1_DMA_IRQ_SOURCE)))); + case 0x2301: + return ((Memory.FillRAM [0x2200] & 0xf) | + (Memory.FillRAM [0x2301] & 0xf0)); + case 0x2306: + return ((uint8) SA1.sum); + case 0x2307: + return ((uint8) (SA1.sum >> 8)); + case 0x2308: + return ((uint8) (SA1.sum >> 16)); + case 0x2309: + return ((uint8) (SA1.sum >> 24)); + case 0x230a: + return ((uint8) (SA1.sum >> 32)); + case 0x230c: + return (Memory.FillRAM [0x230c]); + case 0x230d: + { + uint8 byte = Memory.FillRAM [0x230d]; + + if (Memory.FillRAM [0x2258] & 0x80) + { + S9xSA1ReadVariableLengthData (TRUE, FALSE); + } + return (byte); + } + default: + printf ("R: %04x\n", address); + break; + } + return (Memory.FillRAM [address]); +} + +void S9xSetSA1 (uint8 byte, uint32 address) +{ +//printf ("W: %02x -> %04x\n", byte, address); + switch (address) + { + case 0x2200: + SA1.Waiting = (byte & 0x60) != 0; +// SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes; + + if (!(byte & 0x20) && (Memory.FillRAM [0x2200] & 0x20)) + { + S9xSA1Reset (); + } + if (byte & 0x80) + { + Memory.FillRAM [0x2301] |= 0x80; + if (Memory.FillRAM [0x220a] & 0x80) + { + SA1.Flags |= IRQ_PENDING_FLAG; + SA1.IRQActive |= SNES_IRQ_SOURCE; + SA1.Executing = !SA1.Waiting && SA1.S9xOpcodes; + } + } + if (byte & 0x10) + { + Memory.FillRAM [0x2301] |= 0x10; +#ifdef DEBUGGER + printf ("###SA1 NMI\n"); +#endif + if (Memory.FillRAM [0x220a] & 0x10) + { + } + } + break; + + case 0x2201: + if (((byte ^ Memory.FillRAM [0x2201]) & 0x80) && + (Memory.FillRAM [0x2300] & byte & 0x80)) + { + S9xSetIRQ (SA1_IRQ_SOURCE); + } + if (((byte ^ Memory.FillRAM [0x2201]) & 0x20) && + (Memory.FillRAM [0x2300] & byte & 0x20)) + { + S9xSetIRQ (SA1_DMA_IRQ_SOURCE); + } + break; + case 0x2202: + if (byte & 0x80) + { + Memory.FillRAM [0x2300] &= ~0x80; + S9xClearIRQ (SA1_IRQ_SOURCE); + } + if (byte & 0x20) + { + Memory.FillRAM [0x2300] &= ~0x20; + S9xClearIRQ (SA1_DMA_IRQ_SOURCE); + } + break; + case 0x2203: +// printf ("SA1 reset vector: %04x\n", byte | (Memory.FillRAM [0x2204] << 8)); + break; + case 0x2204: +// printf ("SA1 reset vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2203]); + break; + + case 0x2205: +// printf ("SA1 NMI vector: %04x\n", byte | (Memory.FillRAM [0x2206] << 8)); + break; + case 0x2206: +// printf ("SA1 NMI vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2205]); + break; + + case 0x2207: +// printf ("SA1 IRQ vector: %04x\n", byte | (Memory.FillRAM [0x2208] << 8)); + break; + case 0x2208: +// printf ("SA1 IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM [0x2207]); + break; + + case 0x2209: + Memory.FillRAM [0x2209] = byte; + if (byte & 0x80) + Memory.FillRAM [0x2300] |= 0x80; + + if (byte & Memory.FillRAM [0x2201] & 0x80) + { + S9xSetIRQ (SA1_IRQ_SOURCE); + } + break; + case 0x220a: + if (((byte ^ Memory.FillRAM [0x220a]) & 0x80) && + (Memory.FillRAM [0x2301] & byte & 0x80)) + { + SA1.Flags |= IRQ_PENDING_FLAG; + SA1.IRQActive |= SNES_IRQ_SOURCE; +// SA1.Executing = !SA1.Waiting; + } + if (((byte ^ Memory.FillRAM [0x220a]) & 0x40) && + (Memory.FillRAM [0x2301] & byte & 0x40)) + { + SA1.Flags |= IRQ_PENDING_FLAG; + SA1.IRQActive |= TIMER_IRQ_SOURCE; +// SA1.Executing = !SA1.Waiting; + } + if (((byte ^ Memory.FillRAM [0x220a]) & 0x20) && + (Memory.FillRAM [0x2301] & byte & 0x20)) + { + SA1.Flags |= IRQ_PENDING_FLAG; + SA1.IRQActive |= DMA_IRQ_SOURCE; +// SA1.Executing = !SA1.Waiting; + } + if (((byte ^ Memory.FillRAM [0x220a]) & 0x10) && + (Memory.FillRAM [0x2301] & byte & 0x10)) + { +#ifdef DEBUGGER + printf ("###SA1 NMI\n"); +#endif + } + break; + case 0x220b: + if (byte & 0x80) + { + SA1.IRQActive &= ~SNES_IRQ_SOURCE; + Memory.FillRAM [0x2301] &= ~0x80; + } + if (byte & 0x40) + { + SA1.IRQActive &= ~TIMER_IRQ_SOURCE; + Memory.FillRAM [0x2301] &= ~0x40; + } + if (byte & 0x20) + { + SA1.IRQActive &= ~DMA_IRQ_SOURCE; + Memory.FillRAM [0x2301] &= ~0x20; + } + if (byte & 0x10) + { + // Clear NMI + Memory.FillRAM [0x2301] &= ~0x10; + } + if (!SA1.IRQActive) + SA1.Flags &= ~IRQ_PENDING_FLAG; + break; + case 0x220c: +// printf ("SNES NMI vector: %04x\n", byte | (Memory.FillRAM [0x220d] << 8)); + break; + case 0x220d: +// printf ("SNES NMI vector: %04x\n", (byte << 8) | Memory.FillRAM [0x220c]); + break; + + case 0x220e: +// printf ("SNES IRQ vector: %04x\n", byte | (Memory.FillRAM [0x220f] << 8)); + break; + case 0x220f: +// printf ("SNES IRQ vector: %04x\n", (byte << 8) | Memory.FillRAM [0x220e]); + break; + + case 0x2210: +#if 0 + printf ("Timer %s\n", (byte & 0x80) ? "linear" : "HV"); + printf ("Timer H-IRQ %s\n", (byte & 1) ? "enabled" : "disabled"); + printf ("Timer V-IRQ %s\n", (byte & 2) ? "enabled" : "disabled"); +#endif + break; + case 0x2211: + printf ("Timer reset\n"); + break; + case 0x2212: + printf ("H-Timer %04x\n", byte | (Memory.FillRAM [0x2213] << 8)); + break; + case 0x2213: + printf ("H-Timer %04x\n", (byte << 8) | Memory.FillRAM [0x2212]); + break; + case 0x2214: + printf ("V-Timer %04x\n", byte | (Memory.FillRAM [0x2215] << 8)); + break; + case 0x2215: + printf ("V-Timer %04x\n", (byte << 8) | Memory.FillRAM [0x2214]); + break; + case 0x2220: + case 0x2221: + case 0x2222: + case 0x2223: + S9xSetSA1MemMap (address - 0x2220, byte); +// printf ("MMC: %02x\n", byte); + break; + case 0x2224: +// printf ("BWRAM image SNES %02x -> 0x6000\n", byte); + Memory.BWRAM = Memory.SRAM + (byte & 7) * 0x2000; + break; + case 0x2225: +// printf ("BWRAM image SA1 %02x -> 0x6000 (%02x)\n", byte, Memory.FillRAM [address]); + if (byte != Memory.FillRAM [address]) + S9xSA1SetBWRAMMemMap (byte); + break; + case 0x2226: +// printf ("BW-RAM SNES write %s\n", (byte & 0x80) ? "enabled" : "disabled"); + break; + case 0x2227: +// printf ("BW-RAM SA1 write %s\n", (byte & 0x80) ? "enabled" : "disabled"); + break; + + case 0x2228: +// printf ("BW-RAM write protect area %02x\n", byte); + break; + case 0x2229: +// printf ("I-RAM SNES write protect area %02x\n", byte); + break; + case 0x222a: +// printf ("I-RAM SA1 write protect area %02x\n", byte); + break; + case 0x2230: +#if 0 + printf ("SA1 DMA %s\n", (byte & 0x80) ? "enabled" : "disabled"); + printf ("DMA priority %s\n", (byte & 0x40) ? "DMA" : "SA1"); + printf ("DMA %s\n", (byte & 0x20) ? "char conv" : "normal"); + printf ("DMA type %s\n", (byte & 0x10) ? "BW-RAM -> I-RAM" : "SA1 -> I-RAM"); + printf ("DMA distination %s\n", (byte & 4) ? "BW-RAM" : "I-RAM"); + printf ("DMA source %s\n", DMAsource [byte & 3]); +#endif + break; + case 0x2231: + if (byte & 0x80) + SA1.in_char_dma = FALSE; +#if 0 + printf ("CHDEND %s\n", (byte & 0x80) ? "complete" : "incomplete"); + printf ("DMA colour mode %d\n", byte & 3); + printf ("virtual VRAM width %d\n", (byte >> 2) & 7); +#endif + break; + case 0x2232: + case 0x2233: + case 0x2234: + Memory.FillRAM [address] = byte; +#if 0 + printf ("DMA source start %06x\n", + Memory.FillRAM [0x2232] | (Memory.FillRAM [0x2233] << 8) | + (Memory.FillRAM [0x2234] << 16)); +#endif + break; + case 0x2235: + Memory.FillRAM [address] = byte; + break; + case 0x2236: + Memory.FillRAM [address] = byte; + if ((Memory.FillRAM [0x2230] & 0xa4) == 0x80) + { + // Normal DMA to I-RAM + S9xSA1DMA (); + } + else + if ((Memory.FillRAM [0x2230] & 0xb0) == 0xb0) + { + Memory.FillRAM [0x2300] |= 0x20; + if (Memory.FillRAM [0x2201] & 0x20) + S9xSetIRQ (SA1_DMA_IRQ_SOURCE); + SA1.in_char_dma = TRUE; + } + break; + case 0x2237: + Memory.FillRAM [address] = byte; + if ((Memory.FillRAM [0x2230] & 0xa4) == 0x84) + { + // Normal DMA to BW-RAM + S9xSA1DMA (); + } +#if 0 + printf ("DMA dest address %06x\n", + Memory.FillRAM [0x2235] | (Memory.FillRAM [0x2236] << 8) | + (Memory.FillRAM [0x2237] << 16)); +#endif + break; + case 0x2238: + case 0x2239: + Memory.FillRAM [address] = byte; +#if 0 + printf ("DMA length %04x\n", + Memory.FillRAM [0x2238] | (Memory.FillRAM [0x2239] << 8)); +#endif + break; + case 0x223f: + SA1.VirtualBitmapFormat = (byte & 0x80) ? 2 : 4; + //printf ("virtual VRAM depth %d\n", (byte & 0x80) ? 2 : 4); + break; + + case 0x2240: case 0x2241: case 0x2242: case 0x2243: + case 0x2244: case 0x2245: case 0x2246: case 0x2247: + case 0x2248: case 0x2249: case 0x224a: case 0x224b: + case 0x224c: case 0x224d: case 0x224e: +#if 0 + if (!(SA1.Flags & TRACE_FLAG)) + { + TraceSA1 (); + Trace (); + } +#endif + Memory.FillRAM [address] = byte; + break; + + case 0x224f: + Memory.FillRAM [address] = byte; + if ((Memory.FillRAM [0x2230] & 0xb0) == 0xa0) + { + // Char conversion 2 DMA enabled + memmove (&Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000] + SA1.in_char_dma * 16, + &Memory.FillRAM [0x2240], 16); + SA1.in_char_dma = (SA1.in_char_dma + 1) & 7; + if ((SA1.in_char_dma & 3) == 0) + { + S9xSA1CharConv2 (); + } + } + break; + case 0x2250: + if (byte & 2) + SA1.sum = 0; + SA1.arithmetic_op = byte & 3; + break; + + case 0x2251: + SA1.op1 = (SA1.op1 & 0xff00) | byte; + break; + case 0x2252: + SA1.op1 = (SA1.op1 & 0xff) | (byte << 8); + break; + case 0x2253: + SA1.op2 = (SA1.op2 & 0xff00) | byte; + break; + case 0x2254: + SA1.op2 = (SA1.op2 & 0xff) | (byte << 8); + switch (SA1.arithmetic_op) + { + case 0: // multiply + SA1.sum = SA1.op1 * SA1.op2; + break; + case 1: // divide + if (SA1.op2 == 0) + SA1.sum = SA1.op1 << 16; + else + { + SA1.sum = (SA1.op1 / (int) ((uint16) SA1.op2)) | + ((SA1.op1 % (int) ((uint16) SA1.op2)) << 16); + } + break; + case 2: + default: // cumulative sum + SA1.sum += SA1.op1 * SA1.op2; + if (SA1.sum & ((int64) 0xffffff << 32)) + SA1.overflow = TRUE; + break; + } + break; + case 0x2258: // Variable bit-field length/auto inc/start. + Memory.FillRAM [0x2258] = byte; + S9xSA1ReadVariableLengthData (TRUE, FALSE); + return; + case 0x2259: + case 0x225a: + case 0x225b: // Variable bit-field start address + Memory.FillRAM [address] = byte; + // XXX: ??? + SA1.variable_bit_pos = 0; + S9xSA1ReadVariableLengthData (FALSE, TRUE); + return; + default: +// printf ("W: %02x->%04x\n", byte, address); + break; + } + if (address >= 0x2200 && address <= 0x22ff) + Memory.FillRAM [address] = byte; +} + +static void S9xSA1CharConv2 () +{ + uint32 dest = Memory.FillRAM [0x2235] | (Memory.FillRAM [0x2236] << 8); + uint32 offset = (SA1.in_char_dma & 7) ? 0 : 1; + int depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 : + (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2; + int bytes_per_char = 8 * depth; + uint8 *p = &Memory.FillRAM [0x3000] + dest + offset * bytes_per_char; + uint8 *q = &Memory.ROM [CMemory::MAX_ROM_SIZE - 0x10000] + offset * 64; + + switch (depth) + { + case 2: + break; + case 4: + break; + case 8: + for (int l = 0; l < 8; l++, q += 8) + { + for (int b = 0; b < 8; b++) + { + uint8 r = *(q + b); + *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1); + *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1); + *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1); + *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1); + *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1); + *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1); + *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1); + *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1); + } + p += 2; + } + break; + } +} + +static void S9xSA1DMA () +{ + uint32 src = Memory.FillRAM [0x2232] | + (Memory.FillRAM [0x2233] << 8) | + (Memory.FillRAM [0x2234] << 16); + uint32 dst = Memory.FillRAM [0x2235] | + (Memory.FillRAM [0x2236] << 8) | + (Memory.FillRAM [0x2237] << 16); + uint32 len = Memory.FillRAM [0x2238] | + (Memory.FillRAM [0x2239] << 8); + + uint8 *s; + uint8 *d; + + switch (Memory.FillRAM [0x2230] & 3) + { + case 0: // ROM + s = SA1.Map [((src&0xffffff) >> MEMMAP_SHIFT)]; + if (s >= (uint8 *) CMemory::MAP_LAST) + s += (src & 0xffff); + else + s = Memory.ROM + (src & 0xffff); + break; + case 1: // BW-RAM + src &= Memory.SRAMMask; + len &= Memory.SRAMMask; + s = Memory.SRAM + src; + break; + default: + case 2: + src &= 0x3ff; + len &= 0x3ff; + s = &Memory.FillRAM [0x3000] + src; + break; + } + + if (Memory.FillRAM [0x2230] & 4) + { + dst &= Memory.SRAMMask; + len &= Memory.SRAMMask; + d = Memory.SRAM + dst; + } + else + { + dst &= 0x3ff; + len &= 0x3ff; + d = &Memory.FillRAM [0x3000] + dst; + } + memmove (d, s, len); + Memory.FillRAM [0x2301] |= 0x20; + + if (Memory.FillRAM [0x220a] & 0x20) + { + SA1.Flags |= IRQ_PENDING_FLAG; + SA1.IRQActive |= DMA_IRQ_SOURCE; +// SA1.Executing = !SA1.Waiting; + } +} + +void S9xSA1ReadVariableLengthData (bool8 inc, bool8 no_shift) +{ + uint32 addr = Memory.FillRAM [0x2259] | + (Memory.FillRAM [0x225a] << 8) | + (Memory.FillRAM [0x225b] << 16); + uint8 shift = Memory.FillRAM [0x2258] & 15; + + if (no_shift) + shift = 0; + else + if (shift == 0) + shift = 16; + + uint8 s = shift + SA1.variable_bit_pos; + + if (s >= 16) + { + addr += (s >> 4) << 1; + s &= 15; + } + uint32 data = S9xSA1GetWord (addr) | + (S9xSA1GetWord (addr + 2) << 16); + + data >>= s; + Memory.FillRAM [0x230c] = (uint8) data; + Memory.FillRAM [0x230d] = (uint8) (data >> 8); + if (inc) + { + SA1.variable_bit_pos = (SA1.variable_bit_pos + shift) & 15; + Memory.FillRAM [0x2259] = (uint8) addr; + Memory.FillRAM [0x225a] = (uint8) (addr >> 8); + Memory.FillRAM [0x225b] = (uint8) (addr >> 16); + } +} + diff --git a/source/snes9x/sa1.h b/source/snes9x/sa1.h new file mode 100644 index 0000000..ae19900 --- /dev/null +++ b/source/snes9x/sa1.h @@ -0,0 +1,289 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _sa1_h_ +#define _sa1_h_ + +#include "memmap.h" + +struct SSA1Registers { + uint8 DB; + pair P; + pair A; + pair D; + pair S; + pair X; + pair Y; + PC_t PC; +}; + +struct SSA1 { + struct SOpcodes *S9xOpcodes; + uint8 *S9xOpLengths; + uint8 _Carry; + uint8 _Zero; + uint8 _Negative; + uint8 _Overflow; + bool8 CPUExecuting; + uint32 ShiftedPB; + uint32 ShiftedDB; + uint32 Flags; + bool8 Executing; + bool8 NMIActive; + bool8 IRQActive; + bool8 WaitingForInterrupt; + bool8 Waiting; +// uint8 WhichEvent; + uint8 *PCBase; + uint8 *BWRAM; + uint32 PBPCAtOpcodeStart; + uint32 WaitAddress; + uint32 WaitCounter; + uint8 *WaitByteAddress1; + uint8 *WaitByteAddress2; +// int32 Cycles; +// int32 NextEvent; +// int32 V_Counter; + uint8 *Map [MEMMAP_NUM_BLOCKS]; + uint8 *WriteMap [MEMMAP_NUM_BLOCKS]; + int16 op1; + int16 op2; + int32 arithmetic_op; + int64 sum; + bool8 overflow; + uint8 VirtualBitmapFormat; + bool8 in_char_dma; + uint8 variable_bit_pos; +}; + +#define SA1CheckZero() (SA1._Zero == 0) +#define SA1CheckCarry() (SA1._Carry) +#define SA1CheckIRQ() (SA1Registers.PL & IRQ) +#define SA1CheckDecimal() (SA1Registers.PL & Decimal) +#define SA1CheckIndex() (SA1Registers.PL & IndexFlag) +#define SA1CheckMemory() (SA1Registers.PL & MemoryFlag) +#define SA1CheckOverflow() (SA1._Overflow) +#define SA1CheckNegative() (SA1._Negative & 0x80) +#define SA1CheckEmulation() (SA1Registers.P.W & Emulation) + +#define SA1ClearFlags(f) (SA1Registers.P.W &= ~(f)) +#define SA1SetFlags(f) (SA1Registers.P.W |= (f)) +#define SA1CheckFlag(f) (SA1Registers.PL & (f)) + + +START_EXTERN_C +uint8 S9xSA1GetByte (uint32); +uint16 S9xSA1GetWord (uint32, enum s9xwrap_t w=WRAP_NONE); +void S9xSA1SetByte (uint8, uint32); +void S9xSA1SetWord (uint16, uint32, enum s9xwrap_t w=WRAP_NONE, enum s9xwriteorder_t o=WRITE_01); +void S9xSA1SetPCBase (uint32); +uint8 S9xGetSA1 (uint32); +void S9xSetSA1 (uint8, uint32); + +extern struct SOpcodes S9xSA1OpcodesM1X1 [256]; +extern struct SOpcodes S9xSA1OpcodesM1X0 [256]; +extern struct SOpcodes S9xSA1OpcodesM0X1 [256]; +extern struct SOpcodes S9xSA1OpcodesM0X0 [256]; +extern uint8 S9xOpLengthsM1X1 [256]; +extern uint8 S9xOpLengthsM1X0 [256]; +extern uint8 S9xOpLengthsM0X1 [256]; +extern uint8 S9xOpLengthsM0X0 [256]; +extern struct SSA1Registers SA1Registers; +extern struct SSA1 SA1; +extern uint8 SA1OpenBus; + +void S9xSA1MainLoop (); +void S9xSA1Init (); +void S9xFixSA1AfterSnapshotLoad (); +void S9xSA1ExecuteDuringSleep (); +END_EXTERN_C + +#define SNES_IRQ_SOURCE (1 << 7) +#define TIMER_IRQ_SOURCE (1 << 6) +#define DMA_IRQ_SOURCE (1 << 5) + +STATIC inline void S9xSA1UnpackStatus() +{ + SA1._Zero = (SA1Registers.PL & Zero) == 0; + SA1._Negative = (SA1Registers.PL & Negative); + SA1._Carry = (SA1Registers.PL & Carry); + SA1._Overflow = (SA1Registers.PL & Overflow) >> 6; +} + +STATIC inline void S9xSA1PackStatus() +{ + SA1Registers.PL &= ~(Zero | Negative | Carry | Overflow); + SA1Registers.PL |= SA1._Carry | ((SA1._Zero == 0) << 1) | + (SA1._Negative & 0x80) | (SA1._Overflow << 6); +} + +STATIC inline void S9xSA1FixCycles () +{ + if (SA1CheckEmulation ()) { + SA1.S9xOpcodes = S9xSA1OpcodesM1X1; + SA1.S9xOpLengths = S9xOpLengthsM1X1; + } else + if (SA1CheckMemory ()) + { + if (SA1CheckIndex ()){ + SA1.S9xOpcodes = S9xSA1OpcodesM1X1; + SA1.S9xOpLengths = S9xOpLengthsM1X1; + } else { + SA1.S9xOpcodes = S9xSA1OpcodesM1X0; + SA1.S9xOpLengths = S9xOpLengthsM1X0; + } + } + else + { + if (SA1CheckIndex ()){ + SA1.S9xOpcodes = S9xSA1OpcodesM0X1; + SA1.S9xOpLengths = S9xOpLengthsM0X1; + } else { + SA1.S9xOpcodes = S9xSA1OpcodesM0X0; + SA1.S9xOpLengths = S9xOpLengthsM0X0; + } + } +} +#endif + diff --git a/source/snes9x/sa1cpu.cpp b/source/snes9x/sa1cpu.cpp new file mode 100644 index 0000000..5341411 --- /dev/null +++ b/source/snes9x/sa1cpu.cpp @@ -0,0 +1,259 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" +#include "cpuexec.h" + +#include "sa1.h" + +#define CPU SA1 +#define ICPU SA1 +#define Registers SA1Registers +#define OpenBus SA1OpenBus +#define S9xGetByte S9xSA1GetByte +#define S9xGetWord S9xSA1GetWord +#define S9xSetByte S9xSA1SetByte +#define S9xSetWord S9xSA1SetWord +#define S9xSetPCBase S9xSA1SetPCBase +#define S9xOpcodesM1X1 S9xSA1OpcodesM1X1 +#define S9xOpcodesM1X0 S9xSA1OpcodesM1X0 +#define S9xOpcodesM0X1 S9xSA1OpcodesM0X1 +#define S9xOpcodesM0X0 S9xSA1OpcodesM0X0 +#define S9xOpcodesE1 S9xSA1OpcodesE1 +#define S9xOpcodesSlow S9xSA1OpcodesSlow +#define S9xOpcode_IRQ S9xSA1Opcode_IRQ +#define S9xOpcode_NMI S9xSA1Opcode_NMI +#define S9xUnpackStatus S9xSA1UnpackStatus +#define S9xPackStatus S9xSA1PackStatus +#define S9xFixCycles S9xSA1FixCycles +#define Immediate8 SA1Immediate8 +#define Immediate16 SA1Immediate16 +#define Relative SA1Relative +#define RelativeLong SA1RelativeLong +#define AbsoluteIndexedIndirect SA1AbsoluteIndexedIndirect +#define AbsoluteIndirectLong SA1AbsoluteIndirectLong +#define AbsoluteIndirect SA1AbsoluteIndirect +#define Absolute SA1Absolute +#define AbsoluteLong SA1AbsoluteLong +#define Direct SA1Direct +#define DirectIndirectIndexed SA1DirectIndirectIndexed +#define DirectIndirectIndexedLong SA1DirectIndirectIndexedLong +#define DirectIndexedIndirect SA1DirectIndexedIndirect +#define DirectIndexedX SA1DirectIndexedX +#define DirectIndexedY SA1DirectIndexedY +#define AbsoluteIndexedX SA1AbsoluteIndexedX +#define AbsoluteIndexedY SA1AbsoluteIndexedY +#define AbsoluteLongIndexedX SA1AbsoluteLongIndexedX +#define DirectIndirect SA1DirectIndirect +#define DirectIndirectLong SA1DirectIndirectLong +#define StackRelative SA1StackRelative +#define StackRelativeIndirectIndexed SA1StackRelativeIndirectIndexed + +//#undef CPU_SHUTDOWN +#define SA1_OPCODES + +#include "cpuops.cpp" + +void S9xSA1MainLoop () +{ + int i; + +#if 0 + if (SA1.Flags & NMI_FLAG) + { + SA1.Flags &= ~NMI_FLAG; + if (SA1.WaitingForInterrupt) + { + SA1.WaitingForInterrupt = FALSE; + SA1Registers.PCw++; + } + S9xSA1Opcode_NMI (); + } +#endif + if (SA1.Flags & IRQ_PENDING_FLAG) + { + if (SA1.IRQActive) + { + if (SA1.WaitingForInterrupt) + { + SA1.WaitingForInterrupt = FALSE; + SA1Registers.PCw++; + } + if (!SA1CheckFlag (IRQ)) + S9xSA1Opcode_IRQ (); + } + else + SA1.Flags &= ~IRQ_PENDING_FLAG; + } + for (i = 0; i < 3 && SA1.Executing; i++) + { +#ifdef DEBUGGER + if (SA1.Flags & TRACE_FLAG){ S9xSA1Trace(); } +#endif +#ifdef CPU_SHUTDOWN + SA1.PBPCAtOpcodeStart = SA1Registers.PBPC; +#endif + + register uint8 Op; + register struct SOpcodes *Opcodes; + if(SA1.PCBase){ + SA1OpenBus = Op = SA1.PCBase[Registers.PCw]; + Opcodes = SA1.S9xOpcodes; + } else { + Op = S9xSA1GetByte(Registers.PBPC); + Opcodes = S9xOpcodesSlow; + } + if((SA1Registers.PCw&MEMMAP_MASK)+SA1.S9xOpLengths[Op]>=MEMMAP_BLOCK_SIZE){ + uint32 oldPC = SA1Registers.PBPC; + S9xSA1SetPCBase(SA1Registers.PBPC); + SA1Registers.PBPC = oldPC; + Opcodes = S9xSA1OpcodesSlow; + } + Registers.PCw++; + (*Opcodes[Op].S9xOpcode) (); + } +} + diff --git a/source/snes9x/sar.h b/source/snes9x/sar.h new file mode 100644 index 0000000..9562fda --- /dev/null +++ b/source/snes9x/sar.h @@ -0,0 +1,193 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _SAR_H_ +#define _SAR_H_ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include "port.h" + +#ifndef snes9x_types_defined +#include "9xtypes.h" +#endif + +#ifdef RIGHTSHIFT_IS_SAR +#define SAR(b, n) ((b)>>(n)) +#else + +static inline int8 SAR(const int8 b, const int n){ +#ifndef RIGHTSHIFT_int8_IS_SAR + if(b<0) return (b>>n)|(-1<<(8-n)); +#endif + return b>>n; +} + +static inline int16 SAR(const int16 b, const int n){ +#ifndef RIGHTSHIFT_int16_IS_SAR + if(b<0) return (b>>n)|(-1<<(16-n)); +#endif + return b>>n; +} + +static inline int32 SAR(const int32 b, const int n){ +#ifndef RIGHTSHIFT_int32_IS_SAR + if(b<0) return (b>>n)|(-1<<(32-n)); +#endif + return b>>n; +} + +static inline int64 SAR(const int64 b, const int n){ +#ifndef RIGHTSHIFT_int64_IS_SAR + if(b<0) return (b>>n)|(-1<<(64-n)); +#endif + return b>>n; +} + +#endif + +#endif + diff --git a/source/snes9x/screenshot.h b/source/snes9x/screenshot.h new file mode 100644 index 0000000..4afdfe9 --- /dev/null +++ b/source/snes9x/screenshot.h @@ -0,0 +1,151 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef SCREENSHOT_H +#define SCREENSHOT_H + +bool8 S9xDoScreenshot(int width, int height); + +#endif + diff --git a/source/snes9x/sdd1.cpp b/source/snes9x/sdd1.cpp new file mode 100644 index 0000000..fa5caf1 --- /dev/null +++ b/source/snes9x/sdd1.cpp @@ -0,0 +1,236 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#include "snes9x.h" +#include "memmap.h" +#include "ppu.h" +#include "sdd1.h" +#include "display.h" + +#ifdef __linux +#include +#endif + +void S9xSetSDD1MemoryMap (uint32 bank, uint32 value) +{ + bank = 0xc00 + bank * 0x100; + value = value * 1024 * 1024; + + int c; + + for (c = 0; c < 0x100; c += 16) + { + uint8 *block = &Memory.ROM [value + (c << 12)]; + int i; + + for (i = c; i < c + 16; i++) + Memory.Map [i + bank] = block; + } +} + +void S9xResetSDD1 () +{ + memset (&Memory.FillRAM [0x4800], 0, 4); + for (int i = 0; i < 4; i++) + { + Memory.FillRAM [0x4804 + i] = i; + S9xSetSDD1MemoryMap (i, i); + } +} + +void S9xSDD1PostLoadState () +{ + for (int i = 0; i < 4; i++) + S9xSetSDD1MemoryMap (i, Memory.FillRAM [0x4804 + i]); +} + +static int S9xCompareSDD1LoggedDataEntries (const void *p1, const void *p2) +{ + uint8 *b1 = (uint8 *) p1; + uint8 *b2 = (uint8 *) p2; + uint32 a1 = (*b1 << 16) + (*(b1 + 1) << 8) + *(b1 + 2); + uint32 a2 = (*b2 << 16) + (*(b2 + 1) << 8) + *(b2 + 2); + + return (a1 - a2); +} + +void S9xSDD1SaveLoggedData () +{ + if (Memory.SDD1LoggedDataCount != Memory.SDD1LoggedDataCountPrev) + { + qsort (Memory.SDD1LoggedData, Memory.SDD1LoggedDataCount, 8, + S9xCompareSDD1LoggedDataEntries); + + FILE *fs = fopen (S9xGetFilename (".dat", PATCH_DIR), "wb"); + + if (fs) + { + fwrite (Memory.SDD1LoggedData, 8, + Memory.SDD1LoggedDataCount, fs); + fclose (fs); +#if defined(__linux) + chown (S9xGetFilename (".dat", PATCH_DIR), getuid (), getgid ()); +#endif + } + Memory.SDD1LoggedDataCountPrev = Memory.SDD1LoggedDataCount; + } +} + +void S9xSDD1LoadLoggedData () +{ + FILE *fs = fopen (S9xGetFilename (".dat", PATCH_DIR), "rb"); + + Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = 0; + + if (fs) + { + int c = fread (Memory.SDD1LoggedData, 8, + MEMMAP_MAX_SDD1_LOGGED_ENTRIES, fs); + + if (c != EOF) + Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = c; + fclose (fs); + } +} + diff --git a/source/snes9x/sdd1.h b/source/snes9x/sdd1.h new file mode 100644 index 0000000..0cc17a8 --- /dev/null +++ b/source/snes9x/sdd1.h @@ -0,0 +1,153 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _SDD1_H_ +#define _SDD1_H_ +void S9xSetSDD1MemoryMap (uint32 bank, uint32 value); +void S9xResetSDD1 (); +void S9xSDD1PostLoadState (); +void S9xSDD1SaveLoggedData (); +void S9xSDD1LoadLoggedData (); +#endif + diff --git a/source/snes9x/sdd1emu.cpp b/source/snes9x/sdd1emu.cpp new file mode 100644 index 0000000..9e6a5a1 --- /dev/null +++ b/source/snes9x/sdd1emu.cpp @@ -0,0 +1,469 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +/* S-DD1 decompressor + * + * Based on code and documentation by Andreas Naive, who deserves a great deal + * of thanks and credit for figuring this out. + * + * Andreas says: + * The author is greatly indebted with The Dumper, without whose help and + * patience providing him with real S-DD1 data the research had never been + * possible. He also wish to note that in the very beggining of his research, + * Neviksti had done some steps in the right direction. By last, the author is + * indirectly indebted to all the people that worked and contributed in the + * S-DD1 issue in the past. + */ + +#include +#include "port.h" +#include "sdd1emu.h" + +static int valid_bits; +static uint16 in_stream; +static uint8 *in_buf; +static uint8 bit_ctr[8]; +static uint8 context_states[32]; +static int context_MPS[32]; +static int bitplane_type; +static int high_context_bits; +static int low_context_bits; +static int prev_bits[8]; + +static struct { + uint8 code_size; + uint8 MPS_next; + uint8 LPS_next; +} evolution_table[] = { + /* 0 */ { 0,25,25}, + /* 1 */ { 0, 2, 1}, + /* 2 */ { 0, 3, 1}, + /* 3 */ { 0, 4, 2}, + /* 4 */ { 0, 5, 3}, + /* 5 */ { 1, 6, 4}, + /* 6 */ { 1, 7, 5}, + /* 7 */ { 1, 8, 6}, + /* 8 */ { 1, 9, 7}, + /* 9 */ { 2,10, 8}, + /* 10 */ { 2,11, 9}, + /* 11 */ { 2,12,10}, + /* 12 */ { 2,13,11}, + /* 13 */ { 3,14,12}, + /* 14 */ { 3,15,13}, + /* 15 */ { 3,16,14}, + /* 16 */ { 3,17,15}, + /* 17 */ { 4,18,16}, + /* 18 */ { 4,19,17}, + /* 19 */ { 5,20,18}, + /* 20 */ { 5,21,19}, + /* 21 */ { 6,22,20}, + /* 22 */ { 6,23,21}, + /* 23 */ { 7,24,22}, + /* 24 */ { 7,24,23}, + /* 25 */ { 0,26, 1}, + /* 26 */ { 1,27, 2}, + /* 27 */ { 2,28, 4}, + /* 28 */ { 3,29, 8}, + /* 29 */ { 4,30,12}, + /* 30 */ { 5,31,16}, + /* 31 */ { 6,32,18}, + /* 32 */ { 7,24,22} +}; + +static uint8 run_table[128] = { + 128, 64, 96, 32, 112, 48, 80, 16, 120, 56, 88, 24, 104, 40, 72, + 8, 124, 60, 92, 28, 108, 44, 76, 12, 116, 52, 84, 20, 100, 36, + 68, 4, 126, 62, 94, 30, 110, 46, 78, 14, 118, 54, 86, 22, 102, + 38, 70, 6, 122, 58, 90, 26, 106, 42, 74, 10, 114, 50, 82, 18, + 98, 34, 66, 2, 127, 63, 95, 31, 111, 47, 79, 15, 119, 55, 87, + 23, 103, 39, 71, 7, 123, 59, 91, 27, 107, 43, 75, 11, 115, 51, + 83, 19, 99, 35, 67, 3, 125, 61, 93, 29, 109, 45, 77, 13, 117, + 53, 85, 21, 101, 37, 69, 5, 121, 57, 89, 25, 105, 41, 73, 9, + 113, 49, 81, 17, 97, 33, 65, 1 +}; + +static inline uint8 GetCodeword(int bits){ + uint8 tmp; + + if(!valid_bits){ + in_stream|=*(in_buf++); + valid_bits=8; + } + in_stream<<=1; + valid_bits--; + in_stream^=0x8000; + if(in_stream&0x8000) return 0x80+(1<>8) | (0x7f>>bits); + in_stream<<=bits; + valid_bits-=bits; + if(valid_bits<0){ + in_stream |= (*(in_buf++))<<(-valid_bits); + valid_bits+=8; + } + return run_table[tmp]; +} + +static inline uint8 GolombGetBit(int code_size){ + if(!bit_ctr[code_size]) bit_ctr[code_size]=GetCodeword(code_size); + bit_ctr[code_size]--; + if(bit_ctr[code_size]==0x80){ + bit_ctr[code_size]=0; + return 2; /* secret code for 'last zero'. ones are always last. */ + } + return (bit_ctr[code_size]==0)?1:0; +} + +static inline uint8 ProbGetBit(uint8 context){ + uint8 state=context_states[context]; + uint8 bit=GolombGetBit(evolution_table[state].code_size); + + if(bit&1){ + context_states[context]=evolution_table[state].LPS_next; + if(state<2){ + context_MPS[context]^=1; + return context_MPS[context]; /* just inverted, so just return it */ + } else{ + return context_MPS[context]^1; /* we know bit is 1, so use a constant */ + } + } else if(bit){ + context_states[context]=evolution_table[state].MPS_next; + /* zero here, zero there, no difference so drop through. */ + } + return context_MPS[context]; /* we know bit is 0, so don't bother xoring */ +} + +static inline uint8 GetBit(uint8 cur_bitplane){ + uint8 bit; + + bit=ProbGetBit(((cur_bitplane&1)<<4) + | ((prev_bits[cur_bitplane]&high_context_bits)>>5) + | (prev_bits[cur_bitplane]&low_context_bits)); + + prev_bits[cur_bitplane] <<= 1; + prev_bits[cur_bitplane] |= bit; + return bit; +} + +void SDD1_decompress(uint8 *out, uint8 *in, int len){ + uint8 bit, i, plane; + uint8 byte1, byte2; + + if(len==0) len=0x10000; + + bitplane_type=in[0]>>6; + + switch(in[0]&0x30){ + case 0x00: + high_context_bits=0x01c0; + low_context_bits =0x0001; + break; + case 0x10: + high_context_bits=0x0180; + low_context_bits =0x0001; + break; + case 0x20: + high_context_bits=0x00c0; + low_context_bits =0x0001; + break; + case 0x30: + high_context_bits=0x0180; + low_context_bits =0x0003; + break; + } + + in_stream=(in[0]<<11) | (in[1]<<3); + valid_bits=5; + in_buf=in+2; + memset(bit_ctr, 0, sizeof(bit_ctr)); + memset(context_states, 0, sizeof(context_states)); + memset(context_MPS, 0, sizeof(context_MPS)); + memset(prev_bits, 0, sizeof(prev_bits)); + + switch(bitplane_type){ + case 0: + while(1) { + for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ + if(GetBit(0)) byte1 |= bit; + if(GetBit(1)) byte2 |= bit; + } + *(out++)=byte1; + if(!--len) return; + *(out++)=byte2; + if(!--len) return; + } + break; + case 1: + i=plane=0; + while(1) { + for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ + if(GetBit(plane)) byte1 |= bit; + if(GetBit(plane+1)) byte2 |= bit; + } + *(out++)=byte1; + if(!--len) return; + *(out++)=byte2; + if(!--len) return; + if(!(i+=32)) plane = (plane+2)&7; + } + break; + case 2: + i=plane=0; + while(1) { + for(byte1=byte2=0, bit=0x80; bit; bit>>=1){ + if(GetBit(plane)) byte1 |= bit; + if(GetBit(plane+1)) byte2 |= bit; + } + *(out++)=byte1; + if(!--len) return; + *(out++)=byte2; + if(!--len) return; + if(!(i+=32)) plane ^= 2; + } + break; + case 3: + do { + for(byte1=plane=0, bit=1; bit; bit<<=1, plane++){ + if(GetBit(plane)) byte1 |= bit; + } + *(out++)=byte1; + } while(--len); + break; + } +} + +static uint8 cur_plane; +static uint8 num_bits; +static uint8 next_byte; + +void SDD1_init(uint8 *in){ + bitplane_type=in[0]>>6; + + switch(in[0]&0x30){ + case 0x00: + high_context_bits=0x01c0; + low_context_bits =0x0001; + break; + case 0x10: + high_context_bits=0x0180; + low_context_bits =0x0001; + break; + case 0x20: + high_context_bits=0x00c0; + low_context_bits =0x0001; + break; + case 0x30: + high_context_bits=0x0180; + low_context_bits =0x0003; + break; + } + + in_stream=(in[0]<<11) | (in[1]<<3); + valid_bits=5; + in_buf=in+2; + memset(bit_ctr, 0, sizeof(bit_ctr)); + memset(context_states, 0, sizeof(context_states)); + memset(context_MPS, 0, sizeof(context_MPS)); + memset(prev_bits, 0, sizeof(prev_bits)); + + cur_plane=0; + num_bits=0; +} + +uint8 SDD1_get_byte(void){ + uint8 bit; + uint8 byte=0; + + switch(bitplane_type){ + case 0: + num_bits+=16; + if(num_bits&16){ + next_byte=0; + for(bit=0x80; bit; bit>>=1){ + if(GetBit(0)) byte |= bit; + if(GetBit(1)) next_byte |= bit; + } + return byte; + } else { + return next_byte; + } + + case 1: + num_bits+=16; + if(num_bits&16){ + next_byte=0; + for(bit=0x80; bit; bit>>=1){ + if(GetBit(cur_plane)) byte |= bit; + if(GetBit(cur_plane+1)) next_byte |= bit; + } + return byte; + } else { + if(!num_bits) cur_plane = (cur_plane+2)&7; + return next_byte; + } + + case 2: + num_bits+=16; + if(num_bits&16){ + next_byte=0; + for(bit=0x80; bit; bit>>=1){ + if(GetBit(cur_plane)) byte |= bit; + if(GetBit(cur_plane+1)) next_byte |= bit; + } + return byte; + } else { + if(!num_bits) cur_plane ^= 2; + return next_byte; + } + + case 3: + for(cur_plane=0, bit=1; bit; bit<<=1, cur_plane++){ + if(GetBit(cur_plane)) byte |= bit; + } + return byte; + + default: + /* should never happen */ + return 0; + } +} + diff --git a/source/snes9x/sdd1emu.h b/source/snes9x/sdd1emu.h new file mode 100644 index 0000000..1a15296 --- /dev/null +++ b/source/snes9x/sdd1emu.h @@ -0,0 +1,159 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef SDD1EMU_H +#define SDD1EMU_H + +/* for START_EXTERN_C/END_EXTERN_C */ +#include "port.h" + +START_EXTERN_C + +void SDD1_decompress(uint8 *out, uint8 *in, int output_length); + +void SDD1_init(uint8 *in); +uint8 SDD1_get_byte(void); + +END_EXTERN_C + +#endif diff --git a/source/snes9x/seta.cpp b/source/snes9x/seta.cpp new file mode 100644 index 0000000..364e9b7 --- /dev/null +++ b/source/snes9x/seta.cpp @@ -0,0 +1,160 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "seta.h" + +void (*SetSETA)(uint32, uint8)=&S9xSetST010; +uint8 (*GetSETA)(uint32)=&S9xGetST010; + +extern "C"{ +uint8 S9xGetSetaDSP(uint32 Address) +{ + return GetSETA(Address); +} + +void S9xSetSetaDSP(uint8 Byte, uint32 Address) +{ + SetSETA(Address, Byte); +} +} + diff --git a/source/snes9x/seta.h b/source/snes9x/seta.h new file mode 100644 index 0000000..89ba983 --- /dev/null +++ b/source/snes9x/seta.h @@ -0,0 +1,211 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef NO_SETA +#ifndef _seta_h +#define _seta_h + +#include "port.h" + +#define ST_010 0x01 +#define ST_011 0x02 +#define ST_018 0x03 + + +extern "C" +{ +uint8 S9xGetSetaDSP(uint32 Address); +void S9xSetSetaDSP(uint8 byte,uint32 Address); +uint8 S9xGetST018(uint32 Address); +void S9xSetST018(uint8 Byte, uint32 Address); + +uint8 S9xGetST010(uint32 Address); +void S9xSetST010(uint32 Address, uint8 Byte); +uint8 S9xGetST011(uint32 Address); +void S9xSetST011(uint32 Address, uint8 Byte); +} + +extern void (*SetSETA)(uint32, uint8); +extern uint8 (*GetSETA)(uint32); + +typedef struct SETA_ST010_STRUCT +{ + uint8 input_params[16]; + uint8 output_params[16]; + uint8 op_reg; + uint8 execute; + bool8 control_enable; +} ST010_Regs; + +typedef struct SETA_ST011_STRUCT +{ + bool8 waiting4command; + uint8 status; + uint8 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters [512]; + uint8 output [512]; +} ST011_Regs; + +typedef struct SETA_ST018_STRUCT +{ + bool8 waiting4command; + uint8 status; + uint8 part_command; + uint8 pass; + uint32 command; + uint32 in_count; + uint32 in_index; + uint32 out_count; + uint32 out_index; + uint8 parameters [512]; + uint8 output [512]; +} ST018_Regs; + +#endif +#endif + diff --git a/source/snes9x/seta010.cpp b/source/snes9x/seta010.cpp new file mode 100644 index 0000000..8987851 --- /dev/null +++ b/source/snes9x/seta010.cpp @@ -0,0 +1,805 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "seta.h" +#include "memmap.h" + +// Mode 7 scaling constants for all raster lines +const int16 ST010_M7Scale[176] = { + 0x0380, 0x0325, 0x02da, 0x029c, 0x0268, 0x023b, 0x0215, 0x01f3, + 0x01d5, 0x01bb, 0x01a3, 0x018e, 0x017b, 0x016a, 0x015a, 0x014b, + 0x013e, 0x0132, 0x0126, 0x011c, 0x0112, 0x0109, 0x0100, 0x00f8, + 0x00f0, 0x00e9, 0x00e3, 0x00dc, 0x00d6, 0x00d1, 0x00cb, 0x00c6, + 0x00c1, 0x00bd, 0x00b8, 0x00b4, 0x00b0, 0x00ac, 0x00a8, 0x00a5, + 0x00a2, 0x009e, 0x009b, 0x0098, 0x0095, 0x0093, 0x0090, 0x008d, + 0x008b, 0x0088, 0x0086, 0x0084, 0x0082, 0x0080, 0x007e, 0x007c, + 0x007a, 0x0078, 0x0076, 0x0074, 0x0073, 0x0071, 0x006f, 0x006e, + 0x006c, 0x006b, 0x0069, 0x0068, 0x0067, 0x0065, 0x0064, 0x0063, + 0x0062, 0x0060, 0x005f, 0x005e, 0x005d, 0x005c, 0x005b, 0x005a, + 0x0059, 0x0058, 0x0057, 0x0056, 0x0055, 0x0054, 0x0053, 0x0052, + 0x0051, 0x0051, 0x0050, 0x004f, 0x004e, 0x004d, 0x004d, 0x004c, + 0x004b, 0x004b, 0x004a, 0x0049, 0x0048, 0x0048, 0x0047, 0x0047, + 0x0046, 0x0045, 0x0045, 0x0044, 0x0044, 0x0043, 0x0042, 0x0042, + 0x0041, 0x0041, 0x0040, 0x0040, 0x003f, 0x003f, 0x003e, 0x003e, + 0x003d, 0x003d, 0x003c, 0x003c, 0x003b, 0x003b, 0x003a, 0x003a, + 0x003a, 0x0039, 0x0039, 0x0038, 0x0038, 0x0038, 0x0037, 0x0037, + 0x0036, 0x0036, 0x0036, 0x0035, 0x0035, 0x0035, 0x0034, 0x0034, + 0x0034, 0x0033, 0x0033, 0x0033, 0x0032, 0x0032, 0x0032, 0x0031, + 0x0031, 0x0031, 0x0030, 0x0030, 0x0030, 0x0030, 0x002f, 0x002f, + 0x002f, 0x002e, 0x002e, 0x002e, 0x002e, 0x002d, 0x002d, 0x002d, + 0x002d, 0x002c, 0x002c, 0x002c, 0x002c, 0x002b, 0x002b, 0x002b +}; + +// H-DMA hack +bool seta_hack; + +//temporary Op04 requirement +#include + +#ifndef PI +#define PI 3.1415926535897932384626433832795 +#endif + +ST010_Regs ST010; + +uint8 S9xGetST010(uint32 Address) +{ + if(!(Address&0x80000)) + return 0x80; + + if((Address&0xFFF)==0x20) + return ST010.op_reg; + if ((Address&0xFFF)==0x21) + return ST010.execute; + return Memory.SRAM[Address&Memory.SRAMMask]; +} + +const int16 ST010_SinTable[256] = { + 0x0000, 0x0324, 0x0648, 0x096a, 0x0c8c, 0x0fab, 0x12c8, 0x15e2, + 0x18f9, 0x1c0b, 0x1f1a, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, + 0x30fb, 0x33df, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, + 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, + 0x5a82, 0x5cb3, 0x5ed7, 0x60eb, 0x62f1, 0x64e8, 0x66cf, 0x68a6, + 0x6a6d, 0x6c23, 0x6dc9, 0x6f5e, 0x70e2, 0x7254, 0x73b5, 0x7504, + 0x7641, 0x776b, 0x7884, 0x7989, 0x7a7c, 0x7b5c, 0x7c29, 0x7ce3, + 0x7d89, 0x7e1d, 0x7e9c, 0x7f09, 0x7f61, 0x7fa6, 0x7fd8, 0x7ff5, + 0x7fff, 0x7ff5, 0x7fd8, 0x7fa6, 0x7f61, 0x7f09, 0x7e9c, 0x7e1d, + 0x7d89, 0x7ce3, 0x7c29, 0x7b5c, 0x7a7c, 0x7989, 0x7884, 0x776b, + 0x7641, 0x7504, 0x73b5, 0x7254, 0x70e2, 0x6f5e, 0x6dc9, 0x6c23, + 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f1, 0x60eb, 0x5ed7, 0x5cb3, + 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, + 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33df, + 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f1a, 0x1c0b, + 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8c, 0x096a, 0x0648, 0x0324, + 0x0000, -0x0324, -0x0648, -0x096b, -0x0c8c, -0x0fab, -0x12c8, -0x15e2, + -0x18f9, -0x1c0b, -0x1f1a, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11, + -0x30fb, -0x33df, -0x36ba, -0x398d, -0x3c56, -0x3f17, -0x41ce, -0x447a, + -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842, + -0x5a82, -0x5cb3, -0x5ed7, -0x60ec, -0x62f1, -0x64e8, -0x66cf, -0x68a6, + -0x6a6d, -0x6c23, -0x6dc9, -0x6f5e, -0x70e2, -0x7254, -0x73b5, -0x7504, + -0x7641, -0x776b, -0x7884, -0x7989, -0x7a7c, -0x7b5c, -0x7c29, -0x7ce3, + -0x7d89, -0x7e1d, -0x7e9c, -0x7f09, -0x7f61, -0x7fa6, -0x7fd8, -0x7ff5, + -0x7fff, -0x7ff5, -0x7fd8, -0x7fa6, -0x7f61, -0x7f09, -0x7e9c, -0x7e1d, + -0x7d89, -0x7ce3, -0x7c29, -0x7b5c, -0x7a7c, -0x7989, -0x7883, -0x776b, + -0x7641, -0x7504, -0x73b5, -0x7254, -0x70e2, -0x6f5e, -0x6dc9, -0x6c23, + -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f1, -0x60eb, -0x5ed7, -0x5cb3, + -0x5a82, -0x5842, -0x55f5, -0x539a, -0x5133, -0x4ebf, -0x4c3f, -0x49b3, + -0x471c, -0x447a, -0x41cd, -0x3f17, -0x3c56, -0x398c, -0x36b9, -0x33de, + -0x30fb, -0x2e10, -0x2b1f, -0x2826, -0x2527, -0x2223, -0x1f19, -0x1c0b, + -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324}; + +const unsigned char ST010_ArcTan[32][32] = { + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, + { 0x80, 0xa0, 0xad, 0xb3, 0xb6, 0xb8, 0xb9, 0xba, 0xbb, 0xbb, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, 0xbf, 0xbf, 0xbf}, + { 0x80, 0x93, 0xa0, 0xa8, 0xad, 0xb0, 0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd}, + { 0x80, 0x8d, 0x98, 0xa0, 0xa6, 0xaa, 0xad, 0xb0, 0xb1, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb7, 0xb8, + 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbc}, + { 0x80, 0x8a, 0x93, 0x9a, 0xa0, 0xa5, 0xa8, 0xab, 0xad, 0xaf, 0xb0, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5, + 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xba, 0xba, 0xbb, 0xbb}, + { 0x80, 0x88, 0x90, 0x96, 0x9b, 0xa0, 0xa4, 0xa7, 0xa9, 0xab, 0xad, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb4, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9}, + { 0x80, 0x87, 0x8d, 0x93, 0x98, 0x9c, 0xa0, 0xa3, 0xa6, 0xa8, 0xaa, 0xac, 0xad, 0xae, 0xb0, 0xb0, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8}, + { 0x80, 0x86, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa0, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xad, 0xae, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6, 0xb7, 0xb7}, + { 0x80, 0x85, 0x8a, 0x8f, 0x93, 0x97, 0x9a, 0x9d, 0xa0, 0xa2, 0xa5, 0xa6, 0xa8, 0xaa, 0xab, 0xac, + 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb5}, + { 0x80, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x98, 0x9b, 0x9e, 0xa0, 0xa0, 0xa4, 0xa6, 0xa7, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4}, + { 0x80, 0x84, 0x88, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa2, 0xa4, 0xa5, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb2, 0xb2, 0xb2, 0xb3, 0xb3}, + { 0x80, 0x84, 0x87, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, 0xa6, + 0xa7, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2, 0xb2}, + { 0x80, 0x83, 0x87, 0x8a, 0x8d, 0x90, 0x93, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa3, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1}, + { 0x80, 0x83, 0x86, 0x89, 0x8c, 0x8f, 0x92, 0x94, 0x96, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xb0}, + { 0x80, 0x83, 0x86, 0x89, 0x8b, 0x8e, 0x90, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9e, 0xa0, 0xa1, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf}, + { 0x80, 0x83, 0x85, 0x88, 0x8b, 0x8d, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9b, 0x9d, 0x9f, 0xa0, + 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae}, + { 0x80, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x97, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xac, 0xad}, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97, 0x99, 0x9b, 0x9c, 0x9d, + 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa, 0xaa, 0xab, 0xac}, + { 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8d, 0x8f, 0x91, 0x93, 0x95, 0x96, 0x98, 0x99, 0x9b, 0x9c, + 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab}, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x9a, 0x9b, + 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8, 0xa8, 0xa9, 0xaa}, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x99, 0x9a, + 0x9b, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa9}, + { 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8f, 0x90, 0x92, 0x94, 0x95, 0x97, 0x98, 0x99, + 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7, 0xa8}, + { 0x80, 0x82, 0x84, 0x86, 0x87, 0x89, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x93, 0x94, 0x96, 0x97, 0x98, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa3, 0xa4, 0xa5, 0xa6, 0xa6, 0xa7}, + { 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x94, 0x95, 0x96, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5, 0xa6}, + { 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8a, 0x8c, 0x8d, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa5, 0xa5}, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x8a, 0x8b, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4}, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x88, 0x89, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa2, 0xa3, 0xa4}, + { 0x80, 0x82, 0x83, 0x85, 0x86, 0x87, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2, 0xa3}, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x89, 0x8a, 0x8b, 0x8d, 0x8e, 0x8f, 0x90, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9e, 0x9f, 0xa0, 0xa1, 0xa1, 0xa2}, + { 0x80, 0x81, 0x83, 0x84, 0x86, 0x87, 0x88, 0x8a, 0x8b, 0x8c, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1, 0xa1}, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8b, 0x8c, 0x8d, 0x8e, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0, 0xa1}, + { 0x80, 0x81, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9c, 0x9d, 0x9e, 0x9f, 0x9f, 0xa0}}; + +short ST010_Sin(short Theta) +{ + return ST010_SinTable[(Theta >> 8) & 0xff]; +} + +short ST010_Cos(short Theta) +{ + return ST010_SinTable[((Theta + 0x4000) >> 8) & 0xff]; +} + +void ST010_OP01(short x0, short y0, short &x1, short &y1, short &Quadrant, short &Theta) +{ + if ((x0 < 0) && (y0 < 0)) + { + x1 = -x0; + y1 = -y0; + Quadrant = -0x8000; + } + else if (x0 < 0) + { + x1 = y0; + y1 = -x0; + Quadrant = -0x4000; + } + else if (y0 < 0) + { + x1 = -y0; + y1 = x0; + Quadrant = 0x4000; + } + else + { + x1 = x0; + y1 = y0; + Quadrant = 0x0000; + } + + while ((x1 > 0x1f) || (y1 > 0x1f)) + { + if (x1 > 1) x1 >>= 1; + if (y1 > 1) y1 >>= 1; + } + + if (y1 == 0) Quadrant += 0x4000; + + Theta = (ST010_ArcTan[y1][x1] << 8) ^ Quadrant; +} + +void ST010_Scale(short Multiplier, short X0, short Y0, int &X1, int &Y1) +{ + X1 = X0 * Multiplier << 1; + Y1 = Y0 * Multiplier << 1; +} + +void ST010_Multiply(short Multiplicand, short Multiplier, int &Product) +{ + Product = Multiplicand * Multiplier << 1; +} + +void ST010_Rotate(short Theta, short X0, short Y0, short &X1, short &Y1) +{ + X1 = (Y0 * ST010_Sin(Theta) >> 15) + (X0 * ST010_Cos(Theta) >> 15); + Y1 = (Y0 * ST010_Cos(Theta) >> 15) - (X0 * ST010_Sin(Theta) >> 15); +} + +void SETA_Distance(short Y0, short X0, short &Distance) +{ + if (X0 < 0) X0 = -X0; + if (Y0 < 0) Y0 = -Y0; + Distance = ((X0 * 0x7af0) + 0x4000) >> 15; +} + +void ST010_SortDrivers(uint16 Positions, uint16 Places[32], uint16 Drivers[32]) +{ + bool Sorted; + uint16 Temp; + + if (Positions > 1) + do { + Sorted = true; + for (int i = 0; i < Positions - 1; i++) + if (Places[i] < Places[i + 1]) + { + Temp = Places[i + 1]; + Places[i + 1] = Places[i]; + Places[i] = Temp; + + Temp = Drivers[i + 1]; + Drivers[i + 1] = Drivers[i]; + Drivers[i] = Temp; + + Sorted = false; + } + Positions--; + } while (!Sorted); +} + +#define ST010_WORD(offset) (Memory.SRAM[offset + 1] << 8) | Memory.SRAM[offset] + +void S9xSetST010(uint32 Address, uint8 Byte) +{ + if(!(Address&0x80000)) + { + ST010.control_enable=TRUE; + return; + } + //printf("Write %06X:%02X\n", Address, Byte); + + if((Address &0xFFF) ==0x20 && ST010.control_enable) + ST010.op_reg=Byte; + if((Address &0xFFF) ==0x21 && ST010.control_enable) + ST010.execute=Byte; + else Memory.SRAM[Address&Memory.SRAMMask]=Byte; + + if(ST010.execute&0x80) + { + switch(ST010.op_reg) + { + // Sorts Driver Placements + // + // Input + // 0x0024-0x0025 : Positions + // 0x0040-0x007f : Places + // 0x0080-0x00ff : Drivers + // Output + // 0x0040-0x007f : Places + // 0x0080-0x00ff : Drivers + // + case 0x02: + { +#ifdef FAST_LSB_WORD_ACCESS + ST010_SortDrivers(*(short*)&SRAM[0x0024], (uint16*) (SRAM + 0x0040), (uint16*) (SRAM + 0x0080)); +#else + uint16 Places[32]; + uint16 Positions = ST010_WORD(0x0024); + int Pos, Offset; + + Offset = 0; + + for (Pos = 0; Pos < Positions; Pos++) + { + Places[Pos] = ST010_WORD(0x0040 + Offset); + Offset += 2; + } + + ST010_SortDrivers(Positions, Places, (uint16*) (SRAM + 0x0080)); + + Offset = 0; + + for (Pos = 0; Pos < Positions; Pos++) + { + SRAM[0x0040 + Offset]=(uint8)(Places[Pos]); + SRAM[0x0041 + Offset]=(uint8)(Places[Pos] >> 8); + Offset += 2; + } +#endif + break; + + } + + // Two Dimensional Coordinate Scale + // + // Input + // 0x0000-0x0001 : X0 (signed) + // 0x0002-0x0003 : Y0 (signed) + // 0x0004-0x0005 : Multiplier (signed) + // Output + // 0x0010-0x0013 : X1 (signed) + // 0x0014-0x0017 : Y1 (signed) + // + case 0x03: + { +#ifdef FAST_LSB_WORD_ACCESS + ST010_Scale(*(short*)&Memory.SRAM[0x0004], *(short*)&Memory.SRAM[0x0000], *(short*)&Memory.SRAM[0x0002], + (int&) Memory.SRAM[0x0010], (int&) Memory.SRAM[0x0014]); +#else + int x1, y1; + + ST010_Scale(ST010_WORD(0x0004), ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1); + + Memory.SRAM[0x0010]=(uint8)(x1); + Memory.SRAM[0x0011]=(uint8)(x1 >> 8); + Memory.SRAM[0x0012]=(uint8)(x1 >> 16); + Memory.SRAM[0x0013]=(uint8)(x1 >> 24); + Memory.SRAM[0x0014]=(uint8)(y1); + Memory.SRAM[0x0015]=(uint8)(y1 >> 8); + Memory.SRAM[0x0016]=(uint8)(y1 >> 16); + Memory.SRAM[0x0017]=(uint8)(y1 >> 24); +#endif + break; + } + + // 16-bit Multiplication + // + // Input + // 0x0000-0x0001 : Multiplcand (signed) + // 0x0002-0x0003 : Multiplier (signed) + // Output + // 0x0010-0x0013 : Product (signed) + // + case 0x06: + { +#ifdef FAST_LSB_WORD_ACCESS + ST010_Multiply(*(short*)&Memory.SRAM[0x0000], *(short*)&Memory.SRAM[0x0002], (int&) Memory.SRAM[0x0010]); +#else + int Product; + + ST010_Multiply(ST010_WORD(0x0000), ST010_WORD(0x0002), Product); + + Memory.SRAM[0x0010]=(uint8)(Product); + Memory.SRAM[0x0011]=(uint8)(Product >> 8); + Memory.SRAM[0x0012]=(uint8)(Product >> 16); + Memory.SRAM[0x0013]=(uint8)(Product >> 24); +#endif + break; + } + + // Mode 7 Raster Data Calculation + // + // Input + // 0x0000-0x0001 : Angle (signed) + // Output + // 0x00f0-0x024f : Mode 7 Matrix A + // 0x0250-0x03af : Mode 7 Matrix B + // 0x03b0-0x050f : Mode 7 Matrix C + // 0x0510-0x066f : Mode 7 Matrix D + // + case 0x07: + { + int16 data; + int32 offset = 0; + int16 Theta = ST010_WORD(0x0000); + + for (int32 line = 0; line < 176; line++) + { + // Calculate Mode 7 Matrix A/D data + data = ST010_M7Scale[line] * ST010_Cos(Theta) >> 15; + + Memory.SRAM[0x00f0 + offset]=(uint8)(data); + Memory.SRAM[0x00f1 + offset]=(uint8)(data >> 8); + Memory.SRAM[0x0510 + offset]=(uint8)(data); + Memory.SRAM[0x0511 + offset]=(uint8)(data >> 8); + + // Calculate Mode 7 Matrix B/C data + data = ST010_M7Scale[line] * ST010_Sin(Theta) >> 15; + + Memory.SRAM[0x0250 + offset]=(uint8)(data); + Memory.SRAM[0x0251 + offset]=(uint8)(data >> 8); + + if (data) data = ~data; + + Memory.SRAM[0x03b0 + offset]=(uint8)(data); + Memory.SRAM[0x03b1 + offset]=(uint8)(data >> 8); + + offset += 2; + } + + // Shift Angle for use with Lookup table + Memory.SRAM[0x00] = Memory.SRAM[0x01]; + Memory.SRAM[0x01] = 0x00; + + break; + } + + // Two dimensional Coordinate Rotation + // + // Input + // 0x0000-0x0001 : X0 (signed) + // 0x0002-0x0003 : Y0 (signed) + // 0x0004-0x0005 : Angle (signed) + // Output + // 0x0010-0x0011 : X1 (signed) + // 0x0012-0x0013 : Y1 (signed) + // + case 0x08: + { +#ifdef FAST_LSB_WORD_ACCESS + ST010_Rotate(*(short*)&Memory.SRAM[0x0004], *(short*)&Memory.SRAM[0x0000], *(short*)&Memory.SRAM[0x0002], + (short&) Memory.SRAM[0x0010], (short&) Memory.SRAM[0x0012]); +#else + short x1, y1; + + ST010_Rotate(ST010_WORD(0x0004), ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1); + + Memory.SRAM[0x0010]=(uint8)(x1); + Memory.SRAM[0x0011]=(uint8)(x1 >> 8); + Memory.SRAM[0x0012]=(uint8)(y1); + Memory.SRAM[0x0013]=(uint8)(y1 >> 8); +#endif + break; + } + + // Input + // 0x0000-0x0001 : DX (signed) + // 0x0002-0x0003 : DY (signed) + // Output + // 0x0010-0x0011 : Angle (signed) + // + case 0x01: + { + Memory.SRAM[0x0006] = Memory.SRAM[0x0002]; + Memory.SRAM[0x0007] = Memory.SRAM[0x0003]; + +#ifdef FAST_LSB_WORD_ACCESS + ST010_OP01(*(short*)&Memory.SRAM[0x0000], *(short*)&Memory.SRAM[0x0002], + (short&) Memory.SRAM[0x0000], (short&) Memory.SRAM[0x0002], + (short&) Memory.SRAM[0x0004], (short&) Memory.SRAM[0x0010]); +#else + short x1, y1, Quadrant, Theta; + + ST010_OP01(ST010_WORD(0x0000), ST010_WORD(0x0002), x1, y1, Quadrant, Theta); + + Memory.SRAM[0x0000]=(uint8)(x1); + Memory.SRAM[0x0001]=(uint8)(x1 >> 8); + Memory.SRAM[0x0002]=(uint8)(y1); + Memory.SRAM[0x0003]=(uint8)(y1 >> 8); + Memory.SRAM[0x0004]=(uint8)(Quadrant); + Memory.SRAM[0x0005]=(uint8)(Quadrant >> 8); + Memory.SRAM[0x0010]=(uint8)(Theta); + Memory.SRAM[0x0011]=(uint8)(Theta >> 8); +#endif + break; + } + + // calculate the vector length of (x,y) + case 0x04: + { + int16 square, x,y; +#ifdef FAST_LSB_WORD_ACCESS + x=*((int16*)Memory.SRAM); + y=*((int16*)&Memory.SRAM[2]); +#else + x=Memory.SRAM[0]|(Memory.SRAM[1]<<8); + y=Memory.SRAM[2]|(Memory.SRAM[3]<<8); +#endif + square=(int16)sqrt((double)(y*y+x*x)); + //SETA_Distance( x,y,square ); + +#ifdef FAST_LSB_WORD_ACCESS + *((int16*)&Memory.SRAM[0x10])=square; +#else + Memory.SRAM[0x10]=(uint8)(square); + Memory.SRAM[0x11]=(uint8)(square>>8); +#endif + break; + } + + // calculate AI orientation based on specific guidelines + case 0x05: + { + int dx,dy; + int16 a1,b1,c1; + uint16 o1; + + bool wrap=false; + + // target (x,y) coordinates + int16 ypos_max = ST010_WORD(0x00C0); + int16 xpos_max = ST010_WORD(0x00C2); + + // current coordinates and direction + int32 ypos = SRAM[0xC4]|(SRAM[0xC5]<<8)|(SRAM[0xC6]<<16)|(SRAM[0xC7]<<24); + int32 xpos = SRAM[0xC8]|(SRAM[0xC9]<<8)|(SRAM[0xCA]<<16)|(SRAM[0xCB]<<24); + uint16 rot = SRAM[0xCC]|(SRAM[0xCD]<<8); + + // physics + uint16 speed = ST010_WORD(0x00D4); + uint16 accel = ST010_WORD(0x00D6); + uint16 speed_max = ST010_WORD(0x00D8); + + // special condition acknowledgment + int16 system = ST010_WORD(0x00DA); + int16 flags = ST010_WORD(0x00DC); + + // new target coordinates + int16 ypos_new = ST010_WORD(0x00DE); + int16 xpos_new = ST010_WORD(0x00E0); + + // mask upper bit + xpos_new &= 0x7FFF; + + // get the current distance + dx = xpos_max-(xpos>>16); + dy = ypos_max-(ypos>>16); + + // quirk: clear and move in9 + SRAM[0xD2]=0xFF; + SRAM[0xD3]=0xFF; + SRAM[0xDA]=0; + SRAM[0xDB]=0; + + // grab the target angle + ST010_OP01(dy,dx,a1,b1,c1,(int16 &)o1); + + // check for wrapping + //if((o1<0x6000 && rot>0xA000) || + // (rot<0x6000 && o1>0xA000)) + //if(o10x8000) + { + o1+=0x8000; + rot+=0x8000; + wrap=true; + } + //o1=0x0000; + //rot=0xFF00; + + uint16 old_speed; + + old_speed = speed; + + // special case + if(abs(o1-rot)==0x8000) + { + speed = 0x100; + } + // slow down for sharp curves + else if(abs(o1-rot)>=0x1000) + { + uint32 slow = abs(o1-rot); + slow >>= 4; // scaling + speed -= slow; + } + // otherwise accelerate + else + { + speed += accel; + if(speed > speed_max) + { + // clip speed + speed = speed_max; + } + } + + // prevent negative/positive overflow + if(abs(old_speed-speed)>0x8000) { + if(old_speedrot && (o1-rot)>0x80) || + (o1=0x80) ) + { + if(o1rot) rot+=0x280; + } + + // turn off wrapping + if(wrap) rot-=0x8000; + + // now check the distances (store for later) + dx = (xpos_max<<16)-xpos; + dy = (ypos_max<<16)-ypos; + dx>>=16; + dy>>=16; + + // if we're in so many units of the target, signal it + if( ( system && (dy<=6 && dy>=-8) && (dx<=126 && dx>=-128)) || + (!system && (dx<=6 && dx>=-8) && (dy<=126 && dy>=-128)) ) + { + // announce our new destination and flag it + xpos_max = xpos_new&0x7FFF; + ypos_max = ypos_new; + flags |= 0x08; + } + + // update position + xpos -= (ST010_Cos(rot) * 0x400 >> 15) * (speed >> 8) << 1; + ypos -= (ST010_Sin(rot) * 0x400 >> 15) * (speed >> 8) << 1; + + // quirk: mask upper byte + xpos &= 0x1FFFFFFF; + ypos &= 0x1FFFFFFF; + + SRAM[0x00C0]=(uint8)(ypos_max); + SRAM[0x00C1]=(uint8)(ypos_max >> 8); + SRAM[0x00C2]=(uint8)(xpos_max); + SRAM[0x00C3]=(uint8)(xpos_max >> 8); + SRAM[0x00C4]=(uint8)(ypos); + SRAM[0x00C5]=(uint8)(ypos >> 8); + SRAM[0x00C6]=(uint8)(ypos >> 16); + SRAM[0x00C7]=(uint8)(ypos >> 24); + SRAM[0x00C8]=(uint8)(xpos); + SRAM[0x00C9]=(uint8)(xpos >> 8); + SRAM[0x00CA]=(uint8)(xpos >> 16); + SRAM[0x00CB]=(uint8)(xpos >> 24); + SRAM[0x00CC]=(uint8)(rot); + SRAM[0x00CD]=(uint8)(rot >> 8); + SRAM[0x00D4]=(uint8)(speed); + SRAM[0x00D5]=(uint8)(speed >> 8); + SRAM[0x00DC]=(uint8)(flags); + SRAM[0x00DD]=(uint8)(flags >> 8); + + break; + } + + default: + printf("Unknown Op\n"); + break; + } + + // lower signal: op processed + ST010.op_reg=0; + ST010.execute=0; + } +} + diff --git a/source/snes9x/seta011.cpp b/source/snes9x/seta011.cpp new file mode 100644 index 0000000..aff5429 --- /dev/null +++ b/source/snes9x/seta011.cpp @@ -0,0 +1,287 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include "seta.h" +#include "memmap.h" + +ST011_Regs ST011; + +// shougi playboard +uint8 board[9][9]; + +// debug +static int line = 0; + +uint8 S9xGetST011(uint32 Address) +{ + uint8 t; + uint16 address = (uint16) Address & 0xFFFF; + + // line counter + line++; + + // status check + if (address == 0x01) + { + t = 0xFF; + } + // read directly from s-ram + else + { + t = Memory.SRAM[address]; + } + + // debug +// if(address<0x150) +// printf( "ST011 R: %06X %02X\n", Address, t); + + return t; +} + +void S9xSetST011(uint32 Address, uint8 Byte) +{ + uint16 address = (uint16) Address & 0xFFFF; + static bool reset = false; + + // debug + line++; + + if(!reset) + { + // bootup values + ST011.waiting4command = true; + reset = true; + } + + // debug +// if(address<0x150) +// printf( "ST011 W: %06X %02X\n", Address, Byte ); + + Memory.SRAM[address]=Byte; + + // op commands/data goes through this address + if(address==0x00) + { + // check for new commands + if (ST011.waiting4command) + { + ST011.waiting4command = false; + ST011.command = Byte; + ST011.in_index = 0; + ST011.out_index = 0; + switch(ST011.command) + { + case 0x01: ST011.in_count = 12*10+8; break; + case 0x02: ST011.in_count = 4; break; + case 0x04: ST011.in_count = 0; break; + case 0x05: ST011.in_count = 0; break; + case 0x06: ST011.in_count = 0; break; + case 0x07: ST011.in_count = 0; break; + case 0x0E: ST011.in_count = 0; break; + default: ST011.waiting4command=true; break; + } + } + else + { + ST011.parameters [ST011.in_index] = Byte; + ST011.in_index++; + } + } + + if (ST011.in_count==ST011.in_index) + { + // Actually execute the command + ST011.waiting4command = true; + ST011.out_index = 0; + switch (ST011.command) + { + // unknown: download playboard + case 0x01: + { + // 9x9 board data: top to bottom, left to right + // Values represent piece types and ownership + for( int lcv=0; lcv<9; lcv++ ) + memcpy( board[lcv], ST011.parameters+lcv*10, 9*1 ); + } + break; + + // unknown + case 0x02: break; + + // unknown + case 0x04: + { + // outputs + Memory.SRAM[0x12C] = 0x00; + //Memory.SRAM[0x12D] = 0x00; + Memory.SRAM[0x12E] = 0x00; + } + break; + + // unknown + case 0x05: + { + // outputs + Memory.SRAM[0x12C] = 0x00; + //Memory.SRAM[0x12D] = 0x00; + Memory.SRAM[0x12E] = 0x00; + } + break; + + // unknown + case 0x06: break; + case 0x07: break; + + // unknown + case 0x0E: + { + // outputs + Memory.SRAM[0x12C] = 0x00; + Memory.SRAM[0x12D] = 0x00; + } + break; + } + } +} + diff --git a/source/snes9x/seta018.cpp b/source/snes9x/seta018.cpp new file mode 100644 index 0000000..505c17e --- /dev/null +++ b/source/snes9x/seta018.cpp @@ -0,0 +1,309 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "seta.h" +#include "memmap.h" + +ST018_Regs ST018; + +static int line; // line counter + +extern "C"{ +uint8 S9xGetST018(uint32 Address) +{ + uint8 t = 0; + uint16 address = (uint16) Address & 0xFFFF; + + line++; + + // these roles may be flipped + // op output + if (address == 0x3804) + { + if (ST018.out_count) + { + t = (uint8) ST018.output [ST018.out_index]; + ST018.out_index++; + if (ST018.out_count==ST018.out_index) + ST018.out_count=0; + } + else + t = 0x81; + } + // status register + else if (address == 0x3800) + t = ST018.status; + + printf( "ST018 R: %06X %02X\n", Address, t); + + return t; +} + +void S9xSetST018(uint8 Byte, uint32 Address) +{ + uint16 address = (uint16) Address&0xFFFF; + static bool reset = false; + + printf( "ST018 W: %06X %02X\n", Address, Byte ); + + line++; + + if (!reset) + { + // bootup values + ST018.waiting4command = true; + ST018.part_command = 0; + reset = true; + } + + Memory.SRAM[address]=Byte; + + // default status for now + ST018.status = 0x00; + + // op data goes through this address + if (address==0x3804) + { + // check for new commands: 3 bytes length + if(ST018.waiting4command && ST018.part_command==2) + { + ST018.waiting4command = false; + ST018.command <<= 8; + ST018.command |= Byte; + ST018.in_index = 0; + ST018.out_index = 0; + ST018.part_command = 0; // 3-byte commands + ST018.pass = 0; // data streams into the chip + switch(ST018.command & 0xFFFFFF) + { + case 0x0100: ST018.in_count = 0; break; + case 0xFF00: ST018.in_count = 0; break; + default: ST018.waiting4command = true; break; + } + } + else if(ST018.waiting4command) + { + // 3-byte commands + ST018.part_command++; + ST018.command <<= 8; + ST018.command |= Byte; + } + } + // extra parameters + else if (address==0x3802) + { + ST018.parameters[ST018.in_index] = Byte; + ST018.in_index++; + } + + if (ST018.in_count==ST018.in_index) + { + // Actually execute the command + ST018.waiting4command = true; + ST018.in_index = 0; + ST018.out_index = 0; + switch (ST018.command) + { + // hardware check? + case 0x0100: + ST018.waiting4command = false; + ST018.pass++; + if (ST018.pass==1) + { + ST018.in_count = 1; + ST018.out_count = 2; + + // Overload's research + ST018.output[0x00] = 0x81; + ST018.output[0x01] = 0x81; + } + else + { + //ST018.in_count = 1; + ST018.out_count = 3; + + // no reason to change this + //ST018.output[0x00] = 0x81; + //ST018.output[0x01] = 0x81; + ST018.output[0x02] = 0x81; + + // done processing requests + if (ST018.pass==3) + ST018.waiting4command = true; + } + break; + + // unknown: feels like a security detection + // format identical to 0x0100 + case 0xFF00: + ST018.waiting4command = false; + ST018.pass++; + if (ST018.pass==1) + { + ST018.in_count = 1; + ST018.out_count = 2; + + // Overload's research + ST018.output[0x00] = 0x81; + ST018.output[0x01] = 0x81; + } + else + { + //ST018.in_count = 1; + ST018.out_count = 3; + + // no reason to change this + //ST018.output[0x00] = 0x81; + //ST018.output[0x01] = 0x81; + ST018.output[0x02] = 0x81; + + // done processing requests + if (ST018.pass==3) + ST018.waiting4command = true; + } + break; + } + } +} +} + diff --git a/source/snes9x/snapshot.cpp b/source/snes9x/snapshot.cpp new file mode 100644 index 0000000..0366774 --- /dev/null +++ b/source/snes9x/snapshot.cpp @@ -0,0 +1,2153 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include +#include + +#if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP) +#include +#include +#include +#endif + +#include "snapshot.h" + +#ifndef NGC +#include "snaporig.h" +#endif + +#include "memmap.h" +#include "snes9x.h" +#include "65c816.h" +#include "ppu.h" +#include "cpuexec.h" +#include "display.h" +#include "apu.h" +#include "soundux.h" +#include "sa1.h" +#include "bsx.h" +#include "srtc.h" +#include "sdd1.h" +#include "spc7110.h" +#include "movie.h" +#include "controls.h" +#include "memfile.h" +#include "gccore.h" +#include "ftfont.h" + +extern uint8 *SRAM; + +#ifdef ZSNES_FX +START_EXTERN_C +void S9xSuperFXPreSaveState (); +void S9xSuperFXPostSaveState (); +void S9xSuperFXPostLoadState (); +END_EXTERN_C +#endif + +void S9xResetSaveTimer(bool8 dontsave){ + static time_t t=-1; + + if(!dontsave && t!=-1 && time(NULL)-t>300){{ +#ifndef NGC + char def [PATH_MAX]; + char filename [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + + _splitpath(Memory.ROMFilename, drive, dir, def, ext); + sprintf(filename, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), + SLASH_STR, def, _MAX_EXT-1, "oops"); + S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, "Auto-saving 'oops' savestate"); + Snapshot(filename); +#endif + }} + t=time(NULL); +} + +bool8 S9xUnfreezeZSNES (const char *filename); + +typedef struct { + int offset; + int size; + int type; + uint16 debuted_in, deleted_in; +} FreezeData; + +enum { + INT_V, uint8_ARRAY_V, uint16_ARRAY_V, uint32_ARRAY_V +}; + +static struct Obsolete { + uint8 SPPU_Joypad1ButtonReadPos; + uint8 SPPU_Joypad2ButtonReadPos; + uint8 SPPU_Joypad3ButtonReadPos; + uint8 SPPU_MouseSpeed[2]; + uint8 SAPU_Flags; +} Obsolete; + +#define Offset(field,structure) \ +((int) (((char *) (&(((structure)NULL)->field))) - ((char *) NULL))) +#define DUMMY(f) Offset(f,struct Obsolete *) +#define DELETED(f) (-1) + +#define COUNT(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0])) + +struct SnapshotMovieInfo +{ + uint32 MovieInputDataSize; +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SnapshotMovieInfo *) + +#ifndef NGC +static FreezeData SnapMovie [] = { + {OFFSET (MovieInputDataSize), 4, INT_V, 1, 9999}, +}; +#endif + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SCPUState *) + +static FreezeData SnapCPU [] = { + {OFFSET (Flags), 4, INT_V, 1, 9999}, + {OFFSET (BranchSkip), 1, INT_V, 1, 9999}, + {OFFSET (NMIActive), 1, INT_V, 1, 9999}, + {OFFSET (IRQActive), 1, INT_V, 1, 9999}, + {OFFSET (WaitingForInterrupt), 1, INT_V, 1, 9999}, + {OFFSET (WhichEvent), 1, INT_V, 1, 9999}, + {OFFSET (Cycles), 4, INT_V, 1, 9999}, + {OFFSET (NextEvent), 4, INT_V, 1, 9999}, + {OFFSET (V_Counter), 4, INT_V, 1, 9999}, + {OFFSET (MemSpeed), 4, INT_V, 1, 9999}, + {OFFSET (MemSpeedx2), 4, INT_V, 1, 9999}, + {OFFSET (FastROMSpeed), 4, INT_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SRegisters *) + +static FreezeData SnapRegisters [] = { + {OFFSET (PB), 1, INT_V, 1, 9999}, + {OFFSET (DB), 1, INT_V, 1, 9999}, + {OFFSET (P.W), 2, INT_V, 1, 9999}, + {OFFSET (A.W), 2, INT_V, 1, 9999}, + {OFFSET (D.W), 2, INT_V, 1, 9999}, + {OFFSET (S.W), 2, INT_V, 1, 9999}, + {OFFSET (X.W), 2, INT_V, 1, 9999}, + {OFFSET (Y.W), 2, INT_V, 1, 9999}, + {OFFSET (PCw), 2, INT_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SPPU *) + +static FreezeData SnapPPU [] = { + {OFFSET (BGMode), 1, INT_V, 1, 9999}, + {OFFSET (BG3Priority), 1, INT_V, 1, 9999}, + {OFFSET (Brightness), 1, INT_V, 1, 9999}, + {OFFSET (VMA.High), 1, INT_V, 1, 9999}, + {OFFSET (VMA.Increment), 1, INT_V, 1, 9999}, + {OFFSET (VMA.Address), 2, INT_V, 1, 9999}, + {OFFSET (VMA.Mask1), 2, INT_V, 1, 9999}, + {OFFSET (VMA.FullGraphicCount), 2, INT_V, 1, 9999}, + {OFFSET (VMA.Shift), 2, INT_V, 1, 9999}, + {OFFSET (BG[0].SCBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[0].VOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[0].HOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[0].BGSize), 1, INT_V, 1, 9999}, + {OFFSET (BG[0].NameBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[0].SCSize), 2, INT_V, 1, 9999}, + + {OFFSET (BG[1].SCBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[1].VOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[1].HOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[1].BGSize), 1, INT_V, 1, 9999}, + {OFFSET (BG[1].NameBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[1].SCSize), 2, INT_V, 1, 9999}, + + {OFFSET (BG[2].SCBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[2].VOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[2].HOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[2].BGSize), 1, INT_V, 1, 9999}, + {OFFSET (BG[2].NameBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[2].SCSize), 2, INT_V, 1, 9999}, + + {OFFSET (BG[3].SCBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[3].VOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[3].HOffset), 2, INT_V, 1, 9999}, + {OFFSET (BG[3].BGSize), 1, INT_V, 1, 9999}, + {OFFSET (BG[3].NameBase), 2, INT_V, 1, 9999}, + {OFFSET (BG[3].SCSize), 2, INT_V, 1, 9999}, + + {OFFSET (CGFLIP), 1, INT_V, 1, 9999}, + {OFFSET (CGDATA), 256, uint16_ARRAY_V, 1, 9999}, + {OFFSET (FirstSprite), 1, INT_V, 1, 9999}, +#define O(N) \ + {OFFSET (OBJ[N].HPos), 2, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].VPos), 2, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].Name), 2, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].VFlip), 1, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].HFlip), 1, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].Priority), 1, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].Palette), 1, INT_V, 1, 9999}, \ + {OFFSET (OBJ[N].Size), 1, INT_V, 1, 9999} + + O( 0), O( 1), O( 2), O( 3), O( 4), O( 5), O( 6), O( 7), + O( 8), O( 9), O( 10), O( 11), O( 12), O( 13), O( 14), O( 15), + O( 16), O( 17), O( 18), O( 19), O( 20), O( 21), O( 22), O( 23), + O( 24), O( 25), O( 26), O( 27), O( 28), O( 29), O( 30), O( 31), + O( 32), O( 33), O( 34), O( 35), O( 36), O( 37), O( 38), O( 39), + O( 40), O( 41), O( 42), O( 43), O( 44), O( 45), O( 46), O( 47), + O( 48), O( 49), O( 50), O( 51), O( 52), O( 53), O( 54), O( 55), + O( 56), O( 57), O( 58), O( 59), O( 60), O( 61), O( 62), O( 63), + O( 64), O( 65), O( 66), O( 67), O( 68), O( 69), O( 70), O( 71), + O( 72), O( 73), O( 74), O( 75), O( 76), O( 77), O( 78), O( 79), + O( 80), O( 81), O( 82), O( 83), O( 84), O( 85), O( 86), O( 87), + O( 88), O( 89), O( 90), O( 91), O( 92), O( 93), O( 94), O( 95), + O( 96), O( 97), O( 98), O( 99), O(100), O(101), O(102), O(103), + O(104), O(105), O(106), O(107), O(108), O(109), O(110), O(111), + O(112), O(113), O(114), O(115), O(116), O(117), O(118), O(119), + O(120), O(121), O(122), O(123), O(124), O(125), O(126), O(127), +#undef O + {OFFSET (OAMPriorityRotation), 1, INT_V, 1, 9999}, + {OFFSET (OAMAddr), 2, INT_V, 1, 9999}, + {OFFSET (OAMFlip), 1, INT_V, 1, 9999}, + {OFFSET (OAMTileAddress), 2, INT_V, 1, 9999}, + {OFFSET (IRQVBeamPos), 2, INT_V, 1, 9999}, + {OFFSET (IRQHBeamPos), 2, INT_V, 1, 9999}, + {OFFSET (VBeamPosLatched), 2, INT_V, 1, 9999}, + {OFFSET (HBeamPosLatched), 2, INT_V, 1, 9999}, + {OFFSET (HBeamFlip), 1, INT_V, 1, 9999}, + {OFFSET (VBeamFlip), 1, INT_V, 1, 9999}, + {OFFSET (HVBeamCounterLatched), 1, INT_V, 1, 9999}, + {OFFSET (MatrixA), 2, INT_V, 1, 9999}, + {OFFSET (MatrixB), 2, INT_V, 1, 9999}, + {OFFSET (MatrixC), 2, INT_V, 1, 9999}, + {OFFSET (MatrixD), 2, INT_V, 1, 9999}, + {OFFSET (CentreX), 2, INT_V, 1, 9999}, + {OFFSET (CentreY), 2, INT_V, 1, 9999}, + {OFFSET (M7HOFS), 2, INT_V, 2, 9999}, + {OFFSET (M7VOFS), 2, INT_V, 2, 9999}, + {DUMMY (SPPU_Joypad1ButtonReadPos), 1, INT_V, 1, 2}, + {DUMMY (SPPU_Joypad2ButtonReadPos), 1, INT_V, 1, 2}, + {DUMMY (SPPU_Joypad3ButtonReadPos), 1, INT_V, 1, 2}, + {OFFSET (CGADD), 1, INT_V, 1, 9999}, + {OFFSET (FixedColourRed), 1, INT_V, 1, 9999}, + {OFFSET (FixedColourGreen), 1, INT_V, 1, 9999}, + {OFFSET (FixedColourBlue), 1, INT_V, 1, 9999}, + {OFFSET (SavedOAMAddr), 2, INT_V, 1, 9999}, + {OFFSET (ScreenHeight), 2, INT_V, 1, 9999}, + {OFFSET (WRAM), 4, INT_V, 1, 9999}, + {OFFSET (ForcedBlanking), 1, INT_V, 1, 9999}, + {OFFSET (OBJNameSelect), 2, INT_V, 1, 9999}, + {OFFSET (OBJSizeSelect), 1, INT_V, 1, 9999}, + {OFFSET (OBJNameBase), 2, INT_V, 1, 9999}, + {OFFSET (OAMReadFlip), 1, INT_V, 1, 9999}, + {OFFSET (VTimerEnabled), 1, INT_V, 1, 9999}, + {OFFSET (HTimerEnabled), 1, INT_V, 1, 9999}, + {OFFSET (HTimerPosition), 2, INT_V, 1, 9999}, + {OFFSET (Mosaic), 1, INT_V, 1, 9999}, + {OFFSET (Mode7HFlip), 1, INT_V, 1, 9999}, + {OFFSET (Mode7VFlip), 1, INT_V, 1, 9999}, + {OFFSET (Mode7Repeat), 1, INT_V, 1, 9999}, + {OFFSET (Window1Left), 1, INT_V, 1, 9999}, + {OFFSET (Window1Right), 1, INT_V, 1, 9999}, + {OFFSET (Window2Left), 1, INT_V, 1, 9999}, + {OFFSET (Window2Right), 1, INT_V, 1, 9999}, +#define O(N) \ + {OFFSET (ClipWindowOverlapLogic[N]), 1, INT_V, 1, 9999}, \ + {OFFSET (ClipWindow1Enable[N]), 1, INT_V, 1, 9999}, \ + {OFFSET (ClipWindow2Enable[N]), 1, INT_V, 1, 9999}, \ + {OFFSET (ClipWindow1Inside[N]), 1, INT_V, 1, 9999}, \ + {OFFSET (ClipWindow2Inside[N]), 1, INT_V, 1, 9999} + + O(0), O(1), O(2), O(3), O(4), O(5), + +#undef O + + {OFFSET (CGFLIPRead), 1, INT_V, 1, 9999}, + {OFFSET (Need16x8Mulitply), 1, INT_V, 1, 9999}, + {OFFSET (BGMosaic), 4, uint8_ARRAY_V, 1, 9999}, + {OFFSET (OAMData), 512 + 32, uint8_ARRAY_V, 1, 9999}, + {OFFSET (Need16x8Mulitply), 1, INT_V, 1, 9999}, + {DUMMY (SPPU_MouseSpeed), 2, uint8_ARRAY_V, 1, 2}, + {OFFSET (OAMWriteRegister), 2, INT_V, 2, 9999}, + {OFFSET (BGnxOFSbyte), 1, INT_V, 2, 9999}, + {OFFSET (M7byte), 1, INT_V, 2, 9999}, + {OFFSET (OpenBus1), 1, INT_V, 2, 9999}, + {OFFSET (OpenBus2), 1, INT_V, 2, 9999}, + {OFFSET (VTimerPosition), 2, INT_V, 2, 9999}, +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SDMA *) + +static FreezeData SnapDMA [] = { +#define O(N) \ + {OFFSET (TransferDirection) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (AAddressFixed) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (AAddressDecrement) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (TransferMode) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (ABank) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (AAddress) + N * sizeof (struct SDMA), 2, INT_V, 1, 9999}, \ + {OFFSET (Address) + N * sizeof (struct SDMA), 2, INT_V, 1, 9999}, \ + {OFFSET (BAddress) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {DELETED (TransferBytes), 2, INT_V, 1, 2}, \ + {OFFSET (HDMAIndirectAddressing) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (DMACount_Or_HDMAIndirectAddress) + N * sizeof (struct SDMA), 2, INT_V, 1, 9999}, \ + {OFFSET (IndirectBank) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (Repeat) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (LineCount) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (DoTransfer) + N * sizeof (struct SDMA), 1, INT_V, 1, 9999}, \ + {OFFSET (UnknownByte) + N * sizeof (struct SDMA), 1, INT_V, 2, 9999}, \ + {OFFSET (UnusedBit43x0) + N * sizeof (struct SDMA), 1, INT_V, 2, 9999} + + O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7) +#undef O +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SAPU *) + +static FreezeData SnapAPU [] = { + {OFFSET (Cycles), 4, INT_V, 1, 9999}, + {OFFSET (ShowROM), 1, INT_V, 1, 9999}, + {DUMMY (SAPU_Flags), 1, INT_V, 1, 2}, + {OFFSET (Flags), 4, INT_V, 2, 9999}, + {OFFSET (KeyedChannels), 1, INT_V, 1, 9999}, + {OFFSET (OutPorts), 4, uint8_ARRAY_V, 1, 9999}, + {OFFSET (DSP), 0x80, uint8_ARRAY_V, 1, 9999}, + {OFFSET (ExtraRAM), 64, uint8_ARRAY_V, 1, 9999}, + {OFFSET (Timer), 3, uint16_ARRAY_V, 1, 9999}, + {OFFSET (TimerTarget), 3, uint16_ARRAY_V, 1, 9999}, + {OFFSET (TimerEnabled), 3, uint8_ARRAY_V, 1, 9999}, + {OFFSET (TimerValueWritten), 3, uint8_ARRAY_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SAPURegisters *) + +static FreezeData SnapAPURegisters [] = { + {OFFSET (P), 1, INT_V, 1, 9999}, + {OFFSET (YA.W), 2, INT_V, 1, 9999}, + {OFFSET (X), 1, INT_V, 1, 9999}, + {OFFSET (S), 1, INT_V, 1, 9999}, + {OFFSET (PC), 2, INT_V, 1, 9999}, +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,SSoundData *) + +static FreezeData SnapSoundData [] = { + {OFFSET (master_volume_left), 2, INT_V, 1, 9999}, + {OFFSET (master_volume_right), 2, INT_V, 1, 9999}, + {OFFSET (echo_volume_left), 2, INT_V, 1, 9999}, + {OFFSET (echo_volume_right), 2, INT_V, 1, 9999}, + {OFFSET (echo_enable), 4, INT_V, 1, 9999}, + {OFFSET (echo_feedback), 4, INT_V, 1, 9999}, + {OFFSET (echo_ptr), 4, INT_V, 1, 9999}, + {OFFSET (echo_buffer_size), 4, INT_V, 1, 9999}, + {OFFSET (echo_write_enabled), 4, INT_V, 1, 9999}, + {OFFSET (echo_channel_enable), 4, INT_V, 1, 9999}, + {OFFSET (pitch_mod), 4, INT_V, 1, 9999}, + {OFFSET (dummy), 3, uint32_ARRAY_V, 1, 9999}, +#define O(N) \ + {OFFSET (channels [N].state), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].type), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].volume_left), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].volume_right), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].hertz), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].count), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].loop), 1, INT_V, 1, 9999}, \ + {OFFSET (channels [N].envx), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].left_vol_level), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].right_vol_level), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].envx_target), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].env_error), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].erate), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].direction), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].attack_rate), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].decay_rate), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].sustain_rate), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].release_rate), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].sustain_level), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].sample), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].decoded), 16, uint16_ARRAY_V, 1, 9999}, \ + {OFFSET (channels [N].previous16), 2, uint16_ARRAY_V, 1, 9999}, \ + {OFFSET (channels [N].sample_number), 2, INT_V, 1, 9999}, \ + {OFFSET (channels [N].last_block), 1, INT_V, 1, 9999}, \ + {OFFSET (channels [N].needs_decode), 1, INT_V, 1, 9999}, \ + {OFFSET (channels [N].block_pointer), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].sample_pointer), 4, INT_V, 1, 9999}, \ + {OFFSET (channels [N].mode), 4, INT_V, 1, 9999} + + O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7), +#undef O + {OFFSET (noise_rate), 4, INT_V, 2, 9999}, +#define O(N) \ + {OFFSET (channels [N].out_sample), 2, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xenvx), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xenvx_target), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xenv_count), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xenv_rate), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xattack_rate), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xdecay_rate), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xsustain_rate), 4, INT_V, 2, 9999}, \ + {OFFSET (channels [N].xsustain_level), 4, INT_V, 2, 9999} + + O(0), O(1), O(2), O(3), O(4), O(5), O(6), O(7) +#undef O +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SSA1Registers *) + +static FreezeData SnapSA1Registers [] = { + {OFFSET (PB), 1, INT_V, 1, 9999}, + {OFFSET (DB), 1, INT_V, 1, 9999}, + {OFFSET (P.W), 2, INT_V, 1, 9999}, + {OFFSET (A.W), 2, INT_V, 1, 9999}, + {OFFSET (D.W), 2, INT_V, 1, 9999}, + {OFFSET (S.W), 2, INT_V, 1, 9999}, + {OFFSET (X.W), 2, INT_V, 1, 9999}, + {OFFSET (Y.W), 2, INT_V, 1, 9999}, + {OFFSET (PCw), 2, INT_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SSA1 *) + +static FreezeData SnapSA1 [] = { + {OFFSET (Flags), 4, INT_V, 1, 9999}, + {OFFSET (NMIActive), 1, INT_V, 1, 9999}, + {OFFSET (IRQActive), 1, INT_V, 1, 9999}, + {OFFSET (WaitingForInterrupt), 1, INT_V, 1, 9999}, + {OFFSET (op1), 2, INT_V, 1, 9999}, + {OFFSET (op2), 2, INT_V, 1, 9999}, + {OFFSET (arithmetic_op), 4, INT_V, 1, 9999}, + {OFFSET (sum), 8, INT_V, 1, 9999}, + {OFFSET (overflow), 1, INT_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SPC7110EmuVars *) + +static FreezeData SnapSPC7110 [] = { + {OFFSET (reg4800), 1, INT_V, 1, 9999}, + {OFFSET (reg4801), 1, INT_V, 1, 9999}, + {OFFSET (reg4802), 1, INT_V, 1, 9999}, + {OFFSET (reg4803), 1, INT_V, 1, 9999}, + {OFFSET (reg4804), 1, INT_V, 1, 9999}, + {OFFSET (reg4805), 1, INT_V, 1, 9999}, + {OFFSET (reg4806), 1, INT_V, 1, 9999}, + {OFFSET (reg4807), 1, INT_V, 1, 9999}, + {OFFSET (reg4808), 1, INT_V, 1, 9999}, + {OFFSET (reg4809), 1, INT_V, 1, 9999}, + {OFFSET (reg480A), 1, INT_V, 1, 9999}, + {OFFSET (reg480B), 1, INT_V, 1, 9999}, + {OFFSET (reg480C), 1, INT_V, 1, 9999}, + {OFFSET (reg4811), 1, INT_V, 1, 9999}, + {OFFSET (reg4812), 1, INT_V, 1, 9999}, + {OFFSET (reg4813), 1, INT_V, 1, 9999}, + {OFFSET (reg4814), 1, INT_V, 1, 9999}, + {OFFSET (reg4815), 1, INT_V, 1, 9999}, + {OFFSET (reg4816), 1, INT_V, 1, 9999}, + {OFFSET (reg4817), 1, INT_V, 1, 9999}, + {OFFSET (reg4818), 1, INT_V, 1, 9999}, + {OFFSET (reg4820), 1, INT_V, 1, 9999}, + {OFFSET (reg4821), 1, INT_V, 1, 9999}, + {OFFSET (reg4822), 1, INT_V, 1, 9999}, + {OFFSET (reg4823), 1, INT_V, 1, 9999}, + {OFFSET (reg4824), 1, INT_V, 1, 9999}, + {OFFSET (reg4825), 1, INT_V, 1, 9999}, + {OFFSET (reg4826), 1, INT_V, 1, 9999}, + {OFFSET (reg4827), 1, INT_V, 1, 9999}, + {OFFSET (reg4828), 1, INT_V, 1, 9999}, + {OFFSET (reg4829), 1, INT_V, 1, 9999}, + {OFFSET (reg482A), 1, INT_V, 1, 9999}, + {OFFSET (reg482B), 1, INT_V, 1, 9999}, + {OFFSET (reg482C), 1, INT_V, 1, 9999}, + {OFFSET (reg482D), 1, INT_V, 1, 9999}, + {OFFSET (reg482E), 1, INT_V, 1, 9999}, + {OFFSET (reg482F), 1, INT_V, 1, 9999}, + {OFFSET (reg4830), 1, INT_V, 1, 9999}, + {OFFSET (reg4831), 1, INT_V, 1, 9999}, + {OFFSET (reg4832), 1, INT_V, 1, 9999}, + {OFFSET (reg4833), 1, INT_V, 1, 9999}, + {OFFSET (reg4834), 1, INT_V, 1, 9999}, + {OFFSET (reg4840), 1, INT_V, 1, 9999}, + {OFFSET (reg4841), 1, INT_V, 1, 9999}, + {OFFSET (reg4842), 1, INT_V, 1, 9999}, + {OFFSET (AlignBy), 1, INT_V, 1, 9999}, + {OFFSET (written), 1, INT_V, 1, 9999}, + {OFFSET (offset_add), 1, INT_V, 1, 9999}, + {OFFSET (DataRomOffset), 4, INT_V, 1, 9999}, + {OFFSET (DataRomSize), 4, INT_V, 1, 9999}, + {OFFSET (bank50Internal), 4, INT_V, 1, 9999}, + {OFFSET (bank50), 0x10000, uint8_ARRAY_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SPC7110RTC *) + +static FreezeData SnapS7RTC [] = { + {OFFSET (reg), 16, uint8_ARRAY_V, 1, 9999}, + {OFFSET (index), 2, INT_V, 1, 9999}, + {OFFSET (control), 1, INT_V, 1, 9999}, + {OFFSET (init), 1, INT_V, 1, 9999}, + {OFFSET (last_used), 4, INT_V, 1, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SControlSnapshot *) + +static FreezeData SnapControls [] = { + {OFFSET (ver), 1, INT_V, 2, 9999}, + {OFFSET (port1_read_idx), 2, uint8_ARRAY_V, 2, 9999}, + {OFFSET (dummy1), 4, uint8_ARRAY_V, 2, 9999}, + {OFFSET (port2_read_idx), 2, uint8_ARRAY_V, 2, 9999}, + {OFFSET (dummy2), 4, uint8_ARRAY_V, 2, 9999}, + {OFFSET (mouse_speed), 2, uint8_ARRAY_V, 2, 9999}, + {OFFSET (justifier_select), 1, INT_V, 2, 9999}, + {OFFSET (dummy3), 10, uint8_ARRAY_V, 2, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct STimings *) + +static FreezeData SnapTimings [] = { + {OFFSET (H_Max_Master), 4, INT_V, 2, 9999}, + {OFFSET (H_Max), 4, INT_V, 2, 9999}, + {OFFSET (V_Max_Master), 4, INT_V, 2, 9999}, + {OFFSET (V_Max), 4, INT_V, 2, 9999}, + {OFFSET (HBlankStart), 4, INT_V, 2, 9999}, + {OFFSET (HBlankEnd), 4, INT_V, 2, 9999}, + {OFFSET (HDMAInit), 4, INT_V, 2, 9999}, + {OFFSET (HDMAStart), 4, INT_V, 2, 9999}, + {OFFSET (NMITriggerPos), 4, INT_V, 2, 9999}, + {OFFSET (WRAMRefreshPos), 4, INT_V, 2, 9999}, + {OFFSET (RenderPos), 4, INT_V, 2, 9999}, + {OFFSET (InterlaceField), 1, INT_V, 2, 9999} +}; + +#undef OFFSET +#define OFFSET(f) Offset(f,struct SBSX *) + +static FreezeData SnapBSX [] = { + {OFFSET (dirty), 1, INT_V, 2, 9999}, + {OFFSET (dirty2), 1, INT_V, 2, 9999}, + {OFFSET (bootup), 1, INT_V, 2, 9999}, + {OFFSET (flash_enable), 1, INT_V, 2, 9999}, + {OFFSET (write_enable), 1, INT_V, 2, 9999}, + {OFFSET (read_enable), 1, INT_V, 2, 9999}, + {OFFSET (flash_command), 4, INT_V, 2, 9999}, + {OFFSET (old_write), 4, INT_V, 2, 9999}, + {OFFSET (new_write), 4, INT_V, 2, 9999}, + {OFFSET (out_index), 1, INT_V, 2, 9999}, + {OFFSET (output), 32, uint8_ARRAY_V, 2, 9999}, + {OFFSET (PPU), 32, uint8_ARRAY_V, 2, 9999}, + {OFFSET (MMC), 16, uint8_ARRAY_V, 2, 9999}, + {OFFSET (prevMMC), 16, uint8_ARRAY_V, 2, 9999}, + {OFFSET (test2192), 32, uint8_ARRAY_V, 2, 9999} +}; + +static char ROMFilename [_MAX_PATH]; +//static char SnapshotFilename [_MAX_PATH]; + +void FreezeStruct (STREAM stream, char *name, void *base, FreezeData *fields, + int num_fields); + +void FreezeBlock (STREAM stream, char *name, uint8 *block, int size); +#ifdef NGC +extern void NGCFreezeBlock (char *name, uint8 *block, int size); +extern int NGCUnFreezeBlock( char *name, uint8 *block, int size ); +extern int GetMem( char *buffer, int len ); +#endif + +int UnfreezeStruct (STREAM stream, char *name, void *base, FreezeData *fields, + int num_fields, int version); +int UnfreezeBlock (STREAM stream, char *name, uint8 *block, int size); + +int UnfreezeStructCopy (STREAM stream, char *name, uint8** block, FreezeData *fields, int num_fields, int version); + +void UnfreezeStructFromCopy (void *base, FreezeData *fields, int num_fields, uint8* block, int version); + +int UnfreezeBlockCopy (STREAM stream, char *name, uint8** block, int size); + +void S9xCloseSnapshotFile (FILE *stream) +{ + fclose(stream); +} + +bool8 Snapshot (const char *filename) +{ + return (S9xFreezeGame (filename)); +} + +bool8 S9xFreezeGame (const char *filename) +{ + STREAM stream = NULL; + +#ifndef NGC + if (S9xOpenSnapshotFile (filename, FALSE, &stream)) +#endif + { + S9xPrepareSoundForSnapshotSave (FALSE); + + S9xFreezeToStream (stream); + S9xCloseSnapshotFile (stream); + + S9xPrepareSoundForSnapshotSave (TRUE); + + S9xResetSaveTimer (TRUE); + +#ifndef NGC + if(S9xMovieActive()) + { + sprintf(String, "Movie snapshot %s", S9xBasename (filename)); + S9xMessage (S9X_INFO, S9X_FREEZE_FILE_INFO, String); + } + else + { + sprintf(String, "Saved %s", S9xBasename (filename)); + S9xMessage (S9X_INFO, S9X_FREEZE_FILE_INFO, String); + } +#endif + return (TRUE); + } + return (FALSE); +} + +bool8 S9xLoadSnapshot (const char *filename) +{ + return (S9xUnfreezeGame (filename)); +} + +bool8 S9xUnfreezeGame (const char *filename) +{ + char def [PATH_MAX]; + char drive [_MAX_DRIVE]; + char dir [_MAX_DIR]; + char ext [_MAX_EXT]; + + _splitpath (filename, drive, dir, def, ext); + S9xResetSaveTimer (!strcmp(ext, "oops") || !strcmp(ext, "oop")); + + ZeroMemory (&Obsolete, sizeof(Obsolete)); + +#ifndef NGC + /*** As the GC never had snapshots - there won't be + any original ones -;) ***/ + if (S9xLoadOrigSnapshot (filename)) + return (TRUE); + + + if (S9xUnfreezeZSNES (filename)) + return (TRUE); + +#endif + + STREAM snapshot = NULL; + +#ifndef NGC + if (S9xOpenSnapshotFile (filename, TRUE, &snapshot)) +#endif + { + int result; + if ((result = S9xUnfreezeFromStream (snapshot)) != SUCCESS) + { + switch (result) + { + case WRONG_FORMAT: + S9xMessage (S9X_ERROR, S9X_WRONG_FORMAT, + "File not in Snes9x freeze format"); + WaitPrompt("File not in Snes9x freeze format"); + break; + case WRONG_VERSION: + S9xMessage (S9X_ERROR, S9X_WRONG_VERSION, + "Incompatable Snes9x freeze file format version"); + WaitPrompt("Incompatable Snes9x freeze file format version"); + break; + case WRONG_MOVIE_SNAPSHOT: + S9xMessage (S9X_ERROR, S9X_WRONG_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_WRONG_MOVIE); + break; + case NOT_A_MOVIE_SNAPSHOT: + S9xMessage (S9X_ERROR, S9X_NOT_A_MOVIE_SNAPSHOT, MOVIE_ERR_SNAPSHOT_NOT_MOVIE); + break; + default: + case FILE_NOT_FOUND: + sprintf (String, "ROM image \"%s\" for freeze file not found", + ROMFilename); + S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String); + WaitPrompt(String); + break; + } + S9xCloseSnapshotFile (snapshot); + return (FALSE); + } + +#ifndef NGC + if(!S9xMovieActive()) + { + sprintf(String, "Loaded %s", S9xBasename (filename)); + S9xMessage (S9X_INFO, S9X_FREEZE_FILE_INFO, String); + } + + S9xCloseSnapshotFile (snapshot); + +#endif + return (TRUE); + } + return (FALSE); +} + +void S9xFreezeToStream (STREAM stream) +{ + char buffer [1024]; + int i; + + S9xSetSoundMute (TRUE); +#ifdef ZSNES_FX + if (Settings.SuperFX) + S9xSuperFXPreSaveState (); +#endif + + S9xUpdateRTC(); + S9xSRTCPreSaveState (); + + for (i = 0; i < 8; i++) + { + SoundData.channels [i].previous16 [0] = (int16) SoundData.channels [i].previous [0]; + SoundData.channels [i].previous16 [1] = (int16) SoundData.channels [i].previous [1]; + } + sprintf (buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION); + WRITE_STREAM (buffer, strlen (buffer), stream); + sprintf (buffer, "NAM:%06d:%s%c", (int)strlen (Memory.ROMFilename) + 1, + Memory.ROMFilename, 0); + WRITE_STREAM (buffer, strlen (buffer) + 1, stream); + FreezeStruct (stream, "CPU", &CPU, SnapCPU, COUNT (SnapCPU)); + FreezeStruct (stream, "REG", &Registers, SnapRegisters, COUNT (SnapRegisters)); + FreezeStruct (stream, "PPU", &PPU, SnapPPU, COUNT (SnapPPU)); + FreezeStruct (stream, "DMA", DMA, SnapDMA, COUNT (SnapDMA)); + + // RAM and VRAM + FreezeBlock (stream, "VRA", Memory.VRAM, 0x10000); + FreezeBlock (stream, "RAM", Memory.RAM, 0x20000); + FreezeBlock (stream, "SRA", ::SRAM, 0x20000); + FreezeBlock (stream, "FIL", Memory.FillRAM, 0x8000); + if (Settings.APUEnabled) + { + // APU + FreezeStruct (stream, "APU", &APU, SnapAPU, COUNT (SnapAPU)); + FreezeStruct (stream, "ARE", &APURegisters, SnapAPURegisters, + COUNT (SnapAPURegisters)); + FreezeBlock (stream, "ARA", IAPU.RAM, 0x10000); + FreezeStruct (stream, "SOU", &SoundData, SnapSoundData, + COUNT (SnapSoundData)); + } + + // Controls + struct SControlSnapshot ctl_snap; + S9xControlPreSave(&ctl_snap); + FreezeStruct (stream, "CTL", &ctl_snap, SnapControls, COUNT (SnapControls)); + + // Timings + FreezeStruct (stream, "TIM", &Timings, SnapTimings, COUNT (SnapTimings)); + + // Special chips + if (Settings.SA1) + { + S9xSA1PackStatus (); + FreezeStruct (stream, "SA1", &SA1, SnapSA1, COUNT (SnapSA1)); + FreezeStruct (stream, "SAR", &SA1Registers, SnapSA1Registers, + COUNT (SnapSA1Registers)); + } + + if (Settings.SPC7110) + { + FreezeStruct (stream, "SP7", &s7r, SnapSPC7110, COUNT (SnapSPC7110)); + } + + if (Settings.SPC7110RTC) + { + FreezeStruct (stream, "RTC", &rtc_f9, SnapS7RTC, COUNT (SnapS7RTC)); + } + + // BS + if (Settings.BS) + { + FreezeStruct (stream, "BSX", &BSX, SnapBSX, COUNT (SnapBSX)); + } + +#ifndef NGC + if (S9xMovieActive ()) + { + uint8* movie_freeze_buf; + uint32 movie_freeze_size; + + S9xMovieFreeze(&movie_freeze_buf, &movie_freeze_size); + if(movie_freeze_buf) + { + struct SnapshotMovieInfo mi; + mi.MovieInputDataSize = movie_freeze_size; + FreezeStruct (stream, "MOV", &mi, SnapMovie, COUNT (SnapMovie)); + FreezeBlock (stream, "MID", movie_freeze_buf, movie_freeze_size); + delete [] movie_freeze_buf; + } + } +#endif + + S9xSetSoundMute (FALSE); +#ifdef ZSNES_FX + if (Settings.SuperFX) + S9xSuperFXPostSaveState (); +#endif +} + +int S9xUnfreezeFromStream (STREAM stream) +{ + char buffer [_MAX_PATH + 1]; + char rom_filename [_MAX_PATH + 1]; + int result; + + int version; + int len = strlen (SNAPSHOT_MAGIC) + 1 + 4 + 1; + +#ifdef NGC + GetMem(buffer, len); +#else + if (READ_STREAM (buffer, len, stream) != len) + return (WRONG_FORMAT); +#endif + if (strncmp (buffer, SNAPSHOT_MAGIC, strlen (SNAPSHOT_MAGIC)) != 0) + return (WRONG_FORMAT); + if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > SNAPSHOT_VERSION) + return (WRONG_VERSION); + + if ((result = UnfreezeBlock (stream, "NAM", (uint8 *) rom_filename, _MAX_PATH)) != SUCCESS) + return (result); + +#ifndef NGC + if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 && + strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0) + { + S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME, + "Current loaded ROM image doesn't match that required by freeze-game file."); + } +#endif + +// ## begin load ## + uint8* local_cpu = NULL; + uint8* local_registers = NULL; + uint8* local_ppu = NULL; + uint8* local_dma = NULL; + uint8* local_vram = NULL; + uint8* local_ram = NULL; + uint8* local_sram = NULL; + uint8* local_fillram = NULL; + uint8* local_apu = NULL; + uint8* local_apu_registers = NULL; + uint8* local_apu_ram = NULL; + uint8* local_apu_sounddata = NULL; + uint8* local_sa1 = NULL; + uint8* local_sa1_registers = NULL; + uint8* local_spc = NULL; + uint8* local_spc_rtc = NULL; + uint8* local_movie_data = NULL; + uint8* local_control_data = NULL; + uint8* local_timing_data = NULL; + uint8* local_bsx_data = NULL; + + do + { + if ((result = UnfreezeStructCopy (stream, "CPU", &local_cpu, SnapCPU, COUNT (SnapCPU), version)) != SUCCESS) + break; + if ((result = UnfreezeStructCopy (stream, "REG", &local_registers, SnapRegisters, COUNT (SnapRegisters), version)) != SUCCESS) + break; + if ((result = UnfreezeStructCopy (stream, "PPU", &local_ppu, SnapPPU, COUNT (SnapPPU), version)) != SUCCESS) + break; + if ((result = UnfreezeStructCopy (stream, "DMA", &local_dma, SnapDMA, COUNT (SnapDMA), version)) != SUCCESS) + break; + if ((result = UnfreezeBlockCopy (stream, "VRA", &local_vram, 0x10000)) != SUCCESS) + break; + if ((result = UnfreezeBlockCopy (stream, "RAM", &local_ram, 0x20000)) != SUCCESS) + break; + if ((result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x20000)) != SUCCESS) + break; + if ((result = UnfreezeBlockCopy (stream, "FIL", &local_fillram, 0x8000)) != SUCCESS) + break; + if (UnfreezeStructCopy (stream, "APU", &local_apu, SnapAPU, COUNT (SnapAPU), version) == SUCCESS) + { + if ((result = UnfreezeStructCopy (stream, "ARE", &local_apu_registers, SnapAPURegisters, COUNT (SnapAPURegisters), version)) != SUCCESS) + break; + if ((result = UnfreezeBlockCopy (stream, "ARA", &local_apu_ram, 0x10000)) != SUCCESS) + break; + if ((result = UnfreezeStructCopy (stream, "SOU", &local_apu_sounddata, SnapSoundData, COUNT (SnapSoundData), version)) != SUCCESS) + break; + } + if ((result = UnfreezeStructCopy (stream, "CTL", &local_control_data, SnapControls, COUNT (SnapControls), version)) != SUCCESS && version>1) + break; + + if ((result = UnfreezeStructCopy (stream, "TIM", &local_timing_data, SnapTimings, COUNT (SnapTimings), version)) != SUCCESS && version>1) + break; + + if ((result = UnfreezeStructCopy (stream, "SA1", &local_sa1, SnapSA1, COUNT(SnapSA1), version)) == SUCCESS) + { + if ((result = UnfreezeStructCopy (stream, "SAR", &local_sa1_registers, SnapSA1Registers, COUNT (SnapSA1Registers), version)) != SUCCESS) + break; + } + + if ((result = UnfreezeStructCopy (stream, "SP7", &local_spc, SnapSPC7110, COUNT(SnapSPC7110), version)) != SUCCESS) + { + if(Settings.SPC7110) + break; + } + if ((result = UnfreezeStructCopy (stream, "RTC", &local_spc_rtc, SnapS7RTC, COUNT (SnapS7RTC), version)) != SUCCESS) + { + if(Settings.SPC7110RTC) + break; + } + + if ((result = UnfreezeStructCopy (stream, "BSX", &local_bsx_data, SnapBSX, COUNT (SnapBSX), version)) != SUCCESS && version > 1) + { + if (Settings.BS) + break; + } + +#ifndef NGC + if (S9xMovieActive ()) + { + SnapshotMovieInfo mi; + if ((result = UnfreezeStruct (stream, "MOV", &mi, SnapMovie, COUNT(SnapMovie), version)) != SUCCESS) + { + result = NOT_A_MOVIE_SNAPSHOT; + break; + } + + if ((result = UnfreezeBlockCopy (stream, "MID", &local_movie_data, mi.MovieInputDataSize)) != SUCCESS) + { + result = NOT_A_MOVIE_SNAPSHOT; + break; + } + + if (!S9xMovieUnfreeze(local_movie_data, mi.MovieInputDataSize)) + { + result = WRONG_MOVIE_SNAPSHOT; + break; + } + } +#endif + result=SUCCESS; + + } while(false); +// ## end load ## + + if (result == SUCCESS) + { + uint32 old_flags = CPU.Flags; + uint32 sa1_old_flags = SA1.Flags; + S9xReset (); + S9xSetSoundMute (TRUE); + + UnfreezeStructFromCopy (&CPU, SnapCPU, COUNT (SnapCPU), local_cpu, version); + UnfreezeStructFromCopy (&Registers, SnapRegisters, COUNT (SnapRegisters), local_registers, version); + UnfreezeStructFromCopy (&PPU, SnapPPU, COUNT (SnapPPU), local_ppu, version); + UnfreezeStructFromCopy (DMA, SnapDMA, COUNT (SnapDMA), local_dma, version); + memcpy (Memory.VRAM, local_vram, 0x10000); + memcpy (Memory.RAM, local_ram, 0x20000); + memcpy (::SRAM, local_sram, 0x20000); + memcpy (Memory.FillRAM, local_fillram, 0x8000); + if(local_apu) + { + UnfreezeStructFromCopy (&APU, SnapAPU, COUNT (SnapAPU), local_apu, version); + UnfreezeStructFromCopy (&APURegisters, SnapAPURegisters, COUNT (SnapAPURegisters), local_apu_registers, version); + memcpy (IAPU.RAM, local_apu_ram, 0x10000); + UnfreezeStructFromCopy (&SoundData, SnapSoundData, COUNT (SnapSoundData), local_apu_sounddata, version); + } + if(local_sa1) + { + UnfreezeStructFromCopy (&SA1, SnapSA1, COUNT (SnapSA1), local_sa1, version); + UnfreezeStructFromCopy (&SA1Registers, SnapSA1Registers, COUNT (SnapSA1Registers), local_sa1_registers, version); + } + if(local_spc) + { + UnfreezeStructFromCopy (&s7r, SnapSPC7110, COUNT (SnapSPC7110), local_spc, version); + } + if(local_spc_rtc) + { + UnfreezeStructFromCopy (&rtc_f9, SnapS7RTC, COUNT (SnapS7RTC), local_spc_rtc, version); + } + + struct SControlSnapshot ctl_snap; + if(local_control_data) { + UnfreezeStructFromCopy (&ctl_snap, SnapControls, COUNT (SnapControls), local_control_data, version); + } else { + // Must be an old snes9x savestate + ZeroMemory(&ctl_snap, sizeof(ctl_snap)); + ctl_snap.ver=0; + ctl_snap.port1_read_idx[0]=Obsolete.SPPU_Joypad1ButtonReadPos; + ctl_snap.port2_read_idx[0]=Obsolete.SPPU_Joypad2ButtonReadPos; + ctl_snap.port2_read_idx[1]=Obsolete.SPPU_Joypad3ButtonReadPos; + // Old snes9x used MouseSpeed[0] for both mice. Weird. + ctl_snap.mouse_speed[0]=ctl_snap.mouse_speed[1]=Obsolete.SPPU_MouseSpeed[0]; + ctl_snap.justifier_select=0; + } + S9xControlPostLoad(&ctl_snap); + + if (local_timing_data) + UnfreezeStructFromCopy (&Timings, SnapTimings, COUNT (SnapTimings), local_timing_data, version); + else // Must be an old snes9x savestate + { + S9xUpdateHVTimerPosition(); + } + + if (local_bsx_data) + UnfreezeStructFromCopy (&BSX, SnapBSX, COUNT (SnapBSX), local_bsx_data, version); + + Memory.FixROMSpeed (); + CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | + SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG); + + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = TRUE; + CPU.InDMA = CPU.InWRAM_DMA = FALSE; + S9xFixColourBrightness (); + IPPU.RenderThisFrame = FALSE; + + if (local_apu) + { + S9xSetSoundMute (FALSE); + IAPU.PC = IAPU.RAM + APURegisters.PC; + S9xAPUUnpackStatus (); + if (APUCheckDirectPage ()) + IAPU.DirectPage = IAPU.RAM + 0x100; + else + IAPU.DirectPage = IAPU.RAM; + Settings.APUEnabled = TRUE; + IAPU.APUExecuting = TRUE; + } + else + { + Settings.APUEnabled = FALSE; + IAPU.APUExecuting = FALSE; + S9xSetSoundMute (TRUE); + } + + if (local_sa1) + { + S9xFixSA1AfterSnapshotLoad (); + SA1.Flags |= sa1_old_flags & (TRACE_FLAG); + } + + if (local_spc_rtc) + { + S9xUpdateRTC(); + } + + if (local_bsx_data) + S9xFixBSXAfterSnapshotLoad(); + + S9xFixSoundAfterSnapshotLoad (version); + + uint8 hdma_byte = Memory.FillRAM[0x420c]; + S9xSetCPU(hdma_byte, 0x420c); + + if(version<2){ + for(int d=0; d<8; d++){ + DMA[d].UnknownByte = Memory.FillRAM[0x430b+(d<<4)]; + DMA[d].UnusedBit43x0 = (Memory.FillRAM[0x4300+(d<<4)]&0x20)?1:0; + } + PPU.M7HOFS = PPU.BG[0].HOffset; + PPU.M7VOFS = PPU.BG[0].VOffset; + if(!Memory.FillRAM[0x4213]){ + // most likely an old savestate + Memory.FillRAM[0x4213]=Memory.FillRAM[0x4201]; + if(!Memory.FillRAM[0x4213]) + Memory.FillRAM[0x4213]=Memory.FillRAM[0x4201]=0xFF; + } + if(local_apu) APU.Flags = Obsolete.SAPU_Flags; + + // FIXME: assuming the old savesate was made outside S9xMainLoop(). + // In this case, V=0 and HDMA was already initialized. + CPU.WhichEvent = HC_HDMA_INIT_EVENT; + CPU.NextEvent = Timings.HDMAInit; + S9xReschedule(); + } + + ICPU.ShiftedPB = Registers.PB << 16; + ICPU.ShiftedDB = Registers.DB << 16; + S9xSetPCBase (Registers.PBPC); + S9xUnpackStatus (); + S9xFixCycles (); +// S9xReschedule (); // <-- this causes desync when recording or playing movies + +#ifdef ZSNES_FX + if (Settings.SuperFX) + S9xSuperFXPostLoadState (); +#endif + + S9xSRTCPostLoadState (); + if (Settings.SDD1) + S9xSDD1PostLoadState (); + + IAPU.NextAPUTimerPos = CPU.Cycles << SNES_APUTIMER_ACCURACY; + IAPU.APUTimerCounter = 0; + } + + if (local_cpu) delete [] local_cpu; + if (local_registers) delete [] local_registers; + if (local_ppu) delete [] local_ppu; + if (local_dma) delete [] local_dma; + if (local_vram) delete [] local_vram; + if (local_ram) delete [] local_ram; + if (local_sram) delete [] local_sram; + if (local_fillram) delete [] local_fillram; + if (local_apu) delete [] local_apu; + if (local_apu_registers) delete [] local_apu_registers; + if (local_apu_ram) delete [] local_apu_ram; + if (local_apu_sounddata) delete [] local_apu_sounddata; + if (local_sa1) delete [] local_sa1; + if (local_sa1_registers) delete [] local_sa1_registers; + if (local_spc) delete [] local_spc; + if (local_spc_rtc) delete [] local_spc_rtc; + if (local_movie_data) delete [] local_movie_data; + if (local_control_data) delete [] local_control_data; + if (local_timing_data) delete [] local_timing_data; + if (local_bsx_data) delete [] local_bsx_data; + + return (result); +} + + +/*****************************************************************/ + +int FreezeSize (int size, int type) +{ + switch (type) + { + case uint16_ARRAY_V: + return (size * 2); + case uint32_ARRAY_V: + return (size * 4); + default: + return (size); + } +} + +void FreezeStruct (STREAM stream, char *name, void *base, FreezeData *fields, + int num_fields) +{ + // Work out the size of the required block + int len = 0; + int i; + int j; + + for (i = 0; i < num_fields; i++) + { + if (SNAPSHOT_VERSION=fields[i].deleted_in) continue; + switch (fields [i].type) + { + case INT_V: + switch (fields [i].size) + { + case 1: + *ptr++ = *((uint8 *) base + fields [i].offset); + break; + case 2: + word = *((uint16 *) ((uint8 *) base + fields [i].offset)); + *ptr++ = (uint8) (word >> 8); + *ptr++ = (uint8) word; + break; + case 4: + dword = *((uint32 *) ((uint8 *) base + fields [i].offset)); + *ptr++ = (uint8) (dword >> 24); + *ptr++ = (uint8) (dword >> 16); + *ptr++ = (uint8) (dword >> 8); + *ptr++ = (uint8) dword; + break; + case 8: + qword = *((int64 *) ((uint8 *) base + fields [i].offset)); + *ptr++ = (uint8) (qword >> 56); + *ptr++ = (uint8) (qword >> 48); + *ptr++ = (uint8) (qword >> 40); + *ptr++ = (uint8) (qword >> 32); + *ptr++ = (uint8) (qword >> 24); + *ptr++ = (uint8) (qword >> 16); + *ptr++ = (uint8) (qword >> 8); + *ptr++ = (uint8) qword; + break; + } + break; + case uint8_ARRAY_V: + memmove (ptr, (uint8 *) base + fields [i].offset, fields [i].size); + ptr += fields [i].size; + break; + case uint16_ARRAY_V: + for (j = 0; j < fields [i].size; j++) + { + word = *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)); + *ptr++ = (uint8) (word >> 8); + *ptr++ = (uint8) word; + } + break; + case uint32_ARRAY_V: + for (j = 0; j < fields [i].size; j++) + { + dword = *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)); + *ptr++ = (uint8) (dword >> 24); + *ptr++ = (uint8) (dword >> 16); + *ptr++ = (uint8) (dword >> 8); + *ptr++ = (uint8) dword; + } + break; + } + } + //fprintf(stderr, "%s: Wrote %d bytes\n", name, ptr-block); + +#ifndef NGC + FreezeBlock (stream, name, block, len); +#else + NGCFreezeBlock(name, block, len); +#endif + + delete[] block; +} + +void FreezeBlock (STREAM stream, char *name, uint8 *block, int size) +{ + char buffer [512]; + sprintf (buffer, "%s:%06d:", name, size); + WRITE_STREAM (buffer, strlen (buffer), stream); + WRITE_STREAM (block, size, stream); + +} + +#ifdef NGC +void NGCFreezeStruct() +{ + STREAM s = NULL; + + FreezeStruct (s,"CPU", &CPU, SnapCPU, COUNT (SnapCPU)); + FreezeStruct (s,"REG", &Registers, SnapRegisters, COUNT (SnapRegisters)); + FreezeStruct (s,"PPU", &PPU, SnapPPU, COUNT (SnapPPU)); + FreezeStruct (s,"DMA", DMA, SnapDMA, COUNT (SnapDMA)); + + // RAM and VRAM + NGCFreezeBlock ("VRA", Memory.VRAM, 0x10000); + NGCFreezeBlock ("RAM", Memory.RAM, 0x20000); + NGCFreezeBlock ("SRA", ::SRAM, 0x20000); + NGCFreezeBlock ("FIL", Memory.FillRAM, 0x8000); + + if (Settings.APUEnabled) + { + // APU + FreezeStruct (s,"APU", &APU, SnapAPU, COUNT (SnapAPU)); + FreezeStruct (s,"ARE", &APURegisters, SnapAPURegisters, + COUNT (SnapAPURegisters)); + NGCFreezeBlock ("ARA", IAPU.RAM, 0x10000); + FreezeStruct (s,"SOU", &SoundData, SnapSoundData, + COUNT (SnapSoundData)); + } + + // Controls + struct SControlSnapshot ctl_snap; + S9xControlPreSave(&ctl_snap); + FreezeStruct (s,"CTL", &ctl_snap, SnapControls, COUNT (SnapControls)); + + // Timings + FreezeStruct (s,"TIM", &Timings, SnapTimings, COUNT (SnapTimings)); + + // Special chips + if (Settings.SA1) + { + S9xSA1PackStatus (); + FreezeStruct (s,"SA1", &SA1, SnapSA1, COUNT (SnapSA1)); + FreezeStruct (s,"SAR", &SA1Registers, SnapSA1Registers, + COUNT (SnapSA1Registers)); + } + + if (Settings.SPC7110) + { + FreezeStruct (s,"SP7", &s7r, SnapSPC7110, COUNT (SnapSPC7110)); + } + + if (Settings.SPC7110RTC) + { + FreezeStruct (s,"RTC", &rtc_f9, SnapS7RTC, COUNT (SnapS7RTC)); + } + + // BS + if (Settings.BS) + { + FreezeStruct (s,"BSX", &BSX, SnapBSX, COUNT (SnapBSX)); + } +} + +#endif + +/*****************************************************************/ + +int UnfreezeBlock (STREAM stream, char *name, uint8 *block, int size) +{ +#ifndef NGC + char buffer [20], *e; + int len = 0; + int rem = 0; + long rewind = FIND_STREAM(stream); + + if (READ_STREAM (buffer, 11, stream) != 11 || + strncmp (buffer, name, 3) != 0 || buffer [3] != ':' || + buffer[10] != ':' || + (len = strtol (&buffer [4], &e, 10)) == 0 || e != buffer+10) + { + REVERT_STREAM(stream, rewind, 0); + return (WRONG_FORMAT); + } + + if (len > size) + { + rem = len - size; + len = size; + } + ZeroMemory (block, size); + if (READ_STREAM (block, len, stream) != len) + { + REVERT_STREAM(stream, rewind, 0); + return (WRONG_FORMAT); + } + if (rem) + { + char *junk = new char [rem]; + len = READ_STREAM (junk, rem, stream); + delete [] junk; + if (len != rem) + { + REVERT_STREAM(stream, rewind, 0); + return (WRONG_FORMAT); + } + } + + return (SUCCESS); +#else + return NGCUnFreezeBlock(name, block, size); +#endif + +} + +int UnfreezeBlockCopy (STREAM stream, char *name, uint8** block, int size) +{ + *block = new uint8 [size]; + int result; + + if ((result = UnfreezeBlock (stream, name, *block, size)) != SUCCESS) + { + delete [] (*block); + *block = NULL; + return (result); + } + + return (result); +} + +int UnfreezeStruct (STREAM stream, char *name, void *base, FreezeData *fields, + int num_fields, int version) +{ + uint8 *block = NULL; + int result; + + result = UnfreezeStructCopy (stream, name, &block, fields, num_fields, version); + if (result != SUCCESS) + { + if (block!=NULL) delete [] block; + return result; + } + UnfreezeStructFromCopy (base, fields, num_fields, block, version); + delete [] block; + return SUCCESS; +} + +int UnfreezeStructCopy (STREAM stream, char *name, uint8** block, FreezeData *fields, int num_fields, int version) +{ + // Work out the size of the required block + int len = 0; + int i; + + for (i = 0; i < num_fields; i++) + { + if (version>=fields [i].debuted_in && version=fields[i].deleted_in) continue; + base = (SNAPSHOT_VERSION>=fields[i].deleted_in)?((void *)&Obsolete):sbase; + switch (fields [i].type) + { + case INT_V: + switch (fields [i].size) + { + case 1: + if(fields[i].offset<0){ ptr++; break; } + *((uint8 *) base + fields [i].offset) = *ptr++; + break; + case 2: + if(fields[i].offset<0){ ptr+=2; break; } + word = *ptr++ << 8; + word |= *ptr++; + *((uint16 *) ((uint8 *) base + fields [i].offset)) = word; + break; + case 4: + if(fields[i].offset<0){ ptr+=4; break; } + dword = *ptr++ << 24; + dword |= *ptr++ << 16; + dword |= *ptr++ << 8; + dword |= *ptr++; + *((uint32 *) ((uint8 *) base + fields [i].offset)) = dword; + break; + case 8: + if(fields[i].offset<0){ ptr+=8; break; } + qword = (int64) *ptr++ << 56; + qword |= (int64) *ptr++ << 48; + qword |= (int64) *ptr++ << 40; + qword |= (int64) *ptr++ << 32; + qword |= (int64) *ptr++ << 24; + qword |= (int64) *ptr++ << 16; + qword |= (int64) *ptr++ << 8; + qword |= (int64) *ptr++; + *((int64 *) ((uint8 *) base + fields [i].offset)) = qword; + break; + } + break; + case uint8_ARRAY_V: + if(fields[i].offset>=0) + memmove ((uint8 *) base + fields [i].offset, ptr, fields [i].size); + ptr += fields [i].size; + break; + case uint16_ARRAY_V: + if(fields[i].offset<0){ ptr+=fields[i].size*2; break; } + for (j = 0; j < fields [i].size; j++) + { + word = *ptr++ << 8; + word |= *ptr++; + *((uint16 *) ((uint8 *) base + fields [i].offset + j * 2)) = word; + } + break; + case uint32_ARRAY_V: + if(fields[i].offset<0){ ptr+=fields[i].size*4; break; } + for (j = 0; j < fields [i].size; j++) + { + dword = *ptr++ << 24; + dword |= *ptr++ << 16; + dword |= *ptr++ << 8; + dword |= *ptr++; + *((uint32 *) ((uint8 *) base + fields [i].offset + j * 4)) = dword; + } + break; + } + } + //fprintf(stderr, "%p: Unfroze %d bytes\n", fields, ptr-block); +} + + +/*****************************************************************/ + +extern uint8 spc_dump_dsp[0x100]; + +bool8 S9xSPCDump (const char *filename) +{ + static uint8 header [] = { + 'S', 'N', 'E', 'S', '-', 'S', 'P', 'C', '7', '0', '0', ' ', + 'S', 'o', 'u', 'n', 'd', ' ', 'F', 'i', 'l', 'e', ' ', + 'D', 'a', 't', 'a', ' ', 'v', '0', '.', '3', '0', 26, 26, 26 + }; + static uint8 version = { + 0x1e + }; + + FILE *fs; + + S9xSetSoundMute (TRUE); + + if (!(fs = fopen (filename, "wb"))) + return (FALSE); + + // The SPC file format: + // 0000: header: 'SNES-SPC700 Sound File Data v0.30',26,26,26 + // 0036: version: $1e + // 0037: SPC700 PC: + // 0039: SPC700 A: + // 0040: SPC700 X: + // 0041: SPC700 Y: + // 0042: SPC700 P: + // 0043: SPC700 S: + // 0044: Reserved: 0, 0, 0, 0 + // 0048: Title of game: 32 bytes + // 0000: Song name: 32 bytes + // 0000: Name of dumper: 32 bytes + // 0000: Comments: 32 bytes + // 0000: Date of SPC dump: 4 bytes + // 0000: Fade out time in milliseconds: 4 bytes + // 0000: Fade out length in milliseconds: 2 bytes + // 0000: Default channel enables: 1 bytes + // 0000: Emulator used to dump .SPC files: 1 byte, 1 == ZSNES + // 0000: Reserved: 36 bytes + // 0256: SPC700 RAM: 64K + // ----: DSP Registers: 256 bytes + + if (fwrite (header, sizeof (header), 1, fs) != 1 || + fputc (version, fs) == EOF || + fseek (fs, 37, SEEK_SET) == EOF || + fputc (APURegisters.PC & 0xff, fs) == EOF || + fputc (APURegisters.PC >> 8, fs) == EOF || + fputc (APURegisters.YA.B.A, fs) == EOF || + fputc (APURegisters.X, fs) == EOF || + fputc (APURegisters.YA.B.Y, fs) == EOF || + fputc (APURegisters.P, fs) == EOF || + fputc (APURegisters.S, fs) == EOF || + fseek (fs, 256, SEEK_SET) == EOF || + fwrite (IAPU.RAM, 0x10000, 1, fs) != 1 || + fwrite (spc_dump_dsp, 1, 256, fs) != 256 || + fwrite (APU.ExtraRAM, 64, 1, fs) != 1 || + fclose (fs) < 0) + { + S9xSetSoundMute (FALSE); + return (FALSE); + } + S9xSetSoundMute (FALSE); + return (TRUE); +} + +bool8 S9xUnfreezeZSNES (const char *filename) +{ + FILE *fs; + uint8 t [4000]; + + if (!(fs = fopen (filename, "rb"))) + return (FALSE); + + if (fread (t, 64, 1, fs) == 1 && + strncmp ((char *) t, "ZSNES Save State File V0.6", 26) == 0) + { + S9xReset (); + S9xSetSoundMute (TRUE); + + // 28 Curr cycle + CPU.V_Counter = READ_WORD (&t [29]); + // 33 instrset + Settings.APUEnabled = t [36]; + + // 34 bcycpl cycles per scanline + // 35 cycphb cyclers per hblank + + Registers.A.W = READ_WORD (&t [41]); + Registers.DB = t [43]; + Registers.PB = t [44]; + Registers.S.W = READ_WORD (&t [45]); + Registers.D.W = READ_WORD (&t [47]); + Registers.X.W = READ_WORD (&t [49]); + Registers.Y.W = READ_WORD (&t [51]); + Registers.P.W = READ_WORD (&t [53]); + Registers.PCw = READ_WORD (&t [55]); + + fread (t, 1, 8, fs); + fread (t, 1, 3019, fs); + S9xSetCPU (t [2], 0x4200); + Memory.FillRAM [0x4210] = t [3]; + PPU.IRQVBeamPos = READ_WORD (&t [4]); + PPU.IRQHBeamPos = READ_WORD (&t [2527]); + PPU.Brightness = t [6]; + PPU.ForcedBlanking = t [8] >> 7; + + int i; + for (i = 0; i < 544; i++) + S9xSetPPU (t [0464 + i], 0x2104); + + PPU.OBJNameBase = READ_WORD (&t [9]); + PPU.OBJNameSelect = READ_WORD (&t [13]) - PPU.OBJNameBase; + switch (t [18]) + { + case 4: + if (t [17] == 1) + PPU.OBJSizeSelect = 0; + else + PPU.OBJSizeSelect = 6; + break; + case 16: + if (t [17] == 1) + PPU.OBJSizeSelect = 1; + else + PPU.OBJSizeSelect = 3; + break; + default: + case 64: + if (t [17] == 1) + PPU.OBJSizeSelect = 2; + else + if (t [17] == 4) + PPU.OBJSizeSelect = 4; + else + PPU.OBJSizeSelect = 5; + break; + } + PPU.OAMAddr = READ_WORD (&t [25]); + PPU.SavedOAMAddr = READ_WORD (&t [27]); + PPU.FirstSprite = t [29]; + PPU.BGMode = t [30]; + PPU.BG3Priority = t [31]; + PPU.BG[0].BGSize = (t [32] >> 0) & 1; + PPU.BG[1].BGSize = (t [32] >> 1) & 1; + PPU.BG[2].BGSize = (t [32] >> 2) & 1; + PPU.BG[3].BGSize = (t [32] >> 3) & 1; + PPU.Mosaic = t [33] + 1; + PPU.BGMosaic [0] = (t [34] & 1) != 0; + PPU.BGMosaic [1] = (t [34] & 2) != 0; + PPU.BGMosaic [2] = (t [34] & 4) != 0; + PPU.BGMosaic [3] = (t [34] & 8) != 0; + PPU.BG [0].SCBase = READ_WORD (&t [35]) >> 1; + PPU.BG [1].SCBase = READ_WORD (&t [37]) >> 1; + PPU.BG [2].SCBase = READ_WORD (&t [39]) >> 1; + PPU.BG [3].SCBase = READ_WORD (&t [41]) >> 1; + PPU.BG [0].SCSize = t [67]; + PPU.BG [1].SCSize = t [68]; + PPU.BG [2].SCSize = t [69]; + PPU.BG [3].SCSize = t [70]; + PPU.BG[0].NameBase = READ_WORD (&t [71]) >> 1; + PPU.BG[1].NameBase = READ_WORD (&t [73]) >> 1; + PPU.BG[2].NameBase = READ_WORD (&t [75]) >> 1; + PPU.BG[3].NameBase = READ_WORD (&t [77]) >> 1; + PPU.BG[0].HOffset = READ_WORD (&t [79]); + PPU.BG[1].HOffset = READ_WORD (&t [81]); + PPU.BG[2].HOffset = READ_WORD (&t [83]); + PPU.BG[3].HOffset = READ_WORD (&t [85]); + PPU.BG[0].VOffset = READ_WORD (&t [89]); + PPU.BG[1].VOffset = READ_WORD (&t [91]); + PPU.BG[2].VOffset = READ_WORD (&t [93]); + PPU.BG[3].VOffset = READ_WORD (&t [95]); + PPU.VMA.Increment = READ_WORD (&t [97]) >> 1; + PPU.VMA.High = t [99]; +#ifndef CORRECT_VRAM_READS + IPPU.FirstVRAMRead = t [100]; +#endif + S9xSetPPU (t [2512], 0x2115); + PPU.VMA.Address = READ_DWORD (&t [101]); + for (i = 0; i < 512; i++) + S9xSetPPU (t [1488 + i], 0x2122); + + PPU.CGADD = (uint8) READ_WORD (&t [105]); + Memory.FillRAM [0x212c] = t [108]; + Memory.FillRAM [0x212d] = t [109]; + PPU.ScreenHeight = READ_WORD (&t [111]); + Memory.FillRAM [0x2133] = t [2526]; + Memory.FillRAM [0x4202] = t [113]; + Memory.FillRAM [0x4204] = t [114]; + Memory.FillRAM [0x4205] = t [115]; + Memory.FillRAM [0x4214] = t [116]; + Memory.FillRAM [0x4215] = t [117]; + Memory.FillRAM [0x4216] = t [118]; + Memory.FillRAM [0x4217] = t [119]; + PPU.VBeamPosLatched = READ_WORD (&t [122]); + PPU.HBeamPosLatched = READ_WORD (&t [120]); + PPU.Window1Left = t [127]; + PPU.Window1Right = t [128]; + PPU.Window2Left = t [129]; + PPU.Window2Right = t [130]; + S9xSetPPU (t [131] | (t [132] << 4), 0x2123); + S9xSetPPU (t [133] | (t [134] << 4), 0x2124); + S9xSetPPU (t [135] | (t [136] << 4), 0x2125); + S9xSetPPU (t [137], 0x212a); + S9xSetPPU (t [138], 0x212b); + S9xSetPPU (t [139], 0x212e); + S9xSetPPU (t [140], 0x212f); + S9xSetPPU (t [141], 0x211a); + PPU.MatrixA = READ_WORD (&t [142]); + PPU.MatrixB = READ_WORD (&t [144]); + PPU.MatrixC = READ_WORD (&t [146]); + PPU.MatrixD = READ_WORD (&t [148]); + PPU.CentreX = READ_WORD (&t [150]); + PPU.CentreY = READ_WORD (&t [152]); + PPU.M7HOFS = PPU.BG[0].HOffset; + PPU.M7VOFS = PPU.BG[0].VOffset; + // JoyAPos t[154] + // JoyBPos t[155] + Memory.FillRAM [0x2134] = t [156]; // Matrix mult + Memory.FillRAM [0x2135] = t [157]; // Matrix mult + Memory.FillRAM [0x2136] = t [158]; // Matrix mult + PPU.WRAM = READ_DWORD (&t [161]); + + for (i = 0; i < 128; i++) + S9xSetCPU (t [165 + i], 0x4300 + i); + + if (t [294]) + CPU.IRQActive |= PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE; + + S9xSetCPU (t [296], 0x420c); + // hdmadata t[297] + 8 * 19 + PPU.FixedColourRed = t [450]; + PPU.FixedColourGreen = t [451]; + PPU.FixedColourBlue = t [452]; + S9xSetPPU (t [454], 0x2130); + S9xSetPPU (t [455], 0x2131); + // vraminctype ... + + fread (Memory.RAM, 1, 128 * 1024, fs); + fread (Memory.VRAM, 1, 64 * 1024, fs); + + if (Settings.APUEnabled) + { + // SNES SPC700 RAM (64K) + fread (IAPU.RAM, 1, 64 * 1024, fs); + + // Junk 16 bytes + fread (t, 1, 16, fs); + + // SNES SPC700 state and internal ZSNES SPC700 emulation state + fread (t, 1, 304, fs); + + APURegisters.PC = READ_DWORD (&t [0]); + APURegisters.YA.B.A = t [4]; + APURegisters.X = t [8]; + APURegisters.YA.B.Y = t [12]; + APURegisters.P = t [16]; + APURegisters.S = t [24]; + + APU.Cycles = READ_DWORD (&t [32]); + APU.ShowROM = (IAPU.RAM [0xf1] & 0x80) != 0; + APU.OutPorts [0] = t [36]; + APU.OutPorts [1] = t [37]; + APU.OutPorts [2] = t [38]; + APU.OutPorts [3] = t [39]; + + APU.TimerEnabled [0] = (t [40] & 1) != 0; + APU.TimerEnabled [1] = (t [40] & 2) != 0; + APU.TimerEnabled [2] = (t [40] & 4) != 0; + S9xSetAPUTimer (0xfa, t [41]); + S9xSetAPUTimer (0xfb, t [42]); + S9xSetAPUTimer (0xfc, t [43]); + APU.Timer [0] = t [44]; + APU.Timer [1] = t [45]; + APU.Timer [2] = t [46]; + + memmove (APU.ExtraRAM, &t [48], 64); + + // Internal ZSNES sound DSP state + fread (t, 1, 1068, fs); + + // SNES sound DSP register values + fread (t, 1, 256, fs); + + uint8 saved = IAPU.RAM [0xf2]; + + for (i = 0; i < 128; i++) + { + switch (i) + { + case APU_KON: + case APU_KOFF: + break; + case APU_FLG: + t [i] &= ~APU_SOFT_RESET; + default: + IAPU.RAM [0xf2] = i; + S9xSetAPUDSP (t [i]); + break; + } + } + IAPU.RAM [0xf2] = APU_KON; + S9xSetAPUDSP (t [APU_KON]); + IAPU.RAM [0xf2] = saved; + + S9xSetSoundMute (FALSE); + IAPU.PC = IAPU.RAM + APURegisters.PC; + S9xAPUUnpackStatus (); + if (APUCheckDirectPage ()) + IAPU.DirectPage = IAPU.RAM + 0x100; + else + IAPU.DirectPage = IAPU.RAM; + Settings.APUEnabled = TRUE; + IAPU.APUExecuting = TRUE; + } + else + { + Settings.APUEnabled = FALSE; + IAPU.APUExecuting = FALSE; + S9xSetSoundMute (TRUE); + } + + if (Settings.SuperFX) + { + fread (::SRAM, 1, 64 * 1024, fs); + fseek (fs, 64 * 1024, SEEK_CUR); + fread (Memory.FillRAM + 0x7000, 1, 692, fs); + } + if (Settings.SA1) + { + fread (t, 1, 2741, fs); + S9xSetSA1 (t [4], 0x2200); // Control + S9xSetSA1 (t [12], 0x2203); // ResetV low + S9xSetSA1 (t [13], 0x2204); // ResetV hi + S9xSetSA1 (t [14], 0x2205); // NMI low + S9xSetSA1 (t [15], 0x2206); // NMI hi + S9xSetSA1 (t [16], 0x2207); // IRQ low + S9xSetSA1 (t [17], 0x2208); // IRQ hi + S9xSetSA1 (((READ_DWORD (&t [28]) - (4096*1024-0x6000))) >> 13, 0x2224); + S9xSetSA1 (t [36], 0x2201); + S9xSetSA1 (t [41], 0x2209); + + SA1Registers.A.W = READ_DWORD (&t [592]); + SA1Registers.X.W = READ_DWORD (&t [596]); + SA1Registers.Y.W = READ_DWORD (&t [600]); + SA1Registers.D.W = READ_DWORD (&t [604]); + SA1Registers.DB = t [608]; + SA1Registers.PB = t [612]; + SA1Registers.S.W = READ_DWORD (&t [616]); + SA1Registers.PCw = READ_DWORD (&t [636]); + SA1Registers.P.W = t [620] | (t [624] << 8); + + memmove (&Memory.FillRAM [0x3000], t + 692, 2 * 1024); + + fread (::SRAM, 1, 64 * 1024, fs); + fseek (fs, 64 * 1024, SEEK_CUR); + S9xFixSA1AfterSnapshotLoad (); + } + if(Settings.SPC7110) + { + uint32 temp; + fread(&s7r.bank50, 1,0x10000, fs); + + //NEWSYM SPCMultA, dd 0 4820-23 + fread(&temp, 1, 4, fs); + + s7r.reg4820=temp&(0x0FF); + s7r.reg4821=(temp>>8)&(0x0FF); + s7r.reg4822=(temp>>16)&(0x0FF); + s7r.reg4823=(temp>>24)&(0x0FF); + + //NEWSYM SPCMultB, dd 0 4824-5 + fread(&temp, 1,4,fs); + s7r.reg4824=temp&(0x0FF); + s7r.reg4825=(temp>>8)&(0x0FF); + + + //NEWSYM SPCDivEnd, dd 0 4826-7 + fread(&temp, 1,4,fs); + s7r.reg4826=temp&(0x0FF); + s7r.reg4827=(temp>>8)&(0x0FF); + + //NEWSYM SPCMulRes, dd 0 4828-B + fread(&temp, 1, 4, fs); + + s7r.reg4828=temp&(0x0FF); + s7r.reg4829=(temp>>8)&(0x0FF); + s7r.reg482A=(temp>>16)&(0x0FF); + s7r.reg482B=(temp>>24)&(0x0FF); + + //NEWSYM SPCDivRes, dd 0 482C-D + fread(&temp, 1,4,fs); + s7r.reg482C=temp&(0x0FF); + s7r.reg482D=(temp>>8)&(0x0FF); + + //NEWSYM SPC7110BankA, dd 020100h 4831-3 + fread(&temp, 1, 4, fs); + + s7r.reg4831=temp&(0x0FF); + s7r.reg4832=(temp>>8)&(0x0FF); + s7r.reg4833=(temp>>16)&(0x0FF); + + //NEWSYM SPC7110RTCStat, dd 0 4840,init,command, index + fread(&temp, 1, 4, fs); + + s7r.reg4840=temp&(0x0FF); + +//NEWSYM SPC7110RTC, db 00,00,00,00,00,00,01,00,01,00,00,00,00,00,0Fh,00 +fread(&temp, 1, 4, fs); +if(Settings.SPC7110RTC) +{ + rtc_f9.reg[0]=temp&(0x0FF); + rtc_f9.reg[1]=(temp>>8)&(0x0FF); + rtc_f9.reg[2]=(temp>>16)&(0x0FF); + rtc_f9.reg[3]=(temp>>24)&(0x0FF); +} +fread(&temp, 1, 4, fs); +if(Settings.SPC7110RTC) +{ + rtc_f9.reg[4]=temp&(0x0FF); + rtc_f9.reg[5]=(temp>>8)&(0x0FF); + rtc_f9.reg[6]=(temp>>16)&(0x0FF); + rtc_f9.reg[7]=(temp>>24)&(0x0FF); +} +fread(&temp, 1, 4, fs); +if(Settings.SPC7110RTC) +{ + rtc_f9.reg[8]=temp&(0x0FF); + rtc_f9.reg[9]=(temp>>8)&(0x0FF); + rtc_f9.reg[10]=(temp>>16)&(0x0FF); + rtc_f9.reg[11]=(temp>>24)&(0x0FF); +} +fread(&temp, 1, 4, fs); +if(Settings.SPC7110RTC) +{ + rtc_f9.reg[12]=temp&(0x0FF); + rtc_f9.reg[13]=(temp>>8)&(0x0FF); + rtc_f9.reg[14]=(temp>>16)&(0x0FF); + rtc_f9.reg[15]=(temp>>24)&(0x0FF); +} +//NEWSYM SPC7110RTCB, db 00,00,00,00,00,00,01,00,01,00,00,00,00,01,0Fh,06 +fread(&temp, 1, 4, fs); +fread(&temp, 1, 4, fs); +fread(&temp, 1, 4, fs); +fread(&temp, 1, 4, fs); + +//NEWSYM SPCROMPtr, dd 0 4811-4813 + fread(&temp, 1, 4, fs); + + s7r.reg4811=temp&(0x0FF); + s7r.reg4812=(temp>>8)&(0x0FF); + s7r.reg4813=(temp>>16)&(0x0FF); +//NEWSYM SPCROMtoI, dd SPCROMPtr + fread(&temp, 1, 4, fs); +//NEWSYM SPCROMAdj, dd 0 4814-5 + fread(&temp, 1, 4, fs); + s7r.reg4814=temp&(0x0FF); + s7r.reg4815=(temp>>8)&(0x0FF); +//NEWSYM SPCROMInc, dd 0 4816-7 + fread(&temp, 1, 4, fs); + s7r.reg4816=temp&(0x0FF); + s7r.reg4817=(temp>>8)&(0x0FF); +//NEWSYM SPCROMCom, dd 0 4818 +fread(&temp, 1, 4, fs); + + s7r.reg4818=temp&(0x0FF); +//NEWSYM SPCCompPtr, dd 0 4801-4804 (+b50i) if"manual" + fread(&temp, 1, 4, fs); + + //do table check + + s7r.reg4801=temp&(0x0FF); + s7r.reg4802=(temp>>8)&(0x0FF); + s7r.reg4803=(temp>>16)&(0x0FF); + s7r.reg4804=(temp>>24)&(0x0FF); +///NEWSYM SPCDecmPtr, dd 0 4805-6 +b50i + fread(&temp, 1, 4, fs); + s7r.reg4805=temp&(0x0FF); + s7r.reg4806=(temp>>8)&(0x0FF); +//NEWSYM SPCCompCounter, dd 0 4809-A + fread(&temp, 1, 4, fs); + s7r.reg4809=temp&(0x0FF); + s7r.reg480A=(temp>>8)&(0x0FF); +//NEWSYM SPCCompCommand, dd 0 480B +fread(&temp, 1, 4, fs); + + s7r.reg480B=temp&(0x0FF); +//NEWSYM SPCCheckFix, dd 0 written(if 1, then set writtne to max value!) +fread(&temp, 1, 4, fs); +(temp&(0x0FF))?s7r.written=0x1F:s7r.written=0x00; +//NEWSYM SPCSignedVal, dd 0 482E +fread(&temp, 1, 4, fs); + + s7r.reg482E=temp&(0x0FF); + + } + fclose (fs); + + Memory.FixROMSpeed (); + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = TRUE; + CPU.InDMA = CPU.InWRAM_DMA = FALSE; + S9xFixColourBrightness (); + IPPU.RenderThisFrame = FALSE; + + S9xFixSoundAfterSnapshotLoad (1); + ICPU.ShiftedPB = Registers.PB << 16; + ICPU.ShiftedDB = Registers.DB << 16; + S9xSetPCBase (Registers.PBPC); + S9xUnpackStatus (); + S9xFixCycles (); + S9xReschedule (); +#ifdef ZSNES_FX + if (Settings.SuperFX) + S9xSuperFXPostLoadState (); +#endif + return (TRUE); + } + fclose (fs); + return (FALSE); +} + diff --git a/source/snes9x/snapshot.h b/source/snes9x/snapshot.h new file mode 100644 index 0000000..b6eb433 --- /dev/null +++ b/source/snes9x/snapshot.h @@ -0,0 +1,172 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _SNAPSHOT_H_ +#define _SNAPSHOT_H_ + +#include +#include "snes9x.h" + +#define SNAPSHOT_MAGIC "#!snes9x" +#define SNAPSHOT_VERSION 2 + +#define SUCCESS 1 +#define WRONG_FORMAT (-1) +#define WRONG_VERSION (-2) +#define FILE_NOT_FOUND (-3) +#define WRONG_MOVIE_SNAPSHOT (-4) +#define NOT_A_MOVIE_SNAPSHOT (-5) + +START_EXTERN_C +void S9xResetSaveTimer(bool8 dontsave); +bool8 S9xFreezeGame (const char *filename); +bool8 S9xUnfreezeGame (const char *filename); +bool8 Snapshot (const char *filename); +bool8 S9xLoadSnapshot (const char *filename); +bool8 S9xSPCDump (const char *filename); +void S9xFreezeToStream (STREAM); +int S9xUnfreezeFromStream (STREAM); +END_EXTERN_C + +#endif + diff --git a/source/snes9x/snes9x.cpp b/source/snes9x/snes9x.cpp new file mode 100644 index 0000000..f8f0155 --- /dev/null +++ b/source/snes9x/snes9x.cpp @@ -0,0 +1,1178 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#include "snes9x.h" +#include "memmap.h" +#include "display.h" + +#ifndef NGC +#include "cheats.h" +#endif + +#include "controls.h" + +#ifndef NGC +#include "netplay.h" +#endif + +#ifdef DEBUGGER +extern FILE *trace; +#endif + +static char *rom_filename=NULL; + +void S9xUsage () +{ + S9xMessage (S9X_INFO, S9X_USAGE, "snes9x: S9xUsage: snes9x \n"); + S9xMessage (S9X_INFO, S9X_USAGE, "Where can be:"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + + /* SOUND OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-sound or -so Enable digital sound output"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nosound or -ns Disable digital sound output"); + S9xMessage(S9X_INFO, S9X_USAGE, "-soundskip or -sk <0-3> Sound CPU skip-waiting method"); +#ifdef SHOW_OBSOLETE_OPTIONS + S9xMessage(S9X_INFO, S9X_USAGE, "-ratio or -ra Ratio of 65c816 to SPC700 instructions (ignored)"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, "-soundquality, -sq, or -r Set sound playback quality"); +#ifdef __sgi +/* BS: changed the sample rate values to match the IRIX options */ + S9xMessage (S9X_INFO, S9X_USAGE, "\ + 0 - off, 1 - 8192, 2 - 11025, 3 - 16000,\n\ + 4 - 22050 (default), 5 - 32000, 6 - 44100,\n\ + 7 - 48000"); +#else + S9xMessage (S9X_INFO, S9X_USAGE, "\ + 0 - off, 1 - 8192, 2 - 11025, 3 - 16500,\n\ + 4 - 22050 (default), 5 - 29300, 6 - 36600,\n\ + 7 - 44000"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, "-altsampledecode or -alt Use alternate sample decoder"); + S9xMessage(S9X_INFO, S9X_USAGE, "-stereo or -st Enable stereo sound output (implies -sound)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-mono Enable monaural sound output (implies -sound)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-soundsync or -sy Enable sound sync to CPU at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-soundsync2 or -sy2 Alternate method to sync sound"); +#ifdef USE_THREADS + S9xMessage(S9X_INFO, S9X_USAGE, "-threadsound or -ts Use a separate thread to output sound"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, "-interpolatedsound or -is <0-3> Select sound interpolation method\n\ + 0=none, 1=linear, 2=cubic, 3=gaussian"); + S9xMessage(S9X_INFO, S9X_USAGE, "-echo or -e Enable DSP echo effects at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-noecho or -ne Disable DSP echo effects at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-envx or -ex Enable volume envelope height reading"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nosamplecaching, -nsc, or -nc Disable sample caching"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nomastervolume or -nmv Disable master volume setting"); + S9xMessage(S9X_INFO, S9X_USAGE, "-fix 'Fix' sound frequencies"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + + /* FEATURE OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-conf Use specified conf file (after standard files)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nostdconf Do not load the standard config files"); + S9xMessage(S9X_INFO, S9X_USAGE, "-hdma or -ha Enable HDMA emulation at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nohdma or -nh Disable HDMA emulation at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-transparency or -tr Enable transparency effects"); + S9xMessage(S9X_INFO, S9X_USAGE, "-notransparency or -nt Disable transparency effects at start"); + S9xMessage(S9X_INFO, S9X_USAGE, "-windows Enable graphic window effects"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nowindows or -nw Disable graphic window effects"); +#ifdef SHOW_OBSOLETE_OPTIONS + S9xMessage(S9X_INFO, S9X_USAGE, "-layering or -L Enable BG Layering Hack at startup (ignored)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nolayering or -nl Disable BG Layering Hack at startup (ignored)"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, "-im7 Enable Mode 7 interpolation effects"); + S9xMessage(S9X_INFO, S9X_USAGE, "-displayframerate or -dfr Display the frame rate counter"); + S9xMessage(S9X_INFO, S9X_USAGE, "-aidoshm Run in AIDO mode, with specified SHM ID"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + + /* DISPLAY OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-hires or -hi Enable support for hi-res and interlace modes"); +#ifdef SHOW_OBSOLETE_OPTIONS + S9xMessage(S9X_INFO, S9X_USAGE, "-16 or -sixteen Enable 16-bit rendering"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, "-frameskip or -f Screen update frame skip rate"); + S9xMessage(S9X_INFO, S9X_USAGE, "-frametime or -ft Milliseconds per frame for frameskip auto-adjust"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + + /* ROM OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-hirom, -hr, or -fh Force Hi-ROM memory map"); + S9xMessage(S9X_INFO, S9X_USAGE, "-lorom, -lr, or -fl Force Lo-ROM memory map"); + S9xMessage(S9X_INFO, S9X_USAGE, "-bs Use BS Satellite System ROM mapping"); + S9xMessage(S9X_INFO, S9X_USAGE, "-bsxbootup Boot up BS games from BS-X"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nointerleave or -ni ROM image is not in interleaved format"); + S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved or -i ROM image is in interleaved format"); + S9xMessage(S9X_INFO, S9X_USAGE, "-interleaved2 or -i2 ROM image is in interleaved 2 format"); + S9xMessage(S9X_INFO, S9X_USAGE, "-interleavedgd24 or -gd24 ROM image is in interleaved gd24 format"); + S9xMessage(S9X_INFO, S9X_USAGE, "-header, -he, or -hd Force the detection of a ROM image header"); + S9xMessage(S9X_INFO, S9X_USAGE, "-noheader or -nhd Force the detection of no ROM image header"); + S9xMessage(S9X_INFO, S9X_USAGE, "-ntsc or -n Force NTSC timing (60 frames/sec)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-pal or -p Force PAL timing (50 frames/sec)"); + S9xMessage(S9X_INFO, S9X_USAGE, "-superfx or -sfx Force detection of the SuperFX chip"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nosuperfx or -nosfx Force detection of no SuperFX chip"); + S9xMessage(S9X_INFO, S9X_USAGE, "-dsp1 Force detection of the DSP-1 chip"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nodsp1 Force detection of no DSP-1 chip"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + +#ifdef DEBUGGER + /* OPTIONS FOR DEBUGGING USE */ + S9xMessage(S9X_INFO, S9X_USAGE, "-cycles or -h <1-199> Percentage of CPU cycles to execute per scanline"); + S9xMessage(S9X_INFO, S9X_USAGE, "-speedhacks or -sh Enable speed hacks"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nospeedhacks or -nsh Disable speed hacks"); + S9xMessage(S9X_INFO, S9X_USAGE, "-debug or -d Set the Debugger flag at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-trace or -t Begin CPU instruction tracing at startup"); + S9xMessage(S9X_INFO, S9X_USAGE, "-noirq Disable processor IRQ (for debugging)"); + S9xMessage(S9X_INFO, S9X_USAGE, "--selftest Run self tests and exit"); +#ifdef DEBUG_MAXCOUNT + S9xMessage(S9X_INFO, S9X_USAGE, "-maxcount Only run through N cycles of the main loop"); +#endif + S9xMessage(S9X_INFO, S9X_USAGE, ""); +#endif + + /* PATCH/CHEAT OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-nopatch Do not apply any available IPS patches"); + S9xMessage(S9X_INFO, S9X_USAGE, "-cheat Apply saved cheats"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nocheat Do not apply saved cheats"); + S9xMessage(S9X_INFO, S9X_USAGE, "-gamegenie or -gg Supply a Game Genie code"); + S9xMessage(S9X_INFO, S9X_USAGE, "-actionreplay or -ar Supply a Pro-Action Reply code"); + S9xMessage(S9X_INFO, S9X_USAGE, "-goldfinger or -gf Supply a Gold Finger code"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + + /* CONTROLLER OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-nomp5 Disable emulation of the Multiplayer 5 adapter"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nomouse Disable emulation of the SNES mouse"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nosuperscope Disable emulation of the Superscope"); + S9xMessage(S9X_INFO, S9X_USAGE, "-nojustifier Disable emulation of the Konami Justifier"); + S9xMessage(S9X_INFO, S9X_USAGE, "-port# Specify which controller to emulate in port 1/2"); + S9xMessage(S9X_INFO, S9X_USAGE, " Controllers: none No controller"); + S9xMessage(S9X_INFO, S9X_USAGE, " pad# Joypad number 1-8"); + S9xMessage(S9X_INFO, S9X_USAGE, " mouse# Mouse number 1-2"); + S9xMessage(S9X_INFO, S9X_USAGE, " superscope Superscope (not useful with -port1)"); + S9xMessage(S9X_INFO, S9X_USAGE, " justifier Blue Justifier (not useful with -port1)"); + S9xMessage(S9X_INFO, S9X_USAGE, " one-justifier ditto"); + S9xMessage(S9X_INFO, S9X_USAGE, " two-justifiers Blue & Pink Justifiers"); + S9xMessage(S9X_INFO, S9X_USAGE, " mp5:#### MP5 with the 4 named pads (1-8 or n)"); + + S9xMessage(S9X_INFO, S9X_USAGE, ""); + +#ifdef NETPLAY_SUPPORT + /* NETPLAY OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-net Enable netplay"); + S9xMessage(S9X_INFO, S9X_USAGE, "-port or -po Use port for netplay"); + S9xMessage(S9X_INFO, S9X_USAGE, "-server or -srv Use the specified server for netplay"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); +#endif + +#ifdef STORM + /* "STORM" OPTIONS */ + S9xMessage(S9X_INFO, S9X_USAGE, "-nosecondjoy Set secondjoy=0"); + S9xMessage(S9X_INFO, S9X_USAGE, "-showfps Set dofps=1"); + S9xMessage(S9X_INFO, S9X_USAGE, "-hicolor Set hicolor=1"); + S9xMessage(S9X_INFO, S9X_USAGE, "-minimal Turn off "Keyboard with exception of ESC""); + S9xMessage(S9X_INFO, S9X_USAGE, "-ahiunit Set AHI Unit to "); + S9xMessage(S9X_INFO, S9X_USAGE, ""); +#endif + +#ifndef NGC + S9xExtraUsage(); +#endif + + S9xMessage (S9X_INFO, S9X_USAGE, "\ +\nROM image needs to be in Super MagiCom (*.smc), Super FamiCom (*.sfc),\n\ +*.fig, or split (*.1, *.2, or sf32527a, sf32527b, etc) format and can be\n\ +compressed with zip, gzip, or compress.\n"); + + exit (1); +} + +#ifdef STORM +extern int dofps; +extern int hicolor; +extern int secondjoy; +extern int minimal; +int prelude=0; +extern int unit; +#endif + +#ifndef NGC +static bool parse_controller_spec(int port, const char *arg){ + if(!strcasecmp(arg, "none")) { + S9xSetController(port, CTL_NONE, 0, 0, 0, 0); + } else if(!strncasecmp(arg, "pad", 3) && + arg[3]>='1' && arg[3]<='8' && + arg[4]=='\0'){ + S9xSetController(port, CTL_JOYPAD, arg[3]-'1', 0, 0, 0); + } else if(!strncasecmp(arg, "mouse", 5) && + arg[5]>='1' && arg[5]<='2' && + arg[6]=='\0'){ + S9xSetController(port, CTL_MOUSE, arg[5]-'1', 0, 0, 0); + } else if(!strcasecmp(arg, "superscope")) { + S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); + } else if(!strcasecmp(arg, "justifier") || + !strcasecmp(arg, "one-justifier")) { + S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); + } else if(!strcasecmp(arg, "two-justifiers")) { + S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0); + } else if(!strncasecmp(arg, "mp5:", 4) && + ((arg[4]>='1' && arg[4]<='8') || arg[4]=='n') && + ((arg[5]>='1' && arg[5]<='8') || arg[5]=='n') && + ((arg[6]>='1' && arg[6]<='8') || arg[6]=='n') && + ((arg[7]>='1' && arg[7]<='8') || arg[7]=='n') && + arg[8]=='\0'){ + S9xSetController(port, CTL_MP5, + (arg[4]=='n')?-1:arg[4]-'1', + (arg[5]=='n')?-1:arg[5]-'1', + (arg[6]=='n')?-1:arg[6]-'1', + (arg[7]=='n')?-1:arg[7]-'1'); + } else { + return false; + } + return true; +} + +#endif + +char *S9xParseArgs (char **argv, int argc) +{ + +#ifndef NGC + // Nintendo Gamecube has NO COMMAND LINE ARGUMENTS -;) ***/ + for (int i = 1; i < argc; i++) + { + if (*argv[i] == '-') + { + if (strcasecmp (argv [i], "--selftest") == 0) + { + // FIXME: Probable missuse of S9X_USAGE + // FIXME: Actual tests. But at least this checks for coredumps. + S9xMessage (S9X_INFO, S9X_USAGE, "Running selftest ..."); + S9xMessage (S9X_INFO, S9X_USAGE, "snes9x started:\t[OK]"); + S9xMessage (S9X_INFO, S9X_USAGE, "All tests ok."); + exit(0); + } + if (strcasecmp (argv [i], "-so") == 0 || + strcasecmp (argv [i], "-sound") == 0) + { + Settings.NextAPUEnabled = TRUE; + } + else if (strcasecmp (argv [i], "-ns") == 0 || + strcasecmp (argv [i], "-nosound") == 0) + { + Settings.NextAPUEnabled = FALSE; + } + else if (strcasecmp (argv [i], "-soundskip") == 0 || + strcasecmp (argv [i], "-sk") == 0) + { + if (i + 1 < argc) + Settings.SoundSkipMethod = atoi (argv [++i]); + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-ra") == 0 || + strcasecmp (argv [i], "-ratio") == 0) + { + if ((i + 1) < argc) + { + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-h") == 0 || + strcasecmp (argv [i], "-cycles") == 0) + { + if (i + 1 < argc) + { + int p = atoi (argv [++i]); + if (p > 0 && p < 200) + Settings.CyclesPercentage = p; + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-nh") == 0 || + strcasecmp (argv [i], "-nohdma") == 0) + { + Settings.DisableHDMA = TRUE; + } + else if (strcasecmp (argv [i], "-ha") == 0 || + strcasecmp (argv [i], "-hdma") == 0) + { + Settings.DisableHDMA = FALSE; + } + else if (strcasecmp (argv [i], "-nsh") == 0 || + strcasecmp (argv [i], "-nospeedhacks") == 0) + { + Settings.ShutdownMaster = FALSE; + } + else if (strcasecmp (argv [i], "-sh") == 0 || + strcasecmp (argv [i], "-speedhacks") == 0) + { + Settings.ShutdownMaster = TRUE; + } + else if (strcasecmp (argv [i], "-p") == 0 || + strcasecmp (argv [i], "-pal") == 0) + { + Settings.ForcePAL = TRUE; + } + else if (strcasecmp (argv [i], "-n") == 0 || + strcasecmp (argv [i], "-ntsc") == 0) + { + Settings.ForceNTSC = TRUE; + } + else if (strcasecmp (argv [i], "-f") == 0 || + strcasecmp (argv [i], "-frameskip") == 0) + { + if (i + 1 < argc) + Settings.SkipFrames = atoi (argv [++i]) + 1; + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-fh") == 0 || + strcasecmp (argv [i], "-hr") == 0 || + strcasecmp (argv [i], "-hirom") == 0) + Settings.ForceHiROM = TRUE; + else if (strcasecmp (argv [i], "-fl") == 0 || + strcasecmp (argv [i], "-lr") == 0 || + strcasecmp (argv [i], "-lorom") == 0) + Settings.ForceLoROM = TRUE; + else if (strcasecmp (argv [i], "-hd") == 0 || + strcasecmp (argv [i], "-header") == 0 || + strcasecmp (argv [i], "-he") == 0) + { + Settings.ForceHeader = TRUE; + } + else if (strcasecmp (argv [i], "-nhd") == 0 || + strcasecmp (argv [i], "-noheader") == 0) + { + Settings.ForceNoHeader = TRUE; + } + else if (strcasecmp (argv [i], "-bs") == 0) + { + Settings.BS = TRUE; + } + else if (strcasecmp (argv [i], "-bsxbootup") == 0) + { + Settings.BSXBootup = TRUE; + } +#ifdef DEBUGGER + else if (strcasecmp (argv [i], "-d") == 0 || + strcasecmp (argv [i], "-debug") == 0) + { + CPU.Flags |= DEBUG_MODE_FLAG; + } + else if (strcasecmp (argv [i], "-t") == 0 || + strcasecmp (argv [i], "-trace") == 0) + { + if(!trace) trace = fopen ("trace.log", "wb"); + CPU.Flags |= TRACE_FLAG; + } +#endif + else if (strcasecmp (argv [i], "-L") == 0 || + strcasecmp (argv [i], "-layering") == 0) + Settings.BGLayering = TRUE; + else if (strcasecmp (argv [i], "-nl") == 0 || + strcasecmp (argv [i], "-nolayering") == 0) + Settings.BGLayering = FALSE; + else if (strcasecmp (argv [i], "-tr") == 0 || + strcasecmp (argv [i], "-transparency") == 0) + { + Settings.ForceTransparency = TRUE; + Settings.ForceNoTransparency = FALSE; + } + else if (strcasecmp (argv [i], "-nt") == 0 || + strcasecmp (argv [i], "-notransparency") == 0) + { + Settings.ForceNoTransparency = TRUE; + Settings.ForceTransparency = FALSE; + } + else if (strcasecmp (argv [i], "-hi") == 0 || + strcasecmp (argv [i], "-hires") == 0) + { + Settings.SupportHiRes = TRUE; + } + else if (strcasecmp (argv [i], "-16") == 0 || + strcasecmp (argv [i], "-sixteen") == 0) + { + } + else if (strcasecmp (argv [i], "-displayframerate") == 0 || + strcasecmp (argv [i], "-dfr") == 0) + { + Settings.DisplayFrameRate = TRUE; + } + else if (strcasecmp (argv [i], "-i") == 0 || + strcasecmp (argv [i], "-interleaved") == 0) + Settings.ForceInterleaved = TRUE; + else if (strcasecmp (argv [i], "-i2") == 0 || + strcasecmp (argv [i], "-interleaved2") == 0) + Settings.ForceInterleaved2=TRUE; + else if (strcasecmp (argv [i], "-gd24") == 0 || + strcasecmp (argv [i], "-interleavedgd24") == 0) + Settings.ForceInterleaveGD24 = TRUE; + else if (strcasecmp (argv [i], "-ni") == 0 || + strcasecmp (argv [i], "-nointerleave") == 0) + Settings.ForceNotInterleaved = TRUE; + else if (strcasecmp (argv [i], "-noirq") == 0) + Settings.DisableIRQ = TRUE; + else if (strcasecmp (argv [i], "-nw") == 0 || + strcasecmp (argv [i], "-nowindows") == 0) + { + Settings.DisableGraphicWindows = TRUE; + } + else if (strcasecmp (argv [i], "-nopatch") == 0) + { + Settings.NoPatch=TRUE; + } + else if (strcasecmp (argv [i], "-nocheat") == 0) + { + Settings.ApplyCheats=FALSE; + } + else if (strcasecmp (argv [i], "-cheat") == 0) + { + Settings.ApplyCheats=TRUE; + } + else if (strcasecmp (argv [i], "-windows") == 0) + { + Settings.DisableGraphicWindows = FALSE; + } + else if (strcasecmp (argv [i], "-aidoshm") == 0) + { + if (i + 1 < argc) + { + Settings.AIDOShmId = atoi (argv [++i]); + fprintf(stderr, "Snes9X running in AIDO mode. shmid: %d\n", + Settings.AIDOShmId); + } else + S9xUsage (); + } +#ifdef DEBUG_MAXCOUNT + else if (strcasecmp (argv [i], "-maxcount") == 0) + { + if (i + 1 < argc) + { + Settings.MaxCount = atol (argv [++i]); + fprintf(stderr, "Running for a maximum of %d loops.\n", + Settings.MaxCount); + } else + S9xUsage (); + } +#endif + else if (strcasecmp (argv [i], "-im7") == 0) + { + Settings.Mode7Interpolate = TRUE; + } + else if (strcasecmp (argv [i], "-gg") == 0 || + strcasecmp (argv [i], "-gamegenie") == 0) + { + if (i + 1 < argc) + { + uint32 address; + uint8 byte; + const char *error; + if ((error = S9xGameGenieToRaw (argv [++i], address, byte)) == NULL) + S9xAddCheat (TRUE, FALSE, address, byte); + else + S9xMessage (S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, + error); + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-ar") == 0 || + strcasecmp (argv [i], "-actionreplay") == 0) + { + if (i + 1 < argc) + { + uint32 address; + uint8 byte; + const char *error; + if ((error = S9xProActionReplayToRaw (argv [++i], address, byte)) == NULL) + S9xAddCheat (TRUE, FALSE, address, byte); + else + S9xMessage (S9X_ERROR, S9X_ACTION_REPLY_CODE_ERROR, + error); + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-gf") == 0 || + strcasecmp (argv [i], "-goldfinger") == 0) + { + if (i + 1 < argc) + { + uint32 address; + uint8 bytes [3]; + bool8 sram; + uint8 num_bytes; + const char *error; + if ((error = S9xGoldFingerToRaw (argv [++i], address, sram, + num_bytes, bytes)) == NULL) + { + for (int c = 0; c < num_bytes; c++) + S9xAddCheat (TRUE, FALSE, address + c, bytes [c]); + } + else + S9xMessage (S9X_ERROR, S9X_GOLD_FINGER_CODE_ERROR, + error); + } + else + S9xUsage (); + } + else if (strcasecmp (argv[i], "-ft") == 0 || + strcasecmp (argv [i], "-frametime") == 0) + { + if (i + 1 < argc) + { + double ft; + if (sscanf (argv [++i], "%lf", &ft) == 1) + { +#ifdef __WIN32__ + Settings.FrameTimePAL = (int32) (ft * 1000); + Settings.FrameTimeNTSC = (int32) (ft * 1000); +#else + Settings.FrameTimePAL = (int32) ft; + Settings.FrameTimeNTSC = (int32) ft; +#endif + + } + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-e") == 0 || + strcasecmp (argv [i], "-echo") == 0) + Settings.DisableSoundEcho = FALSE; + else if (strcasecmp (argv [i], "-ne") == 0 || + strcasecmp (argv [i], "-noecho") == 0) + Settings.DisableSoundEcho = TRUE; + else if (strcasecmp (argv [i], "-r") == 0 || + strcasecmp (argv [i], "-soundquality") == 0 || + strcasecmp (argv [i], "-sq") == 0) + { + if (i + 1 < argc) + Settings.SoundPlaybackRate = atoi (argv [++i]) & 7; + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-stereo") == 0 || + strcasecmp (argv [i], "-st") == 0) + { + Settings.Stereo = TRUE; + Settings.APUEnabled = TRUE; + Settings.NextAPUEnabled = TRUE; + } + else if (strcasecmp (argv [i], "-mono") == 0) + { + Settings.Stereo = FALSE; + Settings.NextAPUEnabled = TRUE; + } + else if (strcasecmp (argv [i], "-envx") == 0 || + strcasecmp (argv [i], "-ex") == 0) + { + Settings.SoundEnvelopeHeightReading = TRUE; + } + else if (strcasecmp (argv [i], "-nosamplecaching") == 0 || + strcasecmp (argv [i], "-nsc") == 0 || + strcasecmp (argv [i], "-nc") == 0) + { + Settings.DisableSampleCaching = TRUE; + } + else if (strcasecmp (argv [i], "-nomastervolume") == 0 || + strcasecmp (argv [i], "-nmv") == 0) + { + Settings.DisableMasterVolume = TRUE; + } + else if (strcasecmp (argv [i], "-soundsync") == 0 || + strcasecmp (argv [i], "-sy") == 0) + { + Settings.SoundSync = TRUE; + Settings.SoundEnvelopeHeightReading = TRUE; + Settings.InterpolatedSound = TRUE; + } + else if (strcasecmp (argv [i], "-soundsync2") == 0 || + strcasecmp (argv [i], "-sy2") == 0) + { + Settings.SoundSync = 2; + Settings.SoundEnvelopeHeightReading = TRUE; + Settings.InterpolatedSound = TRUE; + } + else if (strcasecmp (argv [i], "-interpolatedsound") == 0 || + strcasecmp (argv [i], "-is") == 0) + { + Settings.InterpolatedSound = TRUE; + } +#ifdef USE_THREADS + else if (strcasecmp (argv [i], "-threadsound") == 0 || + strcasecmp (argv [i], "-ts") == 0) + { + Settings.ThreadSound = TRUE; + } +#endif + else if (strcasecmp (argv [i], "-alt") == 0 || + strcasecmp (argv [i], "-altsampledecode") == 0) + { + Settings.AltSampleDecode = 1; + } + else if (strcasecmp (argv [i], "-fix") == 0) + { + Settings.FixFrequency = 1; + } + else if (strcasecmp (argv [i], "-nosuperfx") == 0 || + strcasecmp (argv [i], "-nosfx") == 0) + Settings.ForceNoSuperFX = TRUE; + else if (strcasecmp (argv [i], "-superfx") == 0 || + strcasecmp (argv [i], "-sfx") == 0) + Settings.ForceSuperFX = TRUE; + else if (strcasecmp (argv [i], "-dsp1") == 0) + Settings.ForceDSP1 = TRUE; + else if (strcasecmp (argv [i], "-nodsp1") == 0) + Settings.ForceNoDSP1 = TRUE; + else if (strcasecmp (argv [i], "-nomp5") == 0) + Settings.MultiPlayer5Master = FALSE; + else if (strcasecmp (argv [i], "-nomouse") == 0) + Settings.MouseMaster = FALSE; + else if (strcasecmp (argv [i], "-nosuperscope") == 0) + Settings.SuperScopeMaster = FALSE; + else if (strcasecmp (argv [i], "-nojustifier") == 0) + Settings.JustifierMaster = FALSE; + else if (strcasecmp (argv[i], "-port1") == 0 || + strcasecmp (argv[i], "-port2") == 0) + { + if (i + 1 < argc) + { + i++; + if(!parse_controller_spec(argv[i-1][5]-'1', argv[i])) + S9xUsage (); + } + else + S9xUsage (); + } +#ifdef NETPLAY_SUPPORT + else if (strcasecmp (argv [i], "-port") == 0 || + strcasecmp (argv [i], "-po") == 0) + { + if (i + 1 < argc) + { + Settings.NetPlay = TRUE; + Settings.Port = -atoi (argv [++i]); + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-server") == 0 || + strcasecmp (argv [i], "-srv") == 0) + { + if (i + 1 < argc) + { + Settings.NetPlay = TRUE; + strncpy (Settings.ServerName, argv [++i], 127); + Settings.ServerName [127] = 0; + } + else + S9xUsage (); + } + else if (strcasecmp (argv [i], "-net") == 0) + { + Settings.NetPlay = TRUE; + } +#endif +#ifdef STORM + else if (strcasecmp(argv[i],"-nosecondjoy")==0){secondjoy=0;} + else if (strcasecmp(argv[i],"-showfps")==0){dofps=1;} + else if (strcasecmp(argv[i],"-hicolor")==0){hicolor=1;} + else if (strcasecmp(argv[i],"-minimal")==0){minimal=1;printf("Keyboard with exception of ESC switched off!\n");} + else if (strcasecmp(argv[i],"-ahiunit")==0) + { + if (i+1=argc) S9xUsage(); + // Else do nothing, S9xLoadConfigFiles() handled it + } + else if (strcasecmp (argv [i], "-nostdconf") == 0) + { + // Do nothing, S9xLoadConfigFiles() handled it + } + + else + S9xParseArg (argv, i, argc); + } + else + rom_filename = argv [i]; + } + + S9xVerifyControllers(); + +#endif + + return (rom_filename); + +} + +#ifndef NGC +void S9xParseCheatsFile (const char *rom_filename) +{ + FILE *f; + char dir [_MAX_DIR]; + char drive [_MAX_DRIVE]; + char name [_MAX_FNAME]; + char ext [_MAX_EXT]; + char fname [_MAX_PATH]; + char buf [80]; + uint32 address; + uint8 byte; + uint8 bytes [3]; + bool8 sram; + uint8 num_bytes; + const char *error; + char *p; + + _splitpath (rom_filename, drive, dir, name, ext); + _makepath (fname, drive, dir, name, "pat"); + + if ((f = fopen(fname, "r")) != NULL) + { + while(fgets(buf, 80, f) != NULL) + { + if ((p = strrchr (buf, '\n')) != NULL) + *p = '\0'; + if (((error = S9xGameGenieToRaw (buf, address, byte)) == NULL) || + ((error = S9xProActionReplayToRaw (buf, address, byte)) == NULL)) + { + S9xAddCheat (TRUE, FALSE, address, byte); + } + else + if ((error = S9xGoldFingerToRaw (buf, address, sram, + num_bytes, bytes)) == NULL) + { + for (int c = 0; c < num_bytes; c++) + S9xAddCheat (TRUE, FALSE, address + c, bytes [c]); + } + else + S9xMessage (S9X_ERROR, S9X_GAME_GENIE_CODE_ERROR, error); + } + fclose(f); + } +} + +#endif + +#ifndef NGC +#include "conffile.h" +#include "crosshairs.h" + +static void parse_crosshair_spec(enum crosscontrols ctl, const char *spec){ + int idx=-1, i; + const char *fg=NULL, *bg=NULL, *s=spec; + + if(s[0]=='"'){ + s++; + for(i=0; s[i]!='\0'; i++){ + if(s[i]=='"' && s[i-1]!='\\') break; + } + idx=31-ctl; + std::string fname(s, i); + if(!S9xLoadCrosshairFile(idx, fname.c_str())) return; + s+=i+1; + } else { + if(isdigit(*s)){ idx=*s-'0'; s++; } + if(isdigit(*s)){ idx=idx*10+*s-'0'; s++; } + if(idx>31){ + fprintf(stderr, "Invalid crosshair spec '%s'\n", spec); + return; + } + } + + while(*s!='\0' && isspace(*s)){ s++; } + if(*s!='\0'){ + fg=s; + while(isalnum(*s)){ s++; } + if(*s!='/' || !isalnum(s[1])){ + fprintf(stderr, "Invalid crosshair spec '%s'\n", spec); + return; + } + bg=++s; + while(isalnum(*s)){ s++; } + if(*s!='\0'){ + fprintf(stderr, "Invalid crosshair spec '%s'\n", spec); + return; + } + } + + S9xSetControllerCrosshair(ctl, idx, fg, bg); +} + +static bool try_load(const char *fname, ConfigFile &conf){ + STREAM fp; + if((fp=OPEN_STREAM(fname, "r"))!=NULL){ + fprintf(stderr, "Reading config file %s\n", fname); + conf.LoadFile(new fReader(fp)); + CLOSE_STREAM(fp); + return true; + } + return false; +} + +void S9xLoadConfigFiles(char **argv, int argc){ + int i; + bool skip=false; + + for(i=0; i0 && i<200) Settings.CyclesPercentage = i; + Settings.DisableHDMA=conf.GetBool("Settings::DisableHDMA", false); + Settings.ShutdownMaster=conf.GetBool("Settings::SpeedHacks", true); + Settings.ForcePAL=conf.GetBool("ROM::PAL", false); + Settings.ForceNTSC=conf.GetBool("ROM::NTSC", false); + if(!strcasecmp(conf.GetString("Settings::FrameSkip", "Auto"),"Auto")){ + Settings.SkipFrames=AUTO_FRAMERATE; + } else { + Settings.SkipFrames=conf.GetUInt("Settings::FrameSkip", 0)+1; + } + Settings.TurboSkipFrames=conf.GetUInt("Settings::TurboFrameSkip", 15); + Settings.TurboMode=conf.GetBool("Settings::TurboMode",false); + Settings.StretchScreenshots=conf.GetInt("Settings::StretchScreenshots",1); + Settings.AutoSaveDelay=conf.GetUInt("Settings::AutoSaveDelay", 30); + Settings.ForceHiROM=conf.GetBool("ROM::HiROM", false); + Settings.ForceLoROM=conf.GetBool("ROM::LoROM", false); + if(conf.Exists("ROM::Header")){ + Settings.ForceHeader=conf.GetBool("ROM::Header"); + Settings.ForceNoHeader=!Settings.ForceHeader; + } + Settings.BS=conf.GetBool("ROM::BS", false); +#ifdef DEBUGGER + if(conf.GetBool("DEBUG::Debugger", false)) CPU.Flags |= DEBUG_MODE_FLAG; + if(conf.GetBool("DEBUG::Trace", false)){ + if(!trace) trace = fopen ("trace.log", "wb"); + CPU.Flags |= TRACE_FLAG; + } +#endif + Settings.BGLayering=conf.GetBool("Settings::BGLayeringHack", false); + if(conf.Exists("Display::Transparency")){ + Settings.ForceTransparency=conf.GetBool("Display::Transparency", true); + Settings.ForceNoTransparency=!Settings.ForceTransparency; + } + Settings.SupportHiRes=conf.GetBool("Display::HiRes", true); + Settings.DisplayFrameRate=conf.GetBool("Display::FrameRate", false); + if(conf.Exists("ROM::Interleaved")){ + Settings.ForceInterleaved=conf.GetBool("ROM::Interleaved", false); + Settings.ForceNotInterleaved=!Settings.ForceInterleaved; + } + Settings.ForceInterleaved2=conf.GetBool("ROM::Interleaved2", false); + Settings.ForceInterleaveGD24=conf.GetBool("ROM::InterleaveGD24", false); + Settings.DisableIRQ=conf.GetBool("CPU::DisableIRQ", false); + Settings.DisableGraphicWindows=!conf.GetBool("Display::GraphicWindows", true); + Settings.NoPatch=!conf.GetBool("ROM::Patch", true); + Settings.ApplyCheats=conf.GetBool("ROM::Cheat", true); +#ifdef DEBUG_MAXCOUNT + if(conf.Exists("DEBUG::MaxCount")){ + Settings.MaxCount = conf.GetUInt("DEBUG::MaxCount", 1); + fprintf(stderr, "Running for a maximum of %d loops.\n", Settings.MaxCount); + } +#endif + Settings.Mode7Interpolate=conf.GetBool("Display::Mode7Interpolate", false); + Settings.FrameTimePAL=conf.GetUInt("Settings::PALFrameTime", 20000); + Settings.FrameTimeNTSC=conf.GetUInt("Settings::NTSCFrameTime", 16667); + if(conf.Exists("Settings::FrameTime")){ + double ft; + if (sscanf(conf.GetString("Settings::FrameTime"), "%lf", &ft) == 1) + { +#ifdef __WIN32__ + Settings.FrameTimePAL = (int32) (ft * 1000); + Settings.FrameTimeNTSC = (int32) (ft * 1000); +#else + Settings.FrameTimePAL = (int32) ft; + Settings.FrameTimeNTSC = (int32) ft; +#endif + + } + } + Settings.FrameTime = Settings.FrameTimeNTSC; + Settings.DisableSoundEcho=!conf.GetBool("Sound::Echo", true); + Settings.SoundPlaybackRate=conf.GetUInt("Sound::Rate", Settings.SoundPlaybackRate) & 7; + Settings.SoundBufferSize=conf.GetUInt("Sound::BufferSize", Settings.SoundBufferSize); + if(conf.Exists("Sound::Stereo")){ + Settings.Stereo = conf.GetBool("Sound::Stereo"); + Settings.APUEnabled = TRUE; + Settings.NextAPUEnabled = TRUE; + } + if(conf.Exists("Sound::Mono")){ + Settings.Stereo = !conf.GetBool("Sound::Mono"); + Settings.NextAPUEnabled = TRUE; + } + Settings.SoundEnvelopeHeightReading=conf.GetBool("Sound::EnvelopeHeightReading"); + Settings.DisableSampleCaching=!conf.GetBool("Sound::SampleCaching"); + Settings.DisableMasterVolume=!conf.GetBool("Sound::MasterVolume"); + Settings.InterpolatedSound=conf.GetBool("Sound::Interpolate", false); + if(conf.Exists("Sound::Sync")){ + Settings.SoundSync=conf.GetInt("Sound::Sync", 1); + if(Settings.SoundSync>2) Settings.SoundSync=1; + Settings.SoundEnvelopeHeightReading = TRUE; + Settings.InterpolatedSound = TRUE; + } +#ifdef USE_THREADS + Settings.ThreadSound=conf.GetBool("Sound::ThreadSound", false); +#endif + if(conf.Exists("Sound::AltDecode")){ + Settings.AltSampleDecode=conf.GetInt("Sound::AltDecode", 1); + } + if(conf.Exists("Sound::FixFrequency")){ + Settings.FixFrequency=conf.GetInt("Sound::FixFrequency", 1); + } + if(conf.Exists("ROM::SuperFX")){ + Settings.ForceSuperFX=conf.GetBool("ROM::SuperFX"); + Settings.ForceNoSuperFX=!Settings.ForceSuperFX; + } + if(conf.Exists("ROM::DSP1")){ + Settings.ForceDSP1=conf.GetBool("ROM::DSP1"); + Settings.ForceNoDSP1=!Settings.ForceDSP1; + } + Settings.MultiPlayer5Master=conf.GetBool("Controls::MP5Master", true); + Settings.MouseMaster=conf.GetBool("Controls::MouseMaster", true); + Settings.SuperScopeMaster=conf.GetBool("Controls::SuperscopeMaster", true); + Settings.JustifierMaster=conf.GetBool("Controls::JustifierMaster", true); + if(conf.Exists("Controls::Port1")){ + parse_controller_spec(0, conf.GetString("Controls::Port1")); + } + if(conf.Exists("Controls::Port2")){ + parse_controller_spec(1, conf.GetString("Controls::Port2")); + } + if(conf.Exists("Controls::Mouse1Crosshair")){ + parse_crosshair_spec(X_MOUSE1, conf.GetString("Controls::Mouse1Crosshair")); + } + if(conf.Exists("Controls::Mouse2Crosshair")){ + parse_crosshair_spec(X_MOUSE2, conf.GetString("Controls::Mouse2Crosshair")); + } + if(conf.Exists("Controls::SuperscopeCrosshair")){ + parse_crosshair_spec(X_SUPERSCOPE, conf.GetString("Controls::SuperscopeCrosshair")); + } + if(conf.Exists("Controls::Justifier1Crosshair")){ + parse_crosshair_spec(X_JUSTIFIER1, conf.GetString("Controls::Justifier1Crosshair")); + } + if(conf.Exists("Controls::Justifier2Crosshair")){ + parse_crosshair_spec(X_JUSTIFIER2, conf.GetString("Controls::Justifier2Crosshair")); + } +#ifdef NETPLAY_SUPPORT + Settings.Port = NP_DEFAULT_PORT; + if(conf.Exists("Netplay::Port")){ + Settings.NetPlay = TRUE; + Settings.Port = -conf.GetUInt("Netplay::Port"); + } + Settings.ServerName[0]='\0'; + if(conf.Exists("Netplay::Server")){ + Settings.NetPlay = TRUE; + conf.GetString("Netplay::Server", Settings.ServerName, 128); + } + Settings.NetPlay=conf.GetBool("Netplay::Enable"); +#endif +#ifdef STORM + secondjoy=conf.GetBool("STORM::EnableSecondJoy",true)?1:0; + dofps=conf.GetBool("STORM::ShowFPS",false)?1:0; + hicolor=conf.GetBool("STORM::HiColor",false)?1:0; + if((minimal=conf.GetBool("STORM::Minimal")?1:0)){ + printf("Keyboard with exception of ESC switched off!\n"); + } + if(conf.Exists("STORM::AHIunit")){ + unit=conf.GetInt("STORM::AHIunit",0); + fprintf(stderr,"AHI Unit set to: Unit %i\n",unit); + } +#endif + Settings.JoystickEnabled=conf.GetBool("Controls::Joystick", Settings.JoystickEnabled); + rom_filename=conf.GetStringDup("ROM::Filename", NULL); + + S9xParsePortConfig(conf, 1); + S9xVerifyControllers(); +} + +#endif /*** Nintendo Gamecube Exclusion ***/ diff --git a/source/snes9x/snes9x.h b/source/snes9x/snes9x.h new file mode 100644 index 0000000..83e8e41 --- /dev/null +++ b/source/snes9x/snes9x.h @@ -0,0 +1,483 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _SNES9X_H_ +#define _SNES9X_H_ + +#define VERSION "1.5" + +#include +#include + +#ifdef __WIN32__ +#include "..\wsnes9x.h" +#ifdef ZLIB +#include "..\zlib\zlib.h" +#endif +#endif + +#include "language.h" + +#include "port.h" +#include "65c816.h" +#include "messages.h" + +#if defined(USE_GLIDE) && !defined(GFX_MULTI_FORMAT) +#define GFX_MULTI_FORMAT +#endif + +#define ROM_NAME_LEN 23 + +#ifdef ZLIB +#ifndef __WIN32__ +#include "zlib.h" +#endif + +#define STREAM gzFile +#define READ_STREAM(p,l,s) gzread (s,p,l) +#define WRITE_STREAM(p,l,s) gzwrite (s,p,l) +#define GETS_STREAM(p,l,s) gzgets(s,p,l) +#define GETC_STREAM(s) gzgetc(s) +#define OPEN_STREAM(f,m) gzopen (f,m) +#define REOPEN_STREAM(f,m) gzdopen (f,m) +#define FIND_STREAM(f) gztell(f) +#define REVERT_STREAM(f,o,s) gzseek(f,o,s) +#define CLOSE_STREAM(s) gzclose (s) +#else +#define STREAM FILE * +#define READ_STREAM(p,l,s) fread (p,1,l,s) +#define WRITE_STREAM(p,l,s) fwrite (p,1,l,s) +#define GETS_STREAM(p,l,s) fgets(p,l,s) +#define GETC_STREAM(s) fgetc(s) +#define OPEN_STREAM(f,m) fopen (f,m) +#define REOPEN_STREAM(f,m) fdopen (f,m) +#define FIND_STREAM(f) ftell(f) +#define REVERT_STREAM(f,o,s) fseek(f,o,s) +#define CLOSE_STREAM(s) fclose (s) +#endif + + +#define SNES_WIDTH 256 +#define SNES_HEIGHT 224 +#define SNES_HEIGHT_EXTENDED 239 +#define IMAGE_WIDTH (Settings.SupportHiRes ? SNES_WIDTH * 2 : SNES_WIDTH) +#define IMAGE_HEIGHT (Settings.SupportHiRes ? SNES_HEIGHT_EXTENDED * 2 : SNES_HEIGHT_EXTENDED) + +#define NTSC_MASTER_CLOCK 21477272.0 +#define PAL_MASTER_CLOCK 21281370.0 + +#define SNES_MAX_NTSC_VCOUNTER 262 +#define SNES_MAX_PAL_VCOUNTER 312 +#define SNES_HCOUNTER_MAX 341 + +#define ONE_CYCLE 6 +#define SLOW_ONE_CYCLE 8 +#define TWO_CYCLES 12 +#define ONE_DOT_CYCLE 4 + +#define SNES_CYCLES_PER_SCANLINE (SNES_HCOUNTER_MAX * ONE_DOT_CYCLE) +#define SNES_SCANLINE_TIME (SNES_CYCLES_PER_SCANLINE / NTSC_MASTER_CLOCK) + +#define SNES_WRAM_REFRESH_HC_v1 530 +#define SNES_WRAM_REFRESH_HC_v2 538 +#define SNES_WRAM_REFRESH_CYCLES 40 + +#define SNES_HBLANK_START_HC 1096 // H=274 +#define SNES_HDMA_START_HC 1106 // FIXME: not true +#define SNES_HBLANK_END_HC 4 // H=1 +#define SNES_HDMA_INIT_HC 20 // FIXME: not true +#define SNES_RENDER_START_HC (48 * ONE_DOT_CYCLE) // FIXME: Snes9x renders a line at a time. + +#define SNES_APUTIMER_ACCURACY 10 +#define SNES_APUTIMER2_CYCLE_SHIFT ((int32) ((SNES_CYCLES_PER_SCANLINE << SNES_APUTIMER_ACCURACY) * (1.0 / 64000.0) / SNES_SCANLINE_TIME + 0.5)) + + +#define AUTO_FRAMERATE 200 + +#define SNES_TR_MASK (1 << 4) +#define SNES_TL_MASK (1 << 5) +#define SNES_X_MASK (1 << 6) +#define SNES_A_MASK (1 << 7) +#define SNES_RIGHT_MASK (1 << 8) +#define SNES_LEFT_MASK (1 << 9) +#define SNES_DOWN_MASK (1 << 10) +#define SNES_UP_MASK (1 << 11) +#define SNES_START_MASK (1 << 12) +#define SNES_SELECT_MASK (1 << 13) +#define SNES_Y_MASK (1 << 14) +#define SNES_B_MASK (1 << 15) + +#define DEBUG_MODE_FLAG (1 << 0) +#define TRACE_FLAG (1 << 1) +#define SINGLE_STEP_FLAG (1 << 2) +#define BREAK_FLAG (1 << 3) +#define SCAN_KEYS_FLAG (1 << 4) +#define SAVE_SNAPSHOT_FLAG (1 << 5) +#define DELAYED_NMI_FLAG (1 << 6) +#define NMI_FLAG (1 << 7) +#define PROCESS_SOUND_FLAG (1 << 8) +#define FRAME_ADVANCE_FLAG (1 << 9) +#define DELAYED_NMI_FLAG2 (1 << 10) +#define IRQ_PENDING_FLAG (1 << 11) +#define HALTED_FLAG (1 << 12) + +struct SCPUState{ + uint32 Flags; + bool8 BranchSkip; + bool8 NMIActive; + bool8 IRQActive; + bool8 WaitingForInterrupt; + bool8 InDMA; + bool8 InWRAM_DMA; + uint8 WhichEvent; + uint8 *PCBase; + uint32 PBPCAtOpcodeStart; + uint32 WaitAddress; + uint32 WaitCounter; + int32 Cycles; + int32 NextEvent; + int32 V_Counter; + int32 MemSpeed; + int32 MemSpeedx2; + int32 FastROMSpeed; + uint32 AutoSaveTimer; + bool8 SRAMModified; + bool8 BRKTriggered; + bool8 TriedInterleavedMode2; +}; + +struct STimings { + int32 H_Max_Master; + int32 H_Max; + int32 V_Max_Master; + int32 V_Max; + int32 HBlankStart; + int32 HBlankEnd; + int32 HDMAInit; + int32 HDMAStart; + int32 NMITriggerPos; + int32 WRAMRefreshPos; + int32 RenderPos; + bool8 InterlaceField; +}; + +enum { + HC_HBLANK_START_EVENT = 1, + HC_IRQ_1_3_EVENT = 2, + HC_HDMA_START_EVENT = 3, + HC_IRQ_3_5_EVENT = 4, + HC_HCOUNTER_MAX_EVENT = 5, + HC_IRQ_5_7_EVENT = 6, + HC_HDMA_INIT_EVENT = 7, + HC_IRQ_7_9_EVENT = 8, + HC_RENDER_EVENT = 9, + HC_IRQ_9_A_EVENT = 10, + HC_WRAM_REFRESH_EVENT = 11, + HC_IRQ_A_1_EVENT = 12 +}; + +struct SSettings{ + /* CPU options */ + bool8 APUEnabled; + bool8 Shutdown; + uint8 SoundSkipMethod; + int32 CyclesPercentage; + bool8 DisableIRQ; + bool8 Paused; + bool8 ForcedPause; + bool8 StopEmulation; + bool8 FrameAdvance; + + /* Tracing options */ + bool8 TraceDMA; + bool8 TraceHDMA; + bool8 TraceVRAM; + bool8 TraceUnknownRegisters; + bool8 TraceDSP; + + /* Joystick options */ + bool8 JoystickEnabled; + + /* ROM timing options (see also H_Max above) */ + bool8 ForcePAL; + bool8 ForceNTSC; + bool8 PAL; + uint32 FrameTimePAL; + uint32 FrameTimeNTSC; + uint32 FrameTime; + uint32 SkipFrames; + + /* ROM image options */ + bool8 ForceLoROM; + bool8 ForceHiROM; + bool8 ForceHeader; + bool8 ForceNoHeader; + bool8 ForceInterleaved; + bool8 ForceInterleaved2; + bool8 ForceNotInterleaved; + + /* Peripherial options */ + bool8 ForceSuperFX; + bool8 ForceNoSuperFX; + bool8 ForceDSP1; + bool8 ForceNoDSP1; + bool8 ForceSA1; + bool8 ForceNoSA1; + bool8 ForceC4; + bool8 ForceNoC4; + bool8 ForceSDD1; + bool8 ForceNoSDD1; + bool8 SRTC; + + bool8 ShutdownMaster; + bool8 MultiPlayer5Master; + bool8 SuperScopeMaster; + bool8 MouseMaster; + bool8 JustifierMaster; + bool8 SuperFX; + bool8 DSP1Master; + bool8 SA1; + bool8 C4; + bool8 SDD1; + bool8 SPC7110; + bool8 SPC7110RTC; + bool8 OBC1; + /* Sound options */ + uint32 SoundPlaybackRate; + bool8 TraceSoundDSP; + bool8 Stereo; + bool8 ReverseStereo; + bool8 SixteenBitSound; + int SoundBufferSize; + int SoundMixInterval; + bool8 SoundEnvelopeHeightReading; + bool8 DisableSoundEcho; + bool8 DisableSampleCaching; + bool8 DisableMasterVolume; + bool8 SoundSync; + bool8 InterpolatedSound; + bool8 ThreadSound; + bool8 Mute; + bool8 NextAPUEnabled; + uint8 AltSampleDecode; + bool8 FixFrequency; + + /* Graphics options */ + bool8 Transparency; + bool8 SupportHiRes; + bool8 Mode7Interpolate; + + /* SNES graphics options */ + bool8 BGLayering; + bool8 DisableGraphicWindows; + bool8 ForceTransparency; + bool8 ForceNoTransparency; + bool8 DisableHDMA; + bool8 DisplayFrameRate; + bool8 DisableRangeTimeOver; /* XXX: unused */ + + /* Others */ + bool8 NetPlay; + bool8 NetPlayServer; + char ServerName [128]; + int Port; + bool8 GlideEnable; + bool8 OpenGLEnable; + int32 AutoSaveDelay; /* Time in seconds before S-RAM auto-saved if modified. */ + bool8 ApplyCheats; + bool8 TurboMode; + uint32 TurboSkipFrames; + uint32 AutoMaxSkipFrames; + +/* Fixes for individual games */ + bool8 WinterGold; + bool8 BS; /* Japanese Satellite System games. */ + bool8 BSXItself; + bool8 BSXBootup; + uint8 APURAMInitialValue; + bool8 SampleCatchup; + int8 SETA; + bool8 TakeScreenshot; + int8 StretchScreenshots; + uint16 DisplayColor; + int SoundDriver; + int AIDOShmId; + bool8 SDD1Pack; + bool8 NoPatch; + bool8 ForceInterleaveGD24; +}; + +struct SSNESGameFixes +{ + uint8 APU_OutPorts_ReturnValueFix; + uint8 SRAMInitialValue; + uint8 Uniracers; +}; + +START_EXTERN_C +extern struct SSettings Settings; +extern struct SCPUState CPU; +extern struct STimings Timings; +extern struct SSNESGameFixes SNESGameFixes; +extern char String [513]; + +void S9xExit (); +void S9xMessage (int type, int number, const char *message); +void S9xLoadSDD1Data (); +END_EXTERN_C + +enum { + PAUSE_NETPLAY_CONNECT = (1 << 0), + PAUSE_TOGGLE_FULL_SCREEN = (1 << 1), + PAUSE_EXIT = (1 << 2), + PAUSE_MENU = (1 << 3), + PAUSE_INACTIVE_WINDOW = (1 << 4), + PAUSE_WINDOW_ICONISED = (1 << 5), + PAUSE_RESTORE_GUI = (1 << 6), + PAUSE_FREEZE_FILE = (1 << 7) +}; +void S9xSetPause (uint32 mask); +void S9xClearPause (uint32 mask); + +#endif + diff --git a/source/snes9x/soundux.cpp b/source/snes9x/soundux.cpp new file mode 100644 index 0000000..d551eb8 --- /dev/null +++ b/source/snes9x/soundux.cpp @@ -0,0 +1,2401 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifdef __DJGPP__ +#include +#undef TRUE +#endif + +#include +#include "snes9x.h" +#include "apu.h" +#include "memmap.h" +#include "soundux.h" + +// gaussian table by libopenspc and SNEeSe +static const int32 gauss[512] = +{ + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, + 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, + 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, + 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, + 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A, + 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, + 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011, + 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, + 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B, + 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, + 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028, + 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, + 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, + 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, + 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D, + 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, + 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066, + 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, + 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084, + 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, + 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8, + 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, + 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2, + 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, + 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101, + 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, + 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137, + 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, + 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172, + 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, + 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2, + 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, + 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8, + 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, + 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241, + 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, + 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E, + 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, + 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC, + 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, + 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B, + 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, + 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379, + 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, + 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5, + 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, + 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C, + 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, + 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E, + 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, + 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488, + 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, + 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA, + 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, + 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3, + 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, + 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500, + 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, + 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512, + 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, + 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519 +}; + +//static const int32 *G1 = &gauss[256], *G2 = &gauss[512], +// *G3 = &gauss[255], *G4 = &gauss[-1]; + +#define G1(n) gauss[256 + (n)] +#define G2(n) gauss[512 + (n)] +#define G3(n) gauss[255 + (n)] +#define G4(n) gauss[ -1 + (n)] + +// envelope/noise table by libopenspc and SNEeSe +int32 env_counter_table[32] = +{ + 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, + 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, + 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, + 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 +}; + +static int32 env_counter_max; +static const int32 env_counter_max_master = 0x7800; + +static int rand_seed = 1; + +extern int32 Loop[16]; +extern int32 Echo[24000]; +extern int32 FilterTaps[8]; +extern int32 MixBuffer[SOUND_BUFFER_SIZE]; +extern int32 EchoBuffer[SOUND_BUFFER_SIZE]; +extern int32 DummyEchoBuffer[SOUND_BUFFER_SIZE]; +extern uint32 FIRIndex; + +// For backward compatibility ------------------------------ +static uint32 OldAttackRate[16] = +{ + 4100, 2600, 1500, 1000, 640, 380, 260, 160, + 96, 64, 40, 24, 16, 10, 6, 1 +}; + +static uint32 OldDecayRate[8] = +{ + 1200, 740, 440, 290, 180, 110, 74, 37 +}; + +static uint32 OldSustainRate[32] = +{ + ~0, 38000, 28000, 24000, 19000, 14000, 12000, 9400, + 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500, + 1200, 880, 740, 590, 440, 370, 290, 220, + 180, 150, 110, 92, 74, 55, 37, 18 +}; + +static int OldNoiseFreq[32] = +{ + 0, 16, 21, 25, 31, 42, 50, 63, + 84, 100, 125, 167, 200, 250, 333, 400, + 500, 667, 800, 1000, 1300, 1600, 2000, 2700, + 3200, 4000, 5300, 6400, 8000, 10700, 16000, 32000 +}; +// --------------------------------------------------------- + +#define FIXED_POINT 0x10000UL +#define FIXED_POINT_SHIFT 16 + +#undef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) + +#define CLIP16(v) \ + if ((v) < -32768) \ + (v) = -32768; \ + else \ + if ((v) > 32767) \ + (v) = 32767 + +#define CLIP8(v) \ + if ((v) < -128) \ + (v) = -128; \ + else \ + if ((v) > 127) \ + (v) = 127 + +void S9xAPUSetEndOfSample (int i, Channel *); +void S9xAPUSetEndX (int); +void S9xSetEnvRate (Channel *, int32, int32); +void MixStereo (int); +void MixMono (int); + +static void S9xSetSoundFrequency (int, int); +static void S9xConvertSoundOldValues (); +static void DecodeBlock (Channel *); +static void AltDecodeBlock (Channel *); +static void AltDecodeBlock2 (Channel *); +STATIC inline uint8 *S9xGetSampleAddress (int); + +EXTERN_C void DecodeBlockAsm (int8 *, int16 *, int32 *, int32 *); +EXTERN_C void DecodeBlockAsm2 (int8 *, int16 *, int32 *, int32 *); + + +STATIC inline uint8 *S9xGetSampleAddress (int sample_number) +{ + uint32 addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xFFFF); + return (IAPU.RAM + addr); +} + +void S9xAPUSetEndOfSample (int i, Channel *ch) +{ + ch->state = SOUND_SILENT; + ch->mode = MODE_NONE; + ch->out_sample = 0; + ch->xenvx = 0; + APU.DSP[APU_ENDX] |= 1 << i; + APU.DSP[APU_KON] &= ~(1 << i); + APU.DSP[APU_KOFF] &= ~(1 << i); + APU.KeyedChannels &= ~(1 << i); +} + +#ifdef __DJGPP +END_OF_FUNCTION (S9xAPUSetEndOfSample) +#endif + +void S9xAPUSetEndX (int i) +{ + APU.DSP[APU_ENDX] |= 1 << i; +} + +#ifdef __DJGPP +END_OF_FUNCTION (S9xAPUSetEndX) +#endif + +void S9xSetEnvRate (Channel *ch, int32 rate_count, int32 xtarget) +{ + ch->xenvx_target = xtarget; + ch->xenv_rate = rate_count; +} + +#ifdef __DJGPP +END_OF_FUNCTION(S9xSetEnvRate); +#endif + +void S9xSetEnvelopeRate (int channel, int32 rate_count, int32 xtarget) +{ + S9xSetEnvRate (&SoundData.channels[channel], rate_count, xtarget); +} + +#ifdef __DJGPP +END_OF_FUNCTION(S9xSetEnvelopeRate); +#endif + +void S9xSetSoundVolume (int channel, short volume_left, short volume_right) +{ + Channel *ch = &SoundData.channels[channel]; + + if (so.stereo_switch + 1) + { + volume_left = ((so.stereo_switch & ( 1 << channel)) ? volume_left : 0); + volume_right = ((so.stereo_switch & (256 << channel)) ? volume_right : 0); + } + + if (!so.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + ch->volume_left = volume_left; + ch->volume_right = volume_right; +} + +void S9xSetMasterVolume (short volume_left, short volume_right) +{ + if (Settings.DisableMasterVolume) + { + SoundData.master_volume_left = 127; + SoundData.master_volume_right = 127; + SoundData.master_volume[0] = SoundData.master_volume[1] = 127; + } + else + { + if (!so.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + SoundData.master_volume_left = volume_left; + SoundData.master_volume_right = volume_right; + SoundData.master_volume[Settings.ReverseStereo] = volume_left; + SoundData.master_volume[1 ^ Settings.ReverseStereo] = volume_right; + } +} + +void S9xSetEchoVolume (short volume_left, short volume_right) +{ + if (!so.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + SoundData.echo_volume_left = volume_left; + SoundData.echo_volume_right = volume_right; + SoundData.echo_volume[Settings.ReverseStereo] = volume_left; + SoundData.echo_volume[1 ^ Settings.ReverseStereo] = volume_right; +} + +void S9xSetEchoEnable (uint8 byte) +{ +#if 0 + SoundData.echo_channel_enable = byte; + if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho) + byte = 0; + if (byte && !SoundData.echo_enable) + { + memset (Loop, 0, sizeof (Loop)); + memset (Echo, 0, sizeof (Echo)); + } +#endif + SoundData.echo_enable = byte; + for (int i = 0; i < NUM_CHANNELS; i++) + { + if (byte & (1 << i)) + SoundData.channels[i].echo_buf_ptr = EchoBuffer; + else + SoundData.channels[i].echo_buf_ptr = DummyEchoBuffer; + } +} + +void S9xSetEchoFeedback (int feedback) +{ + SoundData.echo_feedback = feedback; +} + +void S9xSetEchoDelay (unsigned int delay) +{ + SoundData.echo_buffer_size = (delay << 10) * so.playback_rate / 32000; + if (!so.stereo) + SoundData.echo_buffer_size >>= 1; + if (SoundData.echo_buffer_size) + SoundData.echo_ptr %= SoundData.echo_buffer_size; + else + SoundData.echo_ptr = 0; +} + +void S9xSetEchoWriteEnable (uint8 byte) +{ + SoundData.echo_write_enabled = byte; + //printf("Echo write enable: %d\n", byte); +} + +void S9xSetFrequencyModulationEnable (uint8 byte) +{ + SoundData.pitch_mod = byte & ~1; +} + +void S9xSetSoundKeyOff (int channel) +{ + Channel *ch = &SoundData.channels[channel]; + + if (ch->state != SOUND_SILENT) + { + ch->state = SOUND_RELEASE; + ch->mode = MODE_RELEASE; + S9xSetEnvRate (ch, env_counter_max, 0); + } +} + +void S9xPrepareSoundForSnapshotSave (bool8 restore) +{ + static uint32 temp_hertz[NUM_CHANNELS]; + + int i, j; + + if (!restore) + { + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + ch->count = 0; + ch->envx = ch->xenvx >> 4; + ch->envx_target = ch->xenvx_target >> 4; + ch->direction = 0; + ch-> left_vol_level = (ch->xenvx * ch->volume_left ) >> 11; + ch->right_vol_level = (ch->xenvx * ch->volume_right) >> 11; + ch->release_rate = 8; + ch->sustain_level = ch->xsustain_level >> 8; + + if (env_counter_max < ch->xenv_count) + ch->env_error = 0; + else + ch->env_error = (uint32) + ((double) FIXED_POINT / env_counter_max * (env_counter_max - ch->xenv_count)); + + if (ch->xenv_rate < 0) + ch->erate = 0; + else + ch->erate = (uint32) + ((double) FIXED_POINT / env_counter_max * ch->xenv_rate); + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xattack_rate) + break; + ch->attack_rate = OldAttackRate[(unsigned) (((j - 1) >> 1) & 0xF)]; + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xdecay_rate) + break; + ch->decay_rate = OldDecayRate[(unsigned) (((j - 0x10) >> 1) & 0x7)]; + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xsustain_rate) + break; + ch->sustain_rate = OldSustainRate[(unsigned) (j & 0x1F)]; + } + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == SoundData.noise_rate) + break; + + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + temp_hertz[i] = ch->hertz; + if (ch->type == SOUND_NOISE) + ch->hertz = OldNoiseFreq[(unsigned) (j & 0x1F)]; + } + } + else + { + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + ch->hertz = temp_hertz[i]; + } + } +} + +static void S9xConvertSoundOldValues () +{ + int i, j; + int old_noise_freq = 0; + + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + ch->xenvx = ch->envx << 4; + ch->xenvx_target = ch->envx_target << 4; + ch->out_sample = ((ch->sample * ch->xenvx) >> 11) & ~1; + ch->xsustain_level = ch->sustain_level << 8; + + ch->xenv_rate = (int32) ((double) ch->erate * env_counter_max / FIXED_POINT); + ch->xenv_count = env_counter_max - + (int32) ((double) ch->env_error * env_counter_max / FIXED_POINT); + + for (j = 0; j < 16; j++) + if (OldAttackRate[j] == ch->attack_rate) + break; + ch->xattack_rate = env_counter_table[(unsigned) (((j << 1) + 1) & 0x1F)]; + + for (j = 0; j < 8; j++) + if (OldDecayRate[j] == ch->decay_rate) + break; + ch->xdecay_rate = env_counter_table[(unsigned) (((j << 1) + 0x10) & 0x1F)]; + + for (j = 0; j < 32; j++) + if (OldSustainRate[j] == ch->sustain_rate) + break; + ch->xsustain_rate = env_counter_table[(unsigned) (j & 0x1F)]; + + if (ch->type == SOUND_NOISE) + { + old_noise_freq = ch->hertz; + ch->hertz = 32000; + } + } + + if (old_noise_freq) + { + for (j = 0; j < 32; j++) + if (OldNoiseFreq[j] == old_noise_freq) + break; + SoundData.noise_rate = env_counter_table[(unsigned) (j & 0x1F)]; + } + else + SoundData.noise_rate = 0; +} + +void S9xFixSoundAfterSnapshotLoad (int version) +{ + S9xSetEchoEnable (APU.DSP[APU_EON]); + S9xSetEchoWriteEnable (!(APU.DSP[APU_FLG] & APU_ECHO_DISABLED)); + S9xSetEchoDelay (APU.DSP[APU_EDL] & 0xF); + S9xSetEchoFeedback ((signed char) APU.DSP[APU_EFB]); + + S9xSetFilterCoefficient (0, (signed char) APU.DSP[APU_C0]); + S9xSetFilterCoefficient (1, (signed char) APU.DSP[APU_C1]); + S9xSetFilterCoefficient (2, (signed char) APU.DSP[APU_C2]); + S9xSetFilterCoefficient (3, (signed char) APU.DSP[APU_C3]); + S9xSetFilterCoefficient (4, (signed char) APU.DSP[APU_C4]); + S9xSetFilterCoefficient (5, (signed char) APU.DSP[APU_C5]); + S9xSetFilterCoefficient (6, (signed char) APU.DSP[APU_C6]); + S9xSetFilterCoefficient (7, (signed char) APU.DSP[APU_C7]); + + if (version < 2) + S9xConvertSoundOldValues (); + + for (int i = 0; i < NUM_CHANNELS; i++) + { + S9xSetSoundFrequency (i, SoundData.channels[i].hertz); + SoundData.channels[i].needs_decode = TRUE; + SoundData.channels[i].nb_index = 0; + SoundData.channels[i].nb_sample[0] = 0; + SoundData.channels[i].nb_sample[1] = 0; + SoundData.channels[i].nb_sample[2] = 0; + SoundData.channels[i].nb_sample[3] = 0; + SoundData.channels[i].xsmp_count = 0; + SoundData.channels[i].previous[0] = (int32) SoundData.channels[i].previous16[0]; + SoundData.channels[i].previous[1] = (int32) SoundData.channels[i].previous16[1]; + } + + SoundData.noise_count = 0; + + SoundData.master_volume[Settings.ReverseStereo] = SoundData.master_volume_left; + SoundData.master_volume[1 ^ Settings.ReverseStereo] = SoundData.master_volume_right; + SoundData.echo_volume[Settings.ReverseStereo] = SoundData.echo_volume_left; + SoundData.echo_volume[1 ^ Settings.ReverseStereo] = SoundData.echo_volume_right; +} + +void S9xSetFilterCoefficient (int tap, int value) +{ + FilterTaps[tap & 7] = value; + SoundData.no_filter = + FilterTaps[0] == 127 && + FilterTaps[1] == 0 && + FilterTaps[2] == 0 && + FilterTaps[3] == 0 && + FilterTaps[4] == 0 && + FilterTaps[5] == 0 && + FilterTaps[6] == 0 && + FilterTaps[7] == 0; +} + +void S9xSetSoundADSR (int channel, int ar, int dr, int sr, int sl) +{ + Channel *ch = &SoundData.channels[channel]; + + ch->xattack_rate = env_counter_table[(ar << 1) + 1]; + ch->xdecay_rate = env_counter_table[(dr << 1) + 0x10]; + ch->xsustain_rate = env_counter_table[sr]; + ch->xsustain_level = (ENV_RANGE >> 3) * (sl + 1); + + switch (ch->state) + { + case SOUND_ATTACK: + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); + break; + + case SOUND_DECAY: + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + break; + + case SOUND_SUSTAIN: + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + break; + } +} + +void S9xSetEnvelopeHeight (int channel, int32 xlevel) +{ + Channel *ch = &SoundData.channels[channel]; + + ch->xenvx = ch->xenvx_target = xlevel; + ch->xenv_rate = 0; + if (xlevel == 0 && ch->state != SOUND_SILENT && ch->state != SOUND_GAIN) + S9xAPUSetEndOfSample (channel, ch); +} + +uint8 S9xGetEnvelopeHeight (int channel) +{ + if (Settings.SoundEnvelopeHeightReading) + return ((SoundData.channels[channel].xenvx >> ENV_SHIFT) & 0x7F); + else + return (0); +} + +static void S9xSetSoundFrequency (int channel, int hertz) +{ + if (so.playback_rate) + SoundData.channels[channel].frequency = (uint32) + ((int64) (hertz << (FIXED_POINT_SHIFT - 15)) * 32000 / so.playback_rate); + if (Settings.FixFrequency) + SoundData.channels[channel].frequency = (uint32) + (SoundData.channels[channel].frequency * so.pitch_mul); +} + +void S9xSetSoundHertz (int channel, int hertz) +{ + SoundData.channels[channel].hertz = hertz; + S9xSetSoundFrequency (channel, hertz); +} + +void S9xSetSoundType (int channel, int type_of_sound) +{ + SoundData.channels[channel].type = type_of_sound; +} + +bool8 S9xSetSoundMute (bool8 mute) +{ + bool8 old = so.mute_sound; + so.mute_sound = mute; + return (old); +} + +static void AltDecodeBlock (Channel *ch) +{ + if (ch->block_pointer > 0x10000 - 9) + { + ch->last_block = TRUE; + ch->loop = FALSE; + ch->block = ch->decoded; + memset ((void *) ch->decoded, 0, sizeof (int16) * 16); + return; + } + + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + unsigned char filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + + signed short *raw = ch->block = ch->decoded; + +#if (defined (USE_X86_ASM) && (defined (__i386__) || defined (__i486__) || \ + defined (__i586__) || defined (__WIN32__) || defined (__DJGPP))) + if (Settings.AltSampleDecode == 1) + DecodeBlockAsm (compressed, raw, &ch->previous[0], &ch->previous[1]); + else + DecodeBlockAsm2 (compressed, raw, &ch->previous[0], &ch->previous[1]); +#else + int32 out; + unsigned char shift; + signed char sample1, sample2; + uint32 i; + + compressed++; + + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + shift = filter >> 4; + + switch ((filter >> 2) & 3) + { + case 0: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + *raw++ = ((int32) sample1 << shift); + *raw++ = ((int32) sample2 << shift); + } + prev1 = *(raw - 2); + prev0 = *(raw - 1); + break; + + case 1: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + prev0 = (int16) prev0; + *raw++ = prev1 = ((int32) sample1 << shift) + prev0 - (prev0 >> 4); + prev1 = (int16) prev1; + *raw++ = prev0 = ((int32) sample2 << shift) + prev1 - (prev1 >> 4); + } + break; + + case 2: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = (sample1 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - + (prev0 >> 4); + + out = (sample2 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - + (prev0 >> 4); + } + break; + + case 3: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (sample1 << shift); + + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - + (prev0 >> 4) - (prev1 >> 6); + + out = (sample2 << shift); + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - + (prev0 >> 4) - (prev1 >> 6); + } + break; + } + + ch->previous[0] = prev0; + ch->previous[1] = prev1; +#endif + ch->block_pointer += 9; +} + +static void AltDecodeBlock2 (Channel *ch) +{ + int32 out; + unsigned char filter; + unsigned char shift; + signed char sample1, sample2; + uint32 i; + + if (ch->block_pointer > 0x10000 - 9) + { + ch->last_block = TRUE; + ch->loop = FALSE; + ch->block = ch->decoded; + memset ((void *) ch->decoded, 0, sizeof (int16) * 16); + return; + } + + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + + compressed++; + signed short *raw = ch->block = ch->decoded; + + shift = filter >> 4; + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + + if(shift > 12) + shift -= 4; + + switch ((filter >> 2) & 3) + { + case 0: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = (int32) (sample1 << shift); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + } + break; + + case 1: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (int32) (sample1 << shift); + out += (int32) ((double) prev0 * 15/16); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + out += (int32) ((double) prev0 * 15/16); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + } + break; + + case 2: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = ((sample1 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; + + prev1 = prev0; + prev0 = (int16) out; + *raw++ = (int16) out; + + out = ((sample2 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; + + prev1 = prev0; + prev0 = (int16) out; + *raw++ = (int16) out; + } + break; + + case 3: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (int32) (sample1 << shift); + out += (int32) ((double) prev0 * 115/64 - (double) prev1 * 13/16); + + prev1 = prev0; + prev0 = out; + + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + out += (int32) ((double) prev0 * 115/64 - (double) prev1 * 13/16); + + prev1 = prev0; + prev0 = out; + + CLIP16(out); + *raw++ = (int16) out; + } + break; + } + + ch->previous[0] = prev0; + ch->previous[1] = prev1; + + ch->block_pointer += 9; +} + +static void DecodeBlock (Channel *ch) +{ + int32 out; + unsigned char filter; + unsigned char shift; + signed char sample1, sample2; + bool invalid_header; + + if (Settings.AltSampleDecode) + { + if (Settings.AltSampleDecode < 3) + AltDecodeBlock (ch); + else + AltDecodeBlock2 (ch); + return; + } + + if (ch->block_pointer > 0x10000 - 9) + { + ch->last_block = TRUE; + ch->loop = FALSE; + ch->block = ch->decoded; + return; + } + + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + + compressed++; + signed short *raw = ch->block = ch->decoded; + + // Seperate out the header parts used for decoding + + shift = filter >> 4; + + // Header validity check: if range(shift) is over 12, ignore + // all bits of the data for that block except for the sign bit of each + invalid_header = !(shift < 0xD); + + filter &= 0x0C; + + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + + for (uint32 i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + //Sample 2 = Bottom Nibble, Sign Extended. + sample2 >>= 4; + //Sample 1 = Top Nibble, shifted down and Sign Extended. + sample1 >>= 4; + + for (int nybblesmp = 0; nybblesmp < 2; nybblesmp++) + { + out = (nybblesmp ? sample2 : sample1); + if (!invalid_header) + out = (out << shift) >> 1; + else + out &= ~0x7FF; + + switch (filter) + { + case 0x00: + // Method0 -[Smp] + break; + + case 0x04: + // Method1 -[Delta]+[Smp-1](15/16) + out += prev0 >> 1; + out += (-prev0) >> 5; + break; + + case 0x08: + // Method2 -[Delta]+[Smp-1](61/32)-[Smp-2](15/16) + out += prev0; + out += (-(prev0 + (prev0 >> 1))) >> 5; + out -= prev1 >> 1; + out += prev1 >> 5; + break; + + case 0x0C: + // Method3 -[Delta]+[Smp-1](115/64)-[Smp-2](13/16) + out += prev0; + out += (-(prev0 + (prev0 << 2) + (prev0 << 3))) >> 7; + out -= prev1 >> 1; + out += (prev1 + (prev1 >> 1)) >> 4; + break; + } + + CLIP16(out); + + prev1 = (signed short) prev0; + prev0 = *raw++ = (signed short) (out << 1); + } + } + + ch->previous[0] = prev0; + ch->previous[1] = prev1; + + ch->block_pointer += 9; +} + +void MixStereo (int sample_count) +{ + static int32 noise_cache[256]; + static int32 wave[SOUND_BUFFER_SIZE]; + + int pitch_mod = SoundData.pitch_mod & ~APU.DSP[APU_NON]; + + int32 noise_index = 0; + int32 noise_count = 0; + + if (APU.DSP[APU_NON]) + { + noise_count = SoundData.noise_count; + + for (uint32 I = 0; I < (uint32) sample_count; I += 2) + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + rand_seed = rand_seed * 48828125 + 1; + noise_cache[noise_index] = rand_seed; + noise_index = (noise_index + 1) & 0xFF; + noise_count += env_counter_max; + } + } + } + + for (uint32 J = 0; J < NUM_CHANNELS; J++) + { + Channel *ch = &SoundData.channels[J]; + uint32 freq = ch->frequency; + + bool8 last_block = FALSE; + + if (ch->type == SOUND_NOISE) + { + noise_index = 0; + noise_count = SoundData.noise_count; + } + + if (ch->state == SOUND_SILENT || last_block || !(so.sound_switch & (1 << J))) + continue; + + bool8 mod1 = pitch_mod & (1 << J); + bool8 mod2 = pitch_mod & (1 << (J + 1)); + + if (ch->needs_decode) + { + DecodeBlock(ch); + ch->needs_decode = FALSE; + ch->sample = ch->block[0]; + ch->sample_pointer = 0; + } + + for (uint32 I = 0; I < (uint32) sample_count; I += 2) + { + switch (ch->state) + { + case SOUND_ATTACK: + if (ch->xenv_rate == env_counter_max_master) + ch->xenvx += (ENV_RANGE >> 1); // FIXME + else + { + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + + if (ch->xsustain_level != ENV_RANGE) + { + ch->state = SOUND_DECAY; + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + } + else + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + } + + break; + + case SOUND_DECAY: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= ch->xenvx_target) + { + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + else + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + } + + break; + + case SOUND_SUSTAIN: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_RELEASE: + ch->xenv_count -= env_counter_max; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 8); // 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_INCREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_INCREASE_BENT_LINE: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + if (ch->xenvx >= ((ENV_RANGE * 3) >> 2)) // 0x600 + ch->xenvx += (ENV_RANGE >> 8); // 1/256 + else + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_DECREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_DECREASE_EXPONENTIAL: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_GAIN: + S9xSetEnvRate (ch, 0, 0); + + break; + } + + ch->xsmp_count += mod1 ? (((int64) freq * (32768 + wave[I >> 1])) >> 15) : freq; + + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = ch->sample; + ch->nb_index = (ch->nb_index + 1) & 3; + + ch->sample_pointer++; + if (ch->sample_pointer == SOUND_DECODE_LENGTH) + { + ch->sample_pointer = 0; + + if (ch->last_block) + { + S9xAPUSetEndX (J); + if (!ch->loop) + { + ch->xenvx = 0; + last_block = TRUE; + //S9xAPUSetEndOfSample (J, ch); + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = 0; + ch->nb_index = (ch->nb_index + 1) & 3; + } + + break; + } + else + { + ch->last_block = FALSE; + uint8 *dir = S9xGetSampleAddress (ch->sample_number); + ch->block_pointer = READ_WORD(dir + 2); // loop pointer + } + } + + DecodeBlock (ch); + } + + ch->sample = ch->block[ch->sample_pointer]; + } + + int32 outx, d; + + if (ch->type == SOUND_SAMPLE) + { + if (Settings.InterpolatedSound) + { + // 4-point gaussian interpolation + d = ch->xsmp_count >> (FIXED_POINT_SHIFT - 8); + outx = ((G4(-d) * ch->nb_sample[ ch->nb_index ]) >> 11) & ~1; + outx += ((G3(-d) * ch->nb_sample[(ch->nb_index + 1) & 3]) >> 11) & ~1; + outx += ((G2( d) * ch->nb_sample[(ch->nb_index + 2) & 3]) >> 11) & ~1; + outx = ((outx & 0xFFFF) ^ 0x8000) - 0x8000; + outx += ((G1( d) * ch->nb_sample[(ch->nb_index + 3) & 3]) >> 11) & ~1; + CLIP16(outx); + } + else + outx = ch->sample; + } + else // SAMPLE_NOISE + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + noise_count += env_counter_max; + noise_index = (noise_index + 1) & 0xFF; + } + + outx = noise_cache[noise_index] >> 16; + } + + outx = ((outx * ch->xenvx) >> 11) & ~1; + ch->out_sample = outx; + + if (mod2) + wave[I >> 1] = outx; + + int32 VL, VR; + + VL = (outx * ch->volume_left ) >> 7; + VR = (outx * ch->volume_right) >> 7; + + MixBuffer[I ^ Settings.ReverseStereo ] += VL; + MixBuffer[I + (1 ^ Settings.ReverseStereo)] += VR; + ch->echo_buf_ptr[I ^ Settings.ReverseStereo ] += VL; + ch->echo_buf_ptr[I + (1 ^ Settings.ReverseStereo)] += VR; + } + + stereo_exit: ; + } + + if (APU.DSP[APU_NON]) + SoundData.noise_count = noise_count; +} + +#ifdef __DJGPP +END_OF_FUNCTION(MixStereo); +#endif + +void MixMono (int sample_count) +{ + static int32 noise_cache[256]; + static int32 wave[SOUND_BUFFER_SIZE]; + + int pitch_mod = SoundData.pitch_mod & ~APU.DSP[APU_NON]; + + int32 noise_index = 0; + int32 noise_count = 0; + + if (APU.DSP[APU_NON]) + { + noise_count = SoundData.noise_count; + + for (uint32 I = 0; I < (uint32) sample_count; I++) + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + rand_seed = rand_seed * 48828125 + 1; + noise_cache[noise_index] = rand_seed; + noise_index = (noise_index + 1) & 0xFF; + noise_count += env_counter_max; + } + } + } + + for (uint32 J = 0; J < NUM_CHANNELS; J++) + { + Channel *ch = &SoundData.channels[J]; + uint32 freq = ch->frequency; + + bool8 last_block = FALSE; + + if (ch->type == SOUND_NOISE) + { + noise_index = 0; + noise_count = SoundData.noise_count; + } + + if (ch->state == SOUND_SILENT || last_block || !(so.sound_switch & (1 << J))) + continue; + + bool8 mod1 = pitch_mod & (1 << J); + bool8 mod2 = pitch_mod & (1 << (J + 1)); + + if (ch->needs_decode) + { + DecodeBlock(ch); + ch->needs_decode = FALSE; + ch->sample = ch->block[0]; + ch->sample_pointer = 0; + } + + for (uint32 I = 0; I < (uint32) sample_count; I++) + { + switch (ch->state) + { + case SOUND_ATTACK: + if (ch->xenv_rate == env_counter_max_master) + ch->xenvx += (ENV_RANGE >> 1); // FIXME + else + { + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + + if (ch->xsustain_level != ENV_RANGE) + { + ch->state = SOUND_DECAY; + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + } + else + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + } + + break; + + case SOUND_DECAY: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= ch->xenvx_target) + { + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto mono_exit; + } + else + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + } + + break; + + case SOUND_SUSTAIN: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto mono_exit; + } + + break; + + case SOUND_RELEASE: + ch->xenv_count -= env_counter_max; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 8); // 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto mono_exit; + } + + break; + + case SOUND_INCREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_INCREASE_BENT_LINE: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + if (ch->xenvx >= ((ENV_RANGE * 3) >> 2)) // 0x600 + ch->xenvx += (ENV_RANGE >> 8); // 1/256 + else + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_DECREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto mono_exit; + } + + break; + + case SOUND_DECREASE_EXPONENTIAL: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto mono_exit; + } + + break; + + case SOUND_GAIN: + S9xSetEnvRate (ch, 0, 0); + + break; + } + + ch->xsmp_count += mod1 ? (((int64) freq * (32768 + wave[I])) >> 15) : freq; + + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = ch->sample; + ch->nb_index = (ch->nb_index + 1) & 3; + + ch->sample_pointer++; + if (ch->sample_pointer == SOUND_DECODE_LENGTH) + { + ch->sample_pointer = 0; + + if (ch->last_block) + { + S9xAPUSetEndX (J); + if (!ch->loop) + { + ch->xenvx = 0; + last_block = TRUE; + //S9xAPUSetEndOfSample (J, ch); + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = 0; + ch->nb_index = (ch->nb_index + 1) & 3; + } + + break; + } + else + { + ch->last_block = FALSE; + uint8 *dir = S9xGetSampleAddress (ch->sample_number); + ch->block_pointer = READ_WORD(dir + 2); // loop pointer + } + } + + DecodeBlock (ch); + } + + ch->sample = ch->block[ch->sample_pointer]; + } + + int32 outx, d; + + if (ch->type == SOUND_SAMPLE) + { + if (Settings.InterpolatedSound) + { + // 4-point gaussian interpolation + d = ch->xsmp_count >> (FIXED_POINT_SHIFT - 8); + outx = ((G4(-d) * ch->nb_sample[ ch->nb_index ]) >> 11) & ~1; + outx += ((G3(-d) * ch->nb_sample[(ch->nb_index + 1) & 3]) >> 11) & ~1; + outx += ((G2( d) * ch->nb_sample[(ch->nb_index + 2) & 3]) >> 11) & ~1; + outx = ((outx & 0xFFFF) ^ 0x8000) - 0x8000; + outx += ((G1( d) * ch->nb_sample[(ch->nb_index + 3) & 3]) >> 11) & ~1; + CLIP16(outx); + } + else + outx = ch->sample; + } + else // SAMPLE_NOISE + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + noise_count += env_counter_max; + noise_index = (noise_index + 1) & 0xFF; + } + + outx = noise_cache[noise_index] >> 16; + } + + outx = ((outx * ch->xenvx) >> 11) & ~1; + ch->out_sample = outx; + + if (mod2) + wave[I] = outx; + + int32 V; + + V = (outx * ch->volume_left ) >> 7; + + MixBuffer[I] += V; + ch->echo_buf_ptr[I] += V; + } + + mono_exit: ; + } + + if (APU.DSP[APU_NON]) + SoundData.noise_count = noise_count; +} + +#ifdef __DJGPP +END_OF_FUNCTION(MixMono); +#endif + +#ifdef __sun +extern uint8 int2ulaw (int); +#endif + +// For backwards compatibility with older port specific code +void S9xMixSamplesO (uint8 *buffer, int sample_count, int byte_offset) +{ + S9xMixSamples (buffer+byte_offset, sample_count); +} + +#ifdef __DJGPP +END_OF_FUNCTION(S9xMixSamplesO); +#endif + +void S9xMixSamples (uint8 *buffer, int sample_count) +{ + int I, J; + + if (!so.mute_sound) + { + memset (MixBuffer, 0, sample_count * sizeof (MixBuffer[0])); + if (!Settings.DisableSoundEcho) + memset (EchoBuffer, 0, sample_count * sizeof (EchoBuffer[0])); + + if (so.stereo) + MixStereo (sample_count); + else + MixMono (sample_count); + } + + /* Mix and convert waveforms */ + if (so.sixteen_bit) + { + // 16-bit sound + if (so.mute_sound) + memset (buffer, 0, sample_count << 1); + else + { + if (!Settings.DisableSoundEcho) + { + if (so.stereo) + { + // 16-bit stereo sound with echo enabled ... + if (SoundData.no_filter) + { + // ... but no filter defined. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = (E * 127) >> 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + else + { + // ... with filter defined. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = E * FilterTaps[0]; + E += Loop[(FIRIndex - 2) & 15] * FilterTaps[1]; + E += Loop[(FIRIndex - 4) & 15] * FilterTaps[2]; + E += Loop[(FIRIndex - 6) & 15] * FilterTaps[3]; + E += Loop[(FIRIndex - 8) & 15] * FilterTaps[4]; + E += Loop[(FIRIndex - 10) & 15] * FilterTaps[5]; + E += Loop[(FIRIndex - 12) & 15] * FilterTaps[6]; + E += Loop[(FIRIndex - 14) & 15] * FilterTaps[7]; + E >>= 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + } + else + { + // 16-bit mono sound with echo enabled... + if (SoundData.no_filter) + { + // ... no filter defined + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 7] = E; + E = (E * 127) >> 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[0] + + E * SoundData.echo_volume[0]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + else + { + // ... with filter defined + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 7] = E; + E = E * FilterTaps[0]; + E += Loop[(FIRIndex - 1) & 7] * FilterTaps[1]; + E += Loop[(FIRIndex - 2) & 7] * FilterTaps[2]; + E += Loop[(FIRIndex - 3) & 7] * FilterTaps[3]; + E += Loop[(FIRIndex - 4) & 7] * FilterTaps[4]; + E += Loop[(FIRIndex - 5) & 7] * FilterTaps[5]; + E += Loop[(FIRIndex - 6) & 7] * FilterTaps[6]; + E += Loop[(FIRIndex - 7) & 7] * FilterTaps[7]; + E >>= 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[0] + + E * SoundData.echo_volume[0]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + } + } + else + { + // 16-bit mono or stereo sound, no echo + for (J = 0; J < sample_count; J++) + { + I = (MixBuffer[J] * SoundData.master_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + } + } + else + { + // 8-bit sound + if (so.mute_sound) + memset (buffer, 128, sample_count); + else + #ifdef __sun + if (so.encoded) + { + for (J = 0; J < sample_count; J++) + { + I = (MixBuffer[J] * SoundData.master_volume[0]) >> 7; + CLIP16(I); + buffer[J] = int2ulaw (I); + } + } + else + #endif + { + if (!Settings.DisableSoundEcho) + { + if (so.stereo) + { + // 8-bit stereo sound with echo enabled... + if (SoundData.no_filter) + { + // ... but no filter + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = (E * 127) >> 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 15; + CLIP8(I); + buffer[J] = I + 128; + } + } + else + { + // ... with filter + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = E * FilterTaps[0]; + E += Loop[(FIRIndex - 2) & 15] * FilterTaps[1]; + E += Loop[(FIRIndex - 4) & 15] * FilterTaps[2]; + E += Loop[(FIRIndex - 6) & 15] * FilterTaps[3]; + E += Loop[(FIRIndex - 8) & 15] * FilterTaps[4]; + E += Loop[(FIRIndex - 10) & 15] * FilterTaps[5]; + E += Loop[(FIRIndex - 12) & 15] * FilterTaps[6]; + E += Loop[(FIRIndex - 14) & 15] * FilterTaps[7]; + E >>= 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 15; + CLIP8(I); + buffer[J] = I + 128; + } + } + } + else + { + // 8-bit mono sound with echo enabled... + if (SoundData.no_filter) + { + // ... but no filter. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 7] = E; + E = (E * 127) >> 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[0] + + E * SoundData.echo_volume[0]) >> 15; + CLIP8(I); + buffer[J] = I + 128; + } + } + else + { + // ... with filter. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 7] = E; + E = E * FilterTaps[0]; + E += Loop[(FIRIndex - 1) & 7] * FilterTaps[1]; + E += Loop[(FIRIndex - 2) & 7] * FilterTaps[2]; + E += Loop[(FIRIndex - 3) & 7] * FilterTaps[3]; + E += Loop[(FIRIndex - 4) & 7] * FilterTaps[4]; + E += Loop[(FIRIndex - 5) & 7] * FilterTaps[5]; + E += Loop[(FIRIndex - 6) & 7] * FilterTaps[6]; + E += Loop[(FIRIndex - 7) & 7] * FilterTaps[7]; + E >>= 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[0] + + E * SoundData.echo_volume[0]) >> 15; + CLIP8(I); + buffer[J] = I + 128; + } + } + } + } + else + { + // 8-bit mono or stereo sound, no echo + for (J = 0; J < sample_count; J++) + { + I = (MixBuffer[J] * SoundData.master_volume[J & 1]) >> 15; + CLIP8(I); + buffer[J] = I + 128; + } + } + } + } + +} + +#ifdef __DJGPP +END_OF_FUNCTION(S9xMixSamples); +#endif + +void S9xResetSound (bool8 full) +{ + for (int i = 0; i < NUM_CHANNELS; i++) + { + SoundData.channels[i].state = SOUND_SILENT; + SoundData.channels[i].mode = MODE_NONE; + SoundData.channels[i].type = SOUND_SAMPLE; + SoundData.channels[i].volume_left = 0; + SoundData.channels[i].volume_right = 0; + SoundData.channels[i].hertz = 0; + SoundData.channels[i].loop = FALSE; + SoundData.channels[i].xsmp_count = 0; + SoundData.channels[i].xenvx = 0; + SoundData.channels[i].xenvx_target = 0; + SoundData.channels[i].xenv_count = 0; + SoundData.channels[i].xenv_rate = 0; + SoundData.channels[i].xattack_rate = 0; + SoundData.channels[i].xdecay_rate = 0; + SoundData.channels[i].xsustain_rate = 0; + SoundData.channels[i].xsustain_level = 0; + } + + FilterTaps [0] = 127; + FilterTaps [1] = 0; + FilterTaps [2] = 0; + FilterTaps [3] = 0; + FilterTaps [4] = 0; + FilterTaps [5] = 0; + FilterTaps [6] = 0; + FilterTaps [7] = 0; + + rand_seed = 1; + + so.mute_sound = TRUE; + so.noise_gen = 1; + so.sound_switch = 255; + so.stereo_switch = ~0; + so.samples_mixed_so_far = 0; + so.play_position = 0; + so.err_counter = 0; + + if (full) + { + SoundData.echo_volume_left = 0; + SoundData.echo_volume_right = 0; + SoundData.echo_enable = 0; + SoundData.echo_write_enabled = 0; + SoundData.pitch_mod = 0; + SoundData.dummy[0] = 0; + SoundData.dummy[1] = 0; + SoundData.dummy[2] = 0; + SoundData.echo_volume[0] = 0; + SoundData.echo_volume[1] = 0; + SoundData.noise_count = 0; + SoundData.noise_rate = 0; + memset (Loop, 0, sizeof (Loop)); + memset (Echo, 0, sizeof (Echo)); + } + + // At least Super Bomberman 2 requires the defaule master volume is not zero. +#if 1 + SoundData.master_volume_left = 127; + SoundData.master_volume_right = 127; + SoundData.master_volume [0] = SoundData.master_volume [1] = 127; +#else + SoundData.master_volume_left = 0; + SoundData.master_volume_right = 0; + SoundData.master_volume [0] = SoundData.master_volume [1] = 0; +#endif + SoundData.no_filter = TRUE; + SoundData.echo_ptr = 0; + SoundData.echo_feedback = 0; + SoundData.echo_buffer_size = 1; + + if (so.playback_rate) + so.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME * so.playback_rate); + else + so.err_rate = 0; +} + +void S9xSetPlaybackRate (uint32 playback_rate) +{ + if (playback_rate > 48000) + playback_rate = 48000; + + so.playback_rate = playback_rate; + so.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME * so.playback_rate); + + memset (Loop, 0, sizeof (Loop)); + memset (Echo, 0, sizeof (Echo)); + S9xSetEchoDelay (APU.DSP[APU_EDL] & 0xF); + + for (int i = 0; i < NUM_CHANNELS; i++) + S9xSetSoundFrequency (i, SoundData.channels[i].hertz); + + env_counter_max = env_counter_max_master * playback_rate / 32000; + SoundData.noise_count = env_counter_max; +} + +bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size) +{ + so.sound_fd = -1; + so.sound_switch = 255; + so.stereo_switch = ~0; + + so.playback_rate = 0; + so.buffer_size = 0; + so.stereo = stereo; + so.sixteen_bit = Settings.SixteenBitSound; + so.encoded = FALSE; + so.pitch_mul = 0.985; // XXX: necessary for most cards in linux...? + + S9xResetSound (TRUE); + + if (!(mode & 7)) + return (1); + + S9xSetSoundMute (TRUE); + if (!S9xOpenSoundDevice (mode, stereo, buffer_size)) + { + #ifdef NOSOUND + S9xMessage (S9X_WARNING, S9X_SOUND_NOT_BUILT, + "No sound support compiled in"); + #else + S9xMessage (S9X_ERROR, S9X_SOUND_DEVICE_OPEN_FAILED, + "Sound device open failed"); + #endif + return (0); + } + + return (1); +} + +bool8 S9xSetSoundMode (int channel, int mode) +{ + Channel *ch = &SoundData.channels[channel]; + + switch (mode) + { + case MODE_RELEASE: + if (ch->mode != MODE_NONE) + { + ch->mode = MODE_RELEASE; + return (TRUE); + } + break; + + case MODE_DECREASE_LINEAR: + case MODE_DECREASE_EXPONENTIAL: + case MODE_GAIN: + if (ch->mode != MODE_RELEASE) + { + ch->mode = mode; + if (ch->state != SOUND_SILENT) + ch->state = mode; + + return (TRUE); + } + break; + + case MODE_INCREASE_LINEAR: + case MODE_INCREASE_BENT_LINE: + if (ch->mode != MODE_RELEASE) + { + ch->mode = mode; + if (ch->state != SOUND_SILENT) + ch->state = mode; + + return (TRUE); + } + break; + + case MODE_ADSR: + if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR) + { + ch->mode = mode; + return (TRUE); + } + } + + return (FALSE); +} + +void S9xSetSoundControl (int sound_switch) +{ + so.sound_switch = sound_switch; +} + +void S9xPlaySample (int channel) +{ + Channel *ch = &SoundData.channels[channel]; + + ch->state = SOUND_SILENT; + ch->mode = MODE_NONE; + ch->xenvx = 0; + + S9xFixEnvelope (channel, + APU.DSP[APU_GAIN + (channel << 4)], + APU.DSP[APU_ADSR1 + (channel << 4)], + APU.DSP[APU_ADSR2 + (channel << 4)]); + + ch->sample_number = APU.DSP[APU_SRCN + channel * 0x10]; + if (APU.DSP[APU_NON] & (1 << channel)) + ch->type = SOUND_NOISE; + else + ch->type = SOUND_SAMPLE; + + S9xSetSoundFrequency (channel, ch->hertz); + ch->loop = FALSE; + ch->needs_decode = TRUE; + ch->last_block = FALSE; + ch->previous[0] = ch->previous[1] = 0; + uint8 *dir = S9xGetSampleAddress (ch->sample_number); + ch->block_pointer = READ_WORD (dir); + ch->sample_pointer = 0; + ch->xenv_count = env_counter_max; + ch->xsmp_count = 3 * FIXED_POINT; // since gaussian interpolation uses 4 points + ch->nb_sample[0] = 0; + ch->nb_sample[1] = 0; + ch->nb_sample[2] = 0; + ch->nb_sample[3] = 0; + ch->nb_index = 0; + + switch (ch->mode) + { + case MODE_ADSR: // FIXME: rapid attack + #if 0 + ch->state = SOUND_ATTACK; + ch->xenvx = 0; + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); + break; + #else + if (ch->xattack_rate == env_counter_max_master) + { + ch->xenvx = ENV_MAX; + if (ch->xsustain_level == ENV_RANGE) + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + else + { + ch->state = SOUND_DECAY; + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + } + } + else + { + ch->state = SOUND_ATTACK; + ch->xenvx = 0; + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); + } + + break; + #endif + + case MODE_GAIN: + ch->state = SOUND_GAIN; + break; + + case MODE_INCREASE_LINEAR: + ch->state = SOUND_INCREASE_LINEAR; + break; + + case MODE_INCREASE_BENT_LINE: + ch->state = SOUND_INCREASE_BENT_LINE; + break; + + case MODE_DECREASE_LINEAR: + ch->state = SOUND_DECREASE_LINEAR; + break; + + case MODE_DECREASE_EXPONENTIAL: + ch->state = SOUND_DECREASE_EXPONENTIAL; + break; + + default: + break; + } + + S9xFixEnvelope (channel, + APU.DSP[APU_GAIN + (channel << 4)], + APU.DSP[APU_ADSR1 + (channel << 4)], + APU.DSP[APU_ADSR2 + (channel << 4)]); +} diff --git a/source/snes9x/soundux.h b/source/snes9x/soundux.h new file mode 100644 index 0000000..482429f --- /dev/null +++ b/source/snes9x/soundux.h @@ -0,0 +1,333 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _SOUND_H_ +#define _SOUND_H_ + +enum +{ + SOUND_SAMPLE = 0, + SOUND_NOISE +}; + +enum +{ + SOUND_SILENT, + SOUND_ATTACK, + SOUND_DECAY, + SOUND_SUSTAIN, + SOUND_RELEASE, + SOUND_GAIN, + SOUND_INCREASE_LINEAR, + SOUND_INCREASE_BENT_LINE, + SOUND_DECREASE_LINEAR, + SOUND_DECREASE_EXPONENTIAL +}; + +enum +{ + MODE_NONE = SOUND_SILENT, + MODE_ADSR, + MODE_RELEASE = SOUND_RELEASE, + MODE_GAIN, + MODE_INCREASE_LINEAR, + MODE_INCREASE_BENT_LINE, + MODE_DECREASE_LINEAR, + MODE_DECREASE_EXPONENTIAL +}; + +#define NUM_CHANNELS 8 +#define SOUND_DECODE_LENGTH 16 +#define SOUND_BUFFER_SIZE (1024 * 16) +#define MAX_BUFFER_SIZE SOUND_BUFFER_SIZE +#define SOUND_BUFFER_SIZE_MASK (SOUND_BUFFER_SIZE - 1) + +#define ENV_RANGE 0x800 +#define ENV_MAX 0x7FF +#define ENV_SHIFT 4 + +#ifdef __sgi +#include +#endif /* __sgi */ + +typedef struct { + int sound_fd; // ** port specific + int sound_switch; // channel on/off + int playback_rate; // 32000Hz is recommended + int buffer_size; // ** port specific + int noise_gen; // ** unused + bool8 mute_sound; // mute + int stereo; // stereo or mono + bool8 sixteen_bit; // 16bit or 8bit sample + bool8 encoded; // ** port specific +#ifdef __sun + int last_eof; // ** port specific +#endif +#ifdef __sgi + ALport al_port; // ** port specific +#endif /* __sgi */ + int32 samples_mixed_so_far; // ** port specific + int32 play_position; // ** port specific + uint32 err_counter; // ** port specific + uint32 err_rate; // ** port specific + + uint16 stereo_switch; // stereo channel on/off + double pitch_mul; // used with Settings.FixFrequency +} SoundStatus; + +EXTERN_C volatile SoundStatus so; + +typedef struct { + int32 state; // ADSR/GAIN/RELEASE/SILENT + int32 type; // sample or noise + short volume_left; // VOL(L) + short volume_right; // VOL(R) + uint32 hertz; // ((P(H) << 8) + P(L)) * 8 + uint32 frequency; // normalized pitch + uint32 count; // ** unused + bool8 loop; // loop flag in BRR header + int32 envx; // ** unused + short left_vol_level; // ** unused + short right_vol_level; // ** unused + short envx_target; // ** unused + uint32 env_error; // ** unused + uint32 erate; // ** unused + int32 direction; // ** unused + uint32 attack_rate; // ** unused + uint32 decay_rate; // ** unused + uint32 sustain_rate; // ** unused + uint32 release_rate; // ** unused + uint32 sustain_level; // ** unused + signed short sample; // signed 16 bit sample + signed short decoded[16]; // decoded 16 samples + signed short previous16[2]; + signed short *block; + uint16 sample_number; // SRCN + bool8 last_block; // end flag in BRR header + bool8 needs_decode; // true when BRR block will be decoded + uint32 block_pointer; // currect block + uint32 sample_pointer; // pointer in a block + int32 *echo_buf_ptr; // EchoBuffer[] or DummyEchoBuffer[] + int32 mode; // ADSR/GAIN/RELEASE/SILENT + int32 envxx; // ** unused + signed short next_sample; // ** unused + int32 interpolate; // ** unused + int32 previous[2]; // last two nybbles for BRR decode + uint32 dummy[8]; // Just incase they are needed in the future, + // for snapshot compatibility. + + int32 nb_index; // index of cached samples + int16 nb_sample[4]; // cached samples for interpolation + int16 out_sample; // OUTX << 4 + int32 xenvx; // ENVX << 4 + int32 xenvx_target; // ENVX target << 4 + int32 xenv_count; // counter for envelope timing + int32 xenv_rate; // envelope timing from env_counter_table + int32 xsmp_count; // counter for pitch + int32 xattack_rate; // envelope timing from env_counter_table + int32 xdecay_rate; // envelope timing from env_counter_table + int32 xsustain_rate; // envelope timing from env_counter_table + int32 xsustain_level; // (128 / 8 * (SR + 1)) << 4 +} Channel; + +typedef struct +{ + short master_volume_left; // MVOL(L) + short master_volume_right; // MVOL(R) + short echo_volume_left; // EVOL(L) + short echo_volume_right; // EVOL(R) + int32 echo_enable; // EON + int32 echo_feedback; // EFB + int32 echo_ptr; // index of Echo[] + int32 echo_buffer_size; // num of echo samples + int32 echo_write_enabled; // ECEN + int32 echo_channel_enable; // ** unused + int32 pitch_mod; // PMOD + uint32 dummy[3]; // Just incase they are needed in the future, + // for snapshot compatibility. + Channel channels[NUM_CHANNELS]; + bool8 no_filter; // true when simple echo + int32 master_volume[2]; + int32 echo_volume[2]; + int32 noise_hertz; // ** unused + + int32 noise_count; // counter for noise frequency + int32 noise_rate; // noise frequency from env_counter_table +} SSoundData; + +EXTERN_C SSoundData SoundData; + + +void S9xSetEnvelopeRate (int channel, int32 rate_count, int32 xtarget); +void S9xSetSoundVolume (int channel, short volume_left, short volume_right); +void S9xSetMasterVolume (short volume_left, short volume_right); +void S9xSetEchoVolume (short volume_left, short volume_right); +void S9xSetEchoEnable (uint8 byte); +void S9xSetEchoFeedback (int echo_feedback); +void S9xSetEchoDelay (unsigned int byte); +void S9xSetEchoWriteEnable (uint8 byte); +void S9xSetFrequencyModulationEnable (uint8 byte); +void S9xSetSoundKeyOff (int channel); +void S9xPrepareSoundForSnapshotSave (bool8 restore); +void S9xFixSoundAfterSnapshotLoad (int version); +void S9xSetFilterCoefficient (int tap, int value); +void S9xSetSoundADSR (int channel, int ar, int dr, int sr, int sl); +void S9xSetEnvelopeHeight (int channel, int32 xlevel); +uint8 S9xGetEnvelopeHeight (int channel); +void S9xSetSoundHertz (int channel, int hertz); +void S9xSetSoundType (int channel, int type_of_sound); +bool8 S9xSetSoundMute (bool8 mute); +void S9xResetSound (bool8 full); +void S9xSetPlaybackRate (uint32 playback_rate); +bool8 S9xSetSoundMode (int channel, int mode); +void S9xSetSoundControl (int sound_switch); +void S9xPlaySample (int channel); + +void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2); +bool8 S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size); + +EXTERN_C void S9xMixSamples (uint8 *buffer, int sample_count); +EXTERN_C void S9xMixSamplesO (uint8 *buffer, int sample_count, int byte_offset); + +#endif diff --git a/source/snes9x/spc700.cpp b/source/snes9x/spc700.cpp new file mode 100644 index 0000000..95db72e --- /dev/null +++ b/source/snes9x/spc700.cpp @@ -0,0 +1,2632 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include "snes9x.h" +#include "spc700.h" +#include "memmap.h" +#include "display.h" +#include "cpuexec.h" +#include "apu.h" + +// SPC700/Sound DSP chips have a 24.57MHz crystal on their PCB. + +#ifdef NO_INLINE_SET_GET +uint8 S9xAPUGetByteZ (uint8 address); +uint8 S9xAPUGetByte (uint32 address); +void S9xAPUSetByteZ (uint8, uint8 address); +void S9xAPUSetByte (uint8, uint32 address); + +#else +#undef INLINE +#define INLINE inline +#include "apumem.h" +#endif + +START_EXTERN_C +// XXX: FIXME: Rewrite APU core to not use global variables +uint8 Work8; +uint16 Work16; +uint32 Work32; +int8 Int8; +int16 Int16; +int32 Int32; +uint8 W1; +uint8 W2; + +END_EXTERN_C + +#define OP1 (*(IAPU.PC + 1)) +#define OP2 (*(IAPU.PC + 2)) + +#ifdef SPC700_SHUTDOWN +#define APUShutdown() \ + if (Settings.Shutdown && (IAPU.PC == IAPU.WaitAddress1 || IAPU.PC == IAPU.WaitAddress2)) \ + { \ + if (IAPU.WaitCounter == 0) \ + { \ + if (!ICPU.CPUExecuting) \ + { \ + APU.Cycles = CPU.Cycles = CPU.NextEvent; \ + S9xUpdateAPUTimer(); \ + } \ + else \ + IAPU.APUExecuting = FALSE; \ + } \ + else \ + if (IAPU.WaitCounter >= 2) \ + IAPU.WaitCounter = 1; \ + else \ + IAPU.WaitCounter--; \ + } +#else +#define APUShutdown() +#endif + +#define APUSetZN8(b)\ + IAPU._Zero = (b); + +#define APUSetZN16(w)\ + IAPU._Zero = ((w) != 0) | ((w) >> 8); + +void WARN (char *s) +{ + char buffer[100]; + +#ifdef DEBUGGER + S9xAPUOPrint (buffer, IAPU.PC - IAPU.RAM); +#endif + + sprintf (String, "Sound CPU executing %s at %04X\n%s\n", s, (uint32) (IAPU.PC - IAPU.RAM), buffer); + S9xMessage (S9X_ERROR, S9X_APU_STOPPED, String); +} + +void STOP (char *s) +{ + WARN(s); + APU.TimerEnabled[0] = APU.TimerEnabled[1] = APU.TimerEnabled[2] = FALSE; + IAPU.APUExecuting = FALSE; +#ifdef DEBUGGER + CPU.Flags |= DEBUG_MODE_FLAG; +#else + S9xExit (); +#endif +} + +#define TCALL(n)\ +{\ + PushW (IAPU.PC - IAPU.RAM + 1); \ + IAPU.PC = IAPU.RAM + S9xAPUGetByte(0xffc0 + ((15 - n) << 1)) + \ + (S9xAPUGetByte(0xffc1 + ((15 - n) << 1)) << 8); \ +} + +#define SBC(a,b)\ +Int16 = (short) (a) - (short) (b) + (short) (APUCheckCarry ()) - 1;\ +IAPU._Carry = Int16 >= 0;\ +if ((((a) ^ (b)) & 0x80) && (((a) ^ (uint8) Int16) & 0x80))\ + APUSetOverflow ();\ +else \ + APUClearOverflow (); \ +APUSetHalfCarry ();\ +if(((a) ^ (b) ^ (uint8) Int16) & 0x10)\ + APUClearHalfCarry ();\ +(a) = (uint8) Int16;\ +APUSetZN8 ((uint8) Int16); + +#define ADC(a,b)\ +Work16 = (a) + (b) + APUCheckCarry();\ +IAPU._Carry = Work16 >= 0x100; \ +if (~((a) ^ (b)) & ((b) ^ (uint8) Work16) & 0x80)\ + APUSetOverflow ();\ +else \ + APUClearOverflow (); \ +APUClearHalfCarry ();\ +if(((a) ^ (b) ^ (uint8) Work16) & 0x10)\ + APUSetHalfCarry ();\ +(a) = (uint8) Work16;\ +APUSetZN8 ((uint8) Work16); + +#define CMP(a,b)\ +Int16 = (short) (a) - (short) (b);\ +IAPU._Carry = Int16 >= 0;\ +APUSetZN8 ((uint8) Int16); + +#define ASL(b)\ + IAPU._Carry = ((b) & 0x80) != 0; \ + (b) <<= 1;\ + APUSetZN8 (b); +#define LSR(b)\ + IAPU._Carry = (b) & 1;\ + (b) >>= 1;\ + APUSetZN8 (b); +#define ROL(b)\ + Work16 = ((b) << 1) | APUCheckCarry (); \ + IAPU._Carry = Work16 >= 0x100; \ + (b) = (uint8) Work16; \ + APUSetZN8 (b); +#define ROR(b)\ + Work16 = (b) | ((uint16) APUCheckCarry () << 8); \ + IAPU._Carry = (uint8) Work16 & 1; \ + Work16 >>= 1; \ + (b) = (uint8) Work16; \ + APUSetZN8 (b); + +#define Push(b)\ + *(IAPU.RAM + 0x100 + APURegisters.S) = b;\ + APURegisters.S--; + +#define Pop(b)\ + APURegisters.S++;\ + (b) = *(IAPU.RAM + 0x100 + APURegisters.S); + +#ifdef FAST_LSB_WORD_ACCESS +#define PushW(w)\ + if(APURegisters.S==0){ \ + *(IAPU.RAM + 0x1ff) = (w);\ + *(IAPU.RAM + 0x100) = (w >> 8);\ + } else { \ + *(uint16 *) (IAPU.RAM + 0xff + APURegisters.S) = (w);\ + } \ + APURegisters.S -= 2; +#define PopW(w)\ + APURegisters.S += 2;\ + if(APURegisters.S==0){ \ + (w) = *(IAPU.RAM + 0x1ff) | (*(IAPU.RAM + 0x100)<<8);\ + } else { \ + (w) = *(uint16 *) (IAPU.RAM + 0xff + APURegisters.S); \ + } +#else +#define PushW(w)\ + *(IAPU.RAM + 0x100 + APURegisters.S--) = (w >> 8);\ + *(IAPU.RAM + 0x100 + APURegisters.S--) = (w); +#define PopW(w)\ + APURegisters.S += 2;\ + if(APURegisters.S==0){ \ + (w) = *(IAPU.RAM + 0x1ff) | (*(IAPU.RAM + 0x100)<<8);\ + } else { \ + (w) = *(IAPU.RAM + 0xff + APURegisters.S) + (*(IAPU.RAM + 0x100 + APURegisters.S) << 8); \ + } +#endif + +#define Relative()\ + Int8 = OP1;\ + Int16 = (int32) (IAPU.PC + 2 - IAPU.RAM) + Int8; + +#define Relative2()\ + Int8 = OP2;\ + Int16 = (int32) (IAPU.PC + 3 - IAPU.RAM) + Int8; + +#ifdef FAST_LSB_WORD_ACCESS +#define IndexedXIndirect()\ + IAPU.Address = *(uint16 *) (IAPU.DirectPage + ((OP1 + APURegisters.X) & 0xff)); + +#define Absolute()\ + IAPU.Address = *(uint16 *) (IAPU.PC + 1); + +#define AbsoluteX()\ + IAPU.Address = *(uint16 *) (IAPU.PC + 1) + APURegisters.X; + +#define AbsoluteY()\ + IAPU.Address = *(uint16 *) (IAPU.PC + 1) + APURegisters.YA.B.Y; + +#define MemBit()\ + IAPU.Address = *(uint16 *) (IAPU.PC + 1);\ + IAPU.Bit = (uint8)(IAPU.Address >> 13);\ + IAPU.Address &= 0x1fff; + +#define IndirectIndexedY()\ + IAPU.Address = *(uint16 *) (IAPU.DirectPage + OP1) + APURegisters.YA.B.Y; +#else +#define IndexedXIndirect()\ + IAPU.Address = *(IAPU.DirectPage + ((OP1 + APURegisters.X) & 0xff)) + \ + (*(IAPU.DirectPage + ((OP1 + APURegisters.X + 1) & 0xff)) << 8); +#define Absolute()\ + IAPU.Address = OP1 + (OP2 << 8); + +#define AbsoluteX()\ + IAPU.Address = OP1 + (OP2 << 8) + APURegisters.X; + +#define AbsoluteY()\ + IAPU.Address = OP1 + (OP2 << 8) + APURegisters.YA.B.Y; + +#define MemBit()\ + IAPU.Address = OP1 + (OP2 << 8);\ + IAPU.Bit = (int8) (IAPU.Address >> 13);\ + IAPU.Address &= 0x1fff; + +#define IndirectIndexedY()\ + IAPU.Address = *(IAPU.DirectPage + OP1) + \ + (*(IAPU.DirectPage + OP1 + 1) << 8) + \ + APURegisters.YA.B.Y; +#endif + +void Apu00 () +{ +// NOP + IAPU.PC++; +} + +void Apu01 () { TCALL (0) } + +void Apu11 () { TCALL (1) } + +void Apu21 () { TCALL (2) } + +void Apu31 () { TCALL (3) } + +void Apu41 () { TCALL (4) } + +void Apu51 () { TCALL (5) } + +void Apu61 () { TCALL (6) } + +void Apu71 () { TCALL (7) } + +void Apu81 () { TCALL (8) } + +void Apu91 () { TCALL (9) } + +void ApuA1 () { TCALL (10) } + +void ApuB1 () { TCALL (11) } + +void ApuC1 () { TCALL (12) } + +void ApuD1 () { TCALL (13) } + +void ApuE1 () { TCALL (14) } + +void ApuF1 () { TCALL (15) } + +void Apu3F () // CALL absolute +{ + Absolute (); + // 0xB6f for Star Fox 2 + PushW (IAPU.PC + 3 - IAPU.RAM); + IAPU.PC = IAPU.RAM + IAPU.Address; +} + +void Apu4F () // PCALL $XX +{ + Work8 = OP1; + PushW (IAPU.PC + 2 - IAPU.RAM); + IAPU.PC = IAPU.RAM + 0xff00 + Work8; +} + +#define SET(b) \ +S9xAPUSetByteZ ((uint8) (S9xAPUGetByteZ (OP1 ) | (1 << (b))), OP1); \ +IAPU.PC += 2 + +void Apu02 () +{ + SET (0); +} + +void Apu22 () +{ + SET (1); +} + +void Apu42 () +{ + SET (2); +} + +void Apu62 () +{ + SET (3); +} + +void Apu82 () +{ + SET (4); +} + +void ApuA2 () +{ + SET (5); +} + +void ApuC2 () +{ + SET (6); +} + +void ApuE2 () +{ + SET (7); +} + +#define CLR(b) \ +S9xAPUSetByteZ ((uint8) (S9xAPUGetByteZ (OP1) & ~(1 << (b))), OP1); \ +IAPU.PC += 2; + +void Apu12 () +{ + CLR (0); +} + +void Apu32 () +{ + CLR (1); +} + +void Apu52 () +{ + CLR (2); +} + +void Apu72 () +{ + CLR (3); +} + +void Apu92 () +{ + CLR (4); +} + +void ApuB2 () +{ + CLR (5); +} + +void ApuD2 () +{ + CLR (6); +} + +void ApuF2 () +{ + CLR (7); +} + +#define BBS(b) \ +Work8 = OP1; \ +Relative2 (); \ +if (S9xAPUGetByteZ (Work8) & (1 << (b))) \ +{ \ + IAPU.PC = IAPU.RAM + (uint16) Int16; \ + APU.Cycles += IAPU.TwoCycles; \ +} \ +else \ + IAPU.PC += 3 + +void Apu03 () +{ + BBS (0); +} + +void Apu23 () +{ + BBS (1); +} + +void Apu43 () +{ + BBS (2); +} + +void Apu63 () +{ + BBS (3); +} + +void Apu83 () +{ + BBS (4); +} + +void ApuA3 () +{ + BBS (5); +} + +void ApuC3 () +{ + BBS (6); +} + +void ApuE3 () +{ + BBS (7); +} + +#define BBC(b) \ +Work8 = OP1; \ +Relative2 (); \ +if (!(S9xAPUGetByteZ (Work8) & (1 << (b)))) \ +{ \ + IAPU.PC = IAPU.RAM + (uint16) Int16; \ + APU.Cycles += IAPU.TwoCycles; \ +} \ +else \ + IAPU.PC += 3 + +void Apu13 () +{ + BBC (0); +} + +void Apu33 () +{ + BBC (1); +} + +void Apu53 () +{ + BBC (2); +} + +void Apu73 () +{ + BBC (3); +} + +void Apu93 () +{ + BBC (4); +} + +void ApuB3 () +{ + BBC (5); +} + +void ApuD3 () +{ + BBC (6); +} + +void ApuF3 () +{ + BBC (7); +} + +void Apu04 () +{ +// OR A,dp + APURegisters.YA.B.A |= S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu05 () +{ +// OR A,abs + Absolute (); + APURegisters.YA.B.A |= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu06 () +{ +// OR A,(X) + APURegisters.YA.B.A |= S9xAPUGetByteZ (APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu07 () +{ +// OR A,(dp+X) + IndexedXIndirect (); + APURegisters.YA.B.A |= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu08 () +{ +// OR A,#00 + APURegisters.YA.B.A |= OP1; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu09 () +{ +// OR dp(dest),dp(src) + Work8 = S9xAPUGetByteZ (OP1); + Work8 |= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu14 () +{ +// OR A,dp+X + APURegisters.YA.B.A |= S9xAPUGetByteZ (OP1 + APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu15 () +{ +// OR A,abs+X + AbsoluteX (); + APURegisters.YA.B.A |= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu16 () +{ +// OR A,abs+Y + AbsoluteY (); + APURegisters.YA.B.A |= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu17 () +{ +// OR A,(dp)+Y + IndirectIndexedY (); + APURegisters.YA.B.A |= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu18 () +{ +// OR dp,#00 + Work8 = OP1; + Work8 |= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu19 () +{ +// OR (X),(Y) + Work8 = S9xAPUGetByteZ (APURegisters.X) | S9xAPUGetByteZ (APURegisters.YA.B.Y); + APUSetZN8 (Work8); + S9xAPUSetByteZ (Work8, APURegisters.X); + IAPU.PC++; +} + +void Apu0A () +{ +// OR1 C,membit + MemBit (); + if (!APUCheckCarry ()) + { + if (S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit)) + APUSetCarry (); + } + IAPU.PC += 3; +} + +void Apu2A () +{ +// OR1 C,not membit + MemBit (); + if (!APUCheckCarry ()) + { + if (!(S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit))) + APUSetCarry (); + } + IAPU.PC += 3; +} + +void Apu4A () +{ +// AND1 C,membit + MemBit (); + if (APUCheckCarry ()) + { + if (!(S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit))) + APUClearCarry (); + } + IAPU.PC += 3; +} + +void Apu6A () +{ +// AND1 C, not membit + MemBit (); + if (APUCheckCarry ()) + { + if ((S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit))) + APUClearCarry (); + } + IAPU.PC += 3; +} + +void Apu8A () +{ +// EOR1 C, membit + MemBit (); + if (APUCheckCarry ()) + { + if (S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit)) + APUClearCarry (); + } + else + { + if (S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit)) + APUSetCarry (); + } + IAPU.PC += 3; +} + +void ApuAA () +{ +// MOV1 C,membit + MemBit (); + if (S9xAPUGetByte (IAPU.Address) & (1 << IAPU.Bit)) + APUSetCarry (); + else + APUClearCarry (); + IAPU.PC += 3; +} + +void ApuCA () +{ +// MOV1 membit,C + MemBit (); + if (APUCheckCarry ()) + { + S9xAPUSetByte (S9xAPUGetByte (IAPU.Address) | (1 << IAPU.Bit), IAPU.Address); + } + else + { + S9xAPUSetByte (S9xAPUGetByte (IAPU.Address) & ~(1 << IAPU.Bit), IAPU.Address); + } + IAPU.PC += 3; +} + +void ApuEA () +{ +// NOT1 membit + MemBit (); + S9xAPUSetByte (S9xAPUGetByte (IAPU.Address) ^ (1 << IAPU.Bit), IAPU.Address); + IAPU.PC += 3; +} + +void Apu0B () +{ +// ASL dp + Work8 = S9xAPUGetByteZ (OP1); + ASL (Work8); + S9xAPUSetByteZ (Work8, OP1); + IAPU.PC += 2; +} + +void Apu0C () +{ +// ASL abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + ASL (Work8); + S9xAPUSetByte (Work8, IAPU.Address); + IAPU.PC += 3; +} + +void Apu1B () +{ +// ASL dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + ASL (Work8); + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void Apu1C () +{ +// ASL A + ASL (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu0D () +{ +// PUSH PSW + S9xAPUPackStatus (); + Push (APURegisters.P); + IAPU.PC++; +} + +void Apu2D () +{ +// PUSH A + Push (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu4D () +{ +// PUSH X + Push (APURegisters.X); + IAPU.PC++; +} + +void Apu6D () +{ +// PUSH Y + Push (APURegisters.YA.B.Y); + IAPU.PC++; +} + +void Apu8E () +{ +// POP PSW + Pop (APURegisters.P); + S9xAPUUnpackStatus (); + if (APUCheckDirectPage ()) + IAPU.DirectPage = IAPU.RAM + 0x100; + else + IAPU.DirectPage = IAPU.RAM; + IAPU.PC++; +} + +void ApuAE () +{ +// POP A + Pop (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuCE () +{ +// POP X + Pop (APURegisters.X); + IAPU.PC++; +} + +void ApuEE () +{ +// POP Y + Pop (APURegisters.YA.B.Y); + IAPU.PC++; +} + +void Apu0E () +{ +// TSET1 abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + S9xAPUSetByte (Work8 | APURegisters.YA.B.A, IAPU.Address); + Work8 &= APURegisters.YA.B.A; + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu4E () +{ +// TCLR1 abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + S9xAPUSetByte (Work8 & ~APURegisters.YA.B.A, IAPU.Address); + Work8 &= APURegisters.YA.B.A; + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu0F () +{ +// BRK + +#if 0 + STOP ("BRK"); +#else + PushW (IAPU.PC + 1 - IAPU.RAM); + S9xAPUPackStatus (); + Push (APURegisters.P); + APUSetBreak (); + APUClearInterrupt (); + IAPU.PC = IAPU.RAM + S9xAPUGetByte(0xffde) + (S9xAPUGetByte(0xffdf)<<8); +#endif +} + +void ApuEF () +{ +// SLEEP + if(!(APU.Flags & HALTED_FLAG)) WARN("SLEEP"); + APU.Flags |= HALTED_FLAG; + APU.TimerEnabled[0] = APU.TimerEnabled[1] = APU.TimerEnabled[2] = FALSE; + IAPU.APUExecuting = FALSE; +} + +void ApuFF () +{ +// STOP + if(!(APU.Flags & HALTED_FLAG)) WARN("STOP"); + APU.Flags |= HALTED_FLAG; + APU.TimerEnabled[0] = APU.TimerEnabled[1] = APU.TimerEnabled[2] = FALSE; + IAPU.APUExecuting = FALSE; +} + +void Apu10 () +{ +// BPL + Relative (); + if (!APUCheckNegative ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void Apu30 () +{ +// BMI + Relative (); + if (APUCheckNegative ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void Apu90 () +{ +// BCC + Relative (); + if (!APUCheckCarry ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void ApuB0 () +{ +// BCS + Relative (); + if (APUCheckCarry ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void ApuD0 () +{ +// BNE + Relative (); + if (!APUCheckZero ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void ApuF0 () +{ +// BEQ + Relative (); + if (APUCheckZero ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 2; +} + +void Apu50 () +{ +// BVC + Relative (); + if (!APUCheckOverflow ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + } + else + IAPU.PC += 2; +} + +void Apu70 () +{ +// BVS + Relative (); + if (APUCheckOverflow ()) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + } + else + IAPU.PC += 2; +} + +void Apu2F () +{ +// BRA + Relative (); + IAPU.PC = IAPU.RAM + (uint16) Int16; +} + +void Apu80 () +{ +// SETC + APUSetCarry (); + IAPU.PC++; +} + +void ApuED () +{ +// NOTC + IAPU._Carry ^= 1; + IAPU.PC++; +} + +void Apu40 () +{ +// SETP + APUSetDirectPage (); + IAPU.DirectPage = IAPU.RAM + 0x100; + IAPU.PC++; +} + +void Apu1A () +{ +// DECW dp + Work16 = S9xAPUGetByteZ (OP1) + (S9xAPUGetByteZ (OP1 + 1) << 8); + Work16--; + S9xAPUSetByteZ ((uint8) Work16, OP1); + S9xAPUSetByteZ (Work16 >> 8, OP1 + 1); + APUSetZN16 (Work16); + IAPU.PC += 2; +} + +void Apu5A () +{ +// CMPW YA,dp + Work16 = S9xAPUGetByteZ (OP1) + (S9xAPUGetByteZ (OP1 + 1) << 8); + Int32 = (int32) APURegisters.YA.W - (int32) Work16; + IAPU._Carry = Int32 >= 0; + APUSetZN16 ((uint16) Int32); + IAPU.PC += 2; +} + +void Apu3A () +{ +// INCW dp + Work16 = S9xAPUGetByteZ (OP1) + (S9xAPUGetByteZ (OP1 + 1) << 8); + Work16++; + S9xAPUSetByteZ ((uint8) Work16, OP1); + S9xAPUSetByteZ (Work16 >> 8, OP1 + 1); + APUSetZN16 (Work16); + IAPU.PC += 2; +} + +void Apu7A () +{ +// ADDW YA,dp + Work16 = S9xAPUGetByteZ (OP1) + (S9xAPUGetByteZ (OP1 + 1) << 8); + Work32 = (uint32) APURegisters.YA.W + Work16; + IAPU._Carry = Work32 >= 0x10000; + if (~(APURegisters.YA.W ^ Work16) & (Work16 ^ (uint16) Work32) & 0x8000) + APUSetOverflow (); + else + APUClearOverflow (); + APUClearHalfCarry (); + if((APURegisters.YA.W ^ Work16 ^ (uint16) Work32) & 0x1000) + APUSetHalfCarry (); + APURegisters.YA.W = (uint16) Work32; + APUSetZN16 (APURegisters.YA.W); + IAPU.PC += 2; +} + +void Apu9A () +{ +// SUBW YA,dp + Work16 = S9xAPUGetByteZ (OP1) + (S9xAPUGetByteZ (OP1 + 1) << 8); + Int32 = (int32) APURegisters.YA.W - (int32) Work16; + APUClearHalfCarry (); + IAPU._Carry = Int32 >= 0; + if (((APURegisters.YA.W ^ Work16) & 0x8000) && + ((APURegisters.YA.W ^ (uint16) Int32) & 0x8000)) + APUSetOverflow (); + else + APUClearOverflow (); + APUSetHalfCarry (); + if((APURegisters.YA.W ^ Work16 ^ (uint16) Int32) & 0x1000) + APUClearHalfCarry (); + APURegisters.YA.W = (uint16) Int32; + APUSetZN16 (APURegisters.YA.W); + IAPU.PC += 2; +} + +void ApuBA () +{ +// MOVW YA,dp + APURegisters.YA.B.A = S9xAPUGetByteZ (OP1); + APURegisters.YA.B.Y = S9xAPUGetByteZ (OP1 + 1); + APUSetZN16 (APURegisters.YA.W); + IAPU.PC += 2; +} + +void ApuDA () +{ +// MOVW dp,YA + S9xAPUSetByteZ (APURegisters.YA.B.A, OP1); + S9xAPUSetByteZ (APURegisters.YA.B.Y, OP1 + 1); + IAPU.PC += 2; +} + +void Apu64 () +{ +// CMP A,dp + Work8 = S9xAPUGetByteZ (OP1); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu65 () +{ +// CMP A,abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu66 () +{ +// CMP A,(X) + Work8 = S9xAPUGetByteZ (APURegisters.X); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC++; +} + +void Apu67 () +{ +// CMP A,(dp+X) + IndexedXIndirect (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu68 () +{ +// CMP A,#00 + Work8 = OP1; + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu69 () +{ +// CMP dp(dest), dp(src) + W1 = S9xAPUGetByteZ (OP1); + Work8 = S9xAPUGetByteZ (OP2); + CMP (Work8, W1); + IAPU.PC += 3; +} + +void Apu74 () +{ +// CMP A, dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu75 () +{ +// CMP A,abs+X + AbsoluteX (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu76 () +{ +// CMP A, abs+Y + AbsoluteY (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu77 () +{ +// CMP A,(dp)+Y + IndirectIndexedY (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu78 () +{ +// CMP dp,#00 + Work8 = OP1; + W1 = S9xAPUGetByteZ (OP2); + CMP (W1, Work8); + IAPU.PC += 3; +} + +void Apu79 () +{ +// CMP (X),(Y) + W1 = S9xAPUGetByteZ (APURegisters.X); + Work8 = S9xAPUGetByteZ (APURegisters.YA.B.Y); + CMP (W1, Work8); + IAPU.PC++; +} + +void Apu1E () +{ +// CMP X,abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.X, Work8); + IAPU.PC += 3; +} + +void Apu3E () +{ +// CMP X,dp + Work8 = S9xAPUGetByteZ (OP1); + CMP (APURegisters.X, Work8); + IAPU.PC += 2; +} + +void ApuC8 () +{ +// CMP X,#00 + CMP (APURegisters.X, OP1); + IAPU.PC += 2; +} + +void Apu5E () +{ +// CMP Y,abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + CMP (APURegisters.YA.B.Y, Work8); + IAPU.PC += 3; +} + +void Apu7E () +{ +// CMP Y,dp + Work8 = S9xAPUGetByteZ (OP1); + CMP (APURegisters.YA.B.Y, Work8); + IAPU.PC += 2; +} + +void ApuAD () +{ +// CMP Y,#00 + Work8 = OP1; + CMP (APURegisters.YA.B.Y, Work8); + IAPU.PC += 2; +} + +void Apu1F () +{ +// JMP (abs+X) + Absolute (); + IAPU.PC = IAPU.RAM + S9xAPUGetByte (IAPU.Address + APURegisters.X) + + (S9xAPUGetByte (IAPU.Address + APURegisters.X + 1) << 8); +} + +void Apu5F () +{ +// JMP abs + Absolute (); + IAPU.PC = IAPU.RAM + IAPU.Address; +} + +void Apu20 () +{ +// CLRP + APUClearDirectPage (); + IAPU.DirectPage = IAPU.RAM; + IAPU.PC++; +} + +void Apu60 () +{ +// CLRC + APUClearCarry (); + IAPU.PC++; +} + +void ApuE0 () +{ +// CLRV + APUClearHalfCarry (); + APUClearOverflow (); + IAPU.PC++; +} + +void Apu24 () +{ +// AND A,dp + APURegisters.YA.B.A &= S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu25 () +{ +// AND A,abs + Absolute (); + APURegisters.YA.B.A &= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu26 () +{ +// AND A,(X) + APURegisters.YA.B.A &= S9xAPUGetByteZ (APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu27 () +{ +// AND A,(dp+X) + IndexedXIndirect (); + APURegisters.YA.B.A &= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu28 () +{ +// AND A,#00 + APURegisters.YA.B.A &= OP1; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu29 () +{ +// AND dp(dest),dp(src) + Work8 = S9xAPUGetByteZ (OP1); + Work8 &= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu34 () +{ +// AND A,dp+X + APURegisters.YA.B.A &= S9xAPUGetByteZ (OP1 + APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu35 () +{ +// AND A,abs+X + AbsoluteX (); + APURegisters.YA.B.A &= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu36 () +{ +// AND A,abs+Y + AbsoluteY (); + APURegisters.YA.B.A &= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu37 () +{ +// AND A,(dp)+Y + IndirectIndexedY (); + APURegisters.YA.B.A &= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu38 () +{ +// AND dp,#00 + Work8 = OP1; + Work8 &= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu39 () +{ +// AND (X),(Y) + Work8 = S9xAPUGetByteZ (APURegisters.X) & S9xAPUGetByteZ (APURegisters.YA.B.Y); + APUSetZN8 (Work8); + S9xAPUSetByteZ (Work8, APURegisters.X); + IAPU.PC++; +} + +void Apu2B () +{ +// ROL dp + Work8 = S9xAPUGetByteZ (OP1); + ROL (Work8); + S9xAPUSetByteZ (Work8, OP1); + IAPU.PC += 2; +} + +void Apu2C () +{ +// ROL abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + ROL (Work8); + S9xAPUSetByte (Work8, IAPU.Address); + IAPU.PC += 3; +} + +void Apu3B () +{ +// ROL dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + ROL (Work8); + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void Apu3C () +{ +// ROL A + ROL (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu2E () +{ +// CBNE dp,rel + Work8 = OP1; + Relative2 (); + + if (S9xAPUGetByteZ (Work8) != APURegisters.YA.B.A) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 3; +} + +void ApuDE () +{ +// CBNE dp+X,rel + Work8 = OP1 + APURegisters.X; + Relative2 (); + + if (S9xAPUGetByteZ (Work8) != APURegisters.YA.B.A) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + APUShutdown (); + } + else + IAPU.PC += 3; +} + +void Apu3D () +{ +// INC X + APURegisters.X++; + APUSetZN8 (APURegisters.X); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void ApuFC () +{ +// INC Y + APURegisters.YA.B.Y++; + APUSetZN8 (APURegisters.YA.B.Y); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void Apu1D () +{ +// DEC X + APURegisters.X--; + APUSetZN8 (APURegisters.X); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void ApuDC () +{ +// DEC Y + APURegisters.YA.B.Y--; + APUSetZN8 (APURegisters.YA.B.Y); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void ApuAB () +{ +// INC dp + Work8 = S9xAPUGetByteZ (OP1) + 1; + S9xAPUSetByteZ (Work8, OP1); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 2; +} + +void ApuAC () +{ +// INC abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address) + 1; + S9xAPUSetByte (Work8, IAPU.Address); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 3; +} + +void ApuBB () +{ +// INC dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X) + 1; + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 2; +} + +void ApuBC () +{ +// INC A + APURegisters.YA.B.A++; + APUSetZN8 (APURegisters.YA.B.A); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void Apu8B () +{ +// DEC dp + Work8 = S9xAPUGetByteZ (OP1) - 1; + S9xAPUSetByteZ (Work8, OP1); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 2; +} + +void Apu8C () +{ +// DEC abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address) - 1; + S9xAPUSetByte (Work8, IAPU.Address); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 3; +} + +void Apu9B () +{ +// DEC dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X) - 1; + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + APUSetZN8 (Work8); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC += 2; +} + +void Apu9C () +{ +// DEC A + APURegisters.YA.B.A--; + APUSetZN8 (APURegisters.YA.B.A); + +#ifdef SPC700_SHUTDOWN + IAPU.WaitCounter++; +#endif + + IAPU.PC++; +} + +void Apu44 () +{ +// EOR A,dp + APURegisters.YA.B.A ^= S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu45 () +{ +// EOR A,abs + Absolute (); + APURegisters.YA.B.A ^= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu46 () +{ +// EOR A,(X) + APURegisters.YA.B.A ^= S9xAPUGetByteZ (APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu47 () +{ +// EOR A,(dp+X) + IndexedXIndirect (); + APURegisters.YA.B.A ^= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu48 () +{ +// EOR A,#00 + APURegisters.YA.B.A ^= OP1; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu49 () +{ +// EOR dp(dest),dp(src) + Work8 = S9xAPUGetByteZ (OP1); + Work8 ^= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu54 () +{ +// EOR A,dp+X + APURegisters.YA.B.A ^= S9xAPUGetByteZ (OP1 + APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu55 () +{ +// EOR A,abs+X + AbsoluteX (); + APURegisters.YA.B.A ^= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu56 () +{ +// EOR A,abs+Y + AbsoluteY (); + APURegisters.YA.B.A ^= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void Apu57 () +{ +// EOR A,(dp)+Y + IndirectIndexedY (); + APURegisters.YA.B.A ^= S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void Apu58 () +{ +// EOR dp,#00 + Work8 = OP1; + Work8 ^= S9xAPUGetByteZ (OP2); + S9xAPUSetByteZ (Work8, OP2); + APUSetZN8 (Work8); + IAPU.PC += 3; +} + +void Apu59 () +{ +// EOR (X),(Y) + Work8 = S9xAPUGetByteZ (APURegisters.X) ^ S9xAPUGetByteZ (APURegisters.YA.B.Y); + APUSetZN8 (Work8); + S9xAPUSetByteZ (Work8, APURegisters.X); + IAPU.PC++; +} + +void Apu4B () +{ +// LSR dp + Work8 = S9xAPUGetByteZ (OP1); + LSR (Work8); + S9xAPUSetByteZ (Work8, OP1); + IAPU.PC += 2; +} + +void Apu4C () +{ +// LSR abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + LSR (Work8); + S9xAPUSetByte (Work8, IAPU.Address); + IAPU.PC += 3; +} + +void Apu5B () +{ +// LSR dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + LSR (Work8); + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void Apu5C () +{ +// LSR A + LSR (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu7D () +{ +// MOV A,X + APURegisters.YA.B.A = APURegisters.X; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuDD () +{ +// MOV A,Y + APURegisters.YA.B.A = APURegisters.YA.B.Y; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu5D () +{ +// MOV X,A + APURegisters.X = APURegisters.YA.B.A; + APUSetZN8 (APURegisters.X); + IAPU.PC++; +} + +void ApuFD () +{ +// MOV Y,A + APURegisters.YA.B.Y = APURegisters.YA.B.A; + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC++; +} + +void Apu9D () +{ +//MOV X,SP + APURegisters.X = APURegisters.S; + APUSetZN8 (APURegisters.X); + IAPU.PC++; +} + +void ApuBD () +{ +// MOV SP,X + APURegisters.S = APURegisters.X; + IAPU.PC++; +} + +void Apu6B () +{ +// ROR dp + Work8 = S9xAPUGetByteZ (OP1); + ROR (Work8); + S9xAPUSetByteZ (Work8, OP1); + IAPU.PC += 2; +} + +void Apu6C () +{ +// ROR abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + ROR (Work8); + S9xAPUSetByte (Work8, IAPU.Address); + IAPU.PC += 3; +} + +void Apu7B () +{ +// ROR dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + ROR (Work8); + S9xAPUSetByteZ (Work8, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void Apu7C () +{ +// ROR A + ROR (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu6E () +{ +// DBNZ dp,rel + Work8 = OP1; + Relative2 (); + W1 = S9xAPUGetByteZ (Work8) - 1; + S9xAPUSetByteZ (W1, Work8); + if (W1 != 0) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + } + else + IAPU.PC += 3; +} + +void ApuFE () +{ +// DBNZ Y,rel + Relative (); + APURegisters.YA.B.Y--; + if (APURegisters.YA.B.Y != 0) + { + IAPU.PC = IAPU.RAM + (uint16) Int16; + APU.Cycles += IAPU.TwoCycles; + } + else + IAPU.PC += 2; +} + +void Apu6F () +{ +// RET + PopW (APURegisters.PC); + IAPU.PC = IAPU.RAM + APURegisters.PC; +} + +void Apu7F () +{ +// RETI + // STOP ("RETI"); + Pop (APURegisters.P); + S9xAPUUnpackStatus (); + PopW (APURegisters.PC); + IAPU.PC = IAPU.RAM + APURegisters.PC; +} + +void Apu84 () +{ +// ADC A,dp + Work8 = S9xAPUGetByteZ (OP1); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu85 () +{ +// ADC A, abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu86 () +{ +// ADC A,(X) + Work8 = S9xAPUGetByteZ (APURegisters.X); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC++; +} + +void Apu87 () +{ +// ADC A,(dp+X) + IndexedXIndirect (); + Work8 = S9xAPUGetByte (IAPU.Address); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu88 () +{ +// ADC A,#00 + Work8 = OP1; + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu89 () +{ +// ADC dp(dest),dp(src) + Work8 = S9xAPUGetByteZ (OP1); + W1 = S9xAPUGetByteZ (OP2); + ADC (W1, Work8); + S9xAPUSetByteZ (W1, OP2); + IAPU.PC += 3; +} + +void Apu94 () +{ +// ADC A,dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu95 () +{ +// ADC A, abs+X + AbsoluteX (); + Work8 = S9xAPUGetByte (IAPU.Address); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu96 () +{ +// ADC A, abs+Y + AbsoluteY (); + Work8 = S9xAPUGetByte (IAPU.Address); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void Apu97 () +{ +// ADC A, (dp)+Y + IndirectIndexedY (); + Work8 = S9xAPUGetByte (IAPU.Address); + ADC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void Apu98 () +{ +// ADC dp,#00 + Work8 = OP1; + W1 = S9xAPUGetByteZ (OP2); + ADC (W1, Work8); + S9xAPUSetByteZ (W1, OP2); + IAPU.PC += 3; +} + +void Apu99 () +{ +// ADC (X),(Y) + W1 = S9xAPUGetByteZ (APURegisters.X); + Work8 = S9xAPUGetByteZ (APURegisters.YA.B.Y); + ADC (W1, Work8); + S9xAPUSetByteZ (W1, APURegisters.X); + IAPU.PC++; +} + +void Apu8D () +{ +// MOV Y,#00 + APURegisters.YA.B.Y = OP1; + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC += 2; +} + +void Apu8F () +{ +// MOV dp,#00 + Work8 = OP1; + S9xAPUSetByteZ (Work8, OP2); + IAPU.PC += 3; +} + +void Apu9E () +{ +// DIV YA,X + if((APURegisters.X&0xf)<=(APURegisters.YA.B.Y&0x0f)){ + APUSetHalfCarry(); + } else { + APUClearHalfCarry(); + } + uint32 yva, x, i; + yva = APURegisters.YA.W; + x = APURegisters.X << 9; + for(i=0; i<9; i++){ + yva<<=1; if(yva&0x20000) yva=(yva&0x1ffff)|1; + if(yva>=x) yva^=1; + if(yva&1) yva=(yva-x)&0x1ffff; + } + if(yva&0x100){ + APUSetOverflow(); + } else { + APUClearOverflow(); + } + APURegisters.YA.B.Y = (yva>>9)&0xff; + APURegisters.YA.B.A = yva&0xff; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void Apu9F () +{ +// XCN A + APURegisters.YA.B.A = (APURegisters.YA.B.A >> 4) | (APURegisters.YA.B.A << 4); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuA4 () +{ +// SBC A, dp + Work8 = S9xAPUGetByteZ (OP1); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void ApuA5 () +{ +// SBC A, abs + Absolute (); + Work8 = S9xAPUGetByte (IAPU.Address); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void ApuA6 () +{ +// SBC A, (X) + Work8 = S9xAPUGetByteZ (APURegisters.X); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC++; +} + +void ApuA7 () +{ +// SBC A,(dp+X) + IndexedXIndirect (); + Work8 = S9xAPUGetByte (IAPU.Address); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void ApuA8 () +{ +// SBC A,#00 + Work8 = OP1; + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void ApuA9 () +{ +// SBC dp(dest), dp(src) + Work8 = S9xAPUGetByteZ (OP1); + W1 = S9xAPUGetByteZ (OP2); + SBC (W1, Work8); + S9xAPUSetByteZ (W1, OP2); + IAPU.PC += 3; +} + +void ApuB4 () +{ +// SBC A, dp+X + Work8 = S9xAPUGetByteZ (OP1 + APURegisters.X); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void ApuB5 () +{ +// SBC A,abs+X + AbsoluteX (); + Work8 = S9xAPUGetByte (IAPU.Address); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void ApuB6 () +{ +// SBC A,abs+Y + AbsoluteY (); + Work8 = S9xAPUGetByte (IAPU.Address); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 3; +} + +void ApuB7 () +{ +// SBC A,(dp)+Y + IndirectIndexedY (); + Work8 = S9xAPUGetByte (IAPU.Address); + SBC (APURegisters.YA.B.A, Work8); + IAPU.PC += 2; +} + +void ApuB8 () +{ +// SBC dp,#00 + Work8 = OP1; + W1 = S9xAPUGetByteZ (OP2); + SBC (W1, Work8); + S9xAPUSetByteZ (W1, OP2); + IAPU.PC += 3; +} + +void ApuB9 () +{ +// SBC (X),(Y) + W1 = S9xAPUGetByteZ (APURegisters.X); + Work8 = S9xAPUGetByteZ (APURegisters.YA.B.Y); + SBC (W1, Work8); + S9xAPUSetByteZ (W1, APURegisters.X); + IAPU.PC++; +} + +void ApuAF () +{ +// MOV (X)+, A + S9xAPUSetByteZ (APURegisters.YA.B.A, APURegisters.X++); + IAPU.PC++; +} + +void ApuBE () +{ +// DAS + if (APURegisters.YA.B.A > 0x99 || !IAPU._Carry) { + APURegisters.YA.B.A -= 0x60; + APUClearCarry (); + } + else { APUSetCarry (); } + if ((APURegisters.YA.B.A & 0x0f) > 9 || !APUCheckHalfCarry()) + { + APURegisters.YA.B.A -= 6; + } + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuBF () +{ +// MOV A,(X)+ + APURegisters.YA.B.A = S9xAPUGetByteZ (APURegisters.X++); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuC0 () +{ +// DI + APUClearInterrupt (); + IAPU.PC++; +} + +void ApuA0 () +{ +// EI + APUSetInterrupt (); + IAPU.PC++; +} + +void ApuC4 () +{ +// MOV dp,A + S9xAPUSetByteZ (APURegisters.YA.B.A, OP1); + IAPU.PC += 2; +} + +void ApuC5 () +{ +// MOV abs,A + Absolute (); + S9xAPUSetByte (APURegisters.YA.B.A, IAPU.Address); + IAPU.PC += 3; +} + +void ApuC6 () +{ +// MOV (X), A + S9xAPUSetByteZ (APURegisters.YA.B.A, APURegisters.X); + IAPU.PC++; +} + +void ApuC7 () +{ +// MOV (dp+X),A + IndexedXIndirect (); + S9xAPUSetByte (APURegisters.YA.B.A, IAPU.Address); + IAPU.PC += 2; +} + +void ApuC9 () +{ +// MOV abs,X + Absolute (); + S9xAPUSetByte (APURegisters.X, IAPU.Address); + IAPU.PC += 3; +} + +void ApuCB () +{ +// MOV dp,Y + S9xAPUSetByteZ (APURegisters.YA.B.Y, OP1); + IAPU.PC += 2; +} + +void ApuCC () +{ +// MOV abs,Y + Absolute (); + S9xAPUSetByte (APURegisters.YA.B.Y, IAPU.Address); + IAPU.PC += 3; +} + +void ApuCD () +{ +// MOV X,#00 + APURegisters.X = OP1; + APUSetZN8 (APURegisters.X); + IAPU.PC += 2; +} + +void ApuCF () +{ +// MUL YA + APURegisters.YA.W = (uint16) APURegisters.YA.B.A * APURegisters.YA.B.Y; + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC++; +} + +void ApuD4 () +{ +// MOV dp+X, A + S9xAPUSetByteZ (APURegisters.YA.B.A, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void ApuD5 () +{ +// MOV abs+X,A + AbsoluteX (); + S9xAPUSetByte (APURegisters.YA.B.A, IAPU.Address); + IAPU.PC += 3; +} + +void ApuD6 () +{ +// MOV abs+Y,A + AbsoluteY (); + S9xAPUSetByte (APURegisters.YA.B.A, IAPU.Address); + IAPU.PC += 3; +} + +void ApuD7 () +{ +// MOV (dp)+Y,A + IndirectIndexedY (); + S9xAPUSetByte (APURegisters.YA.B.A, IAPU.Address); + IAPU.PC += 2; +} + +void ApuD8 () +{ +// MOV dp,X + S9xAPUSetByteZ (APURegisters.X, OP1); + IAPU.PC += 2; +} + +void ApuD9 () +{ +// MOV dp+Y,X + S9xAPUSetByteZ (APURegisters.X, OP1 + APURegisters.YA.B.Y); + IAPU.PC += 2; +} + +void ApuDB () +{ +// MOV dp+X,Y + S9xAPUSetByteZ (APURegisters.YA.B.Y, OP1 + APURegisters.X); + IAPU.PC += 2; +} + +void ApuDF () +{ +// DAA + if (APURegisters.YA.B.A > 0x99 || IAPU._Carry) + { + APURegisters.YA.B.A += 0x60; + APUSetCarry (); + } + else { APUClearCarry (); } + if ((APURegisters.YA.B.A & 0x0f) > 9 || APUCheckHalfCarry()) + { + APURegisters.YA.B.A += 6; + //APUSetHalfCarry (); Intel procs do this, but this is a Sony proc... + } + //else { APUClearHalfCarry (); } ditto as above + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuE4 () +{ +// MOV A, dp + APURegisters.YA.B.A = S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void ApuE5 () +{ +// MOV A,abs + Absolute (); + APURegisters.YA.B.A = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void ApuE6 () +{ +// MOV A,(X) + APURegisters.YA.B.A = S9xAPUGetByteZ (APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC++; +} + +void ApuE7 () +{ +// MOV A,(dp+X) + IndexedXIndirect (); + APURegisters.YA.B.A = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void ApuE8 () +{ +// MOV A,#00 + APURegisters.YA.B.A = OP1; + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void ApuE9 () +{ +// MOV X, abs + Absolute (); + APURegisters.X = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.X); + IAPU.PC += 3; +} + +void ApuEB () +{ +// MOV Y,dp + APURegisters.YA.B.Y = S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC += 2; +} + +void ApuEC () +{ +// MOV Y,abs + Absolute (); + APURegisters.YA.B.Y = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC += 3; +} + +void ApuF4 () +{ +// MOV A, dp+X + APURegisters.YA.B.A = S9xAPUGetByteZ (OP1 + APURegisters.X); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void ApuF5 () +{ +// MOV A, abs+X + AbsoluteX (); + APURegisters.YA.B.A = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void ApuF6 () +{ +// MOV A, abs+Y + AbsoluteY (); + APURegisters.YA.B.A = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 3; +} + +void ApuF7 () +{ +// MOV A, (dp)+Y + IndirectIndexedY (); + APURegisters.YA.B.A = S9xAPUGetByte (IAPU.Address); + APUSetZN8 (APURegisters.YA.B.A); + IAPU.PC += 2; +} + +void ApuF8 () +{ +// MOV X,dp + APURegisters.X = S9xAPUGetByteZ (OP1); + APUSetZN8 (APURegisters.X); + IAPU.PC += 2; +} + +void ApuF9 () +{ +// MOV X,dp+Y + APURegisters.X = S9xAPUGetByteZ (OP1 + APURegisters.YA.B.Y); + APUSetZN8 (APURegisters.X); + IAPU.PC += 2; +} + +void ApuFA () +{ +// MOV dp(dest),dp(src) + S9xAPUSetByteZ (S9xAPUGetByteZ (OP1), OP2); + IAPU.PC += 3; +} + +void ApuFB () +{ +// MOV Y,dp+X + APURegisters.YA.B.Y = S9xAPUGetByteZ (OP1 + APURegisters.X); + APUSetZN8 (APURegisters.YA.B.Y); + IAPU.PC += 2; +} + +#ifdef NO_INLINE_SET_GET +#undef INLINE +#define INLINE +#include "apumem.h" +#endif + +void (*S9xApuOpcodes[256]) (void) = +{ + Apu00, Apu01, Apu02, Apu03, Apu04, Apu05, Apu06, Apu07, + Apu08, Apu09, Apu0A, Apu0B, Apu0C, Apu0D, Apu0E, Apu0F, + Apu10, Apu11, Apu12, Apu13, Apu14, Apu15, Apu16, Apu17, + Apu18, Apu19, Apu1A, Apu1B, Apu1C, Apu1D, Apu1E, Apu1F, + Apu20, Apu21, Apu22, Apu23, Apu24, Apu25, Apu26, Apu27, + Apu28, Apu29, Apu2A, Apu2B, Apu2C, Apu2D, Apu2E, Apu2F, + Apu30, Apu31, Apu32, Apu33, Apu34, Apu35, Apu36, Apu37, + Apu38, Apu39, Apu3A, Apu3B, Apu3C, Apu3D, Apu3E, Apu3F, + Apu40, Apu41, Apu42, Apu43, Apu44, Apu45, Apu46, Apu47, + Apu48, Apu49, Apu4A, Apu4B, Apu4C, Apu4D, Apu4E, Apu4F, + Apu50, Apu51, Apu52, Apu53, Apu54, Apu55, Apu56, Apu57, + Apu58, Apu59, Apu5A, Apu5B, Apu5C, Apu5D, Apu5E, Apu5F, + Apu60, Apu61, Apu62, Apu63, Apu64, Apu65, Apu66, Apu67, + Apu68, Apu69, Apu6A, Apu6B, Apu6C, Apu6D, Apu6E, Apu6F, + Apu70, Apu71, Apu72, Apu73, Apu74, Apu75, Apu76, Apu77, + Apu78, Apu79, Apu7A, Apu7B, Apu7C, Apu7D, Apu7E, Apu7F, + Apu80, Apu81, Apu82, Apu83, Apu84, Apu85, Apu86, Apu87, + Apu88, Apu89, Apu8A, Apu8B, Apu8C, Apu8D, Apu8E, Apu8F, + Apu90, Apu91, Apu92, Apu93, Apu94, Apu95, Apu96, Apu97, + Apu98, Apu99, Apu9A, Apu9B, Apu9C, Apu9D, Apu9E, Apu9F, + ApuA0, ApuA1, ApuA2, ApuA3, ApuA4, ApuA5, ApuA6, ApuA7, + ApuA8, ApuA9, ApuAA, ApuAB, ApuAC, ApuAD, ApuAE, ApuAF, + ApuB0, ApuB1, ApuB2, ApuB3, ApuB4, ApuB5, ApuB6, ApuB7, + ApuB8, ApuB9, ApuBA, ApuBB, ApuBC, ApuBD, ApuBE, ApuBF, + ApuC0, ApuC1, ApuC2, ApuC3, ApuC4, ApuC5, ApuC6, ApuC7, + ApuC8, ApuC9, ApuCA, ApuCB, ApuCC, ApuCD, ApuCE, ApuCF, + ApuD0, ApuD1, ApuD2, ApuD3, ApuD4, ApuD5, ApuD6, ApuD7, + ApuD8, ApuD9, ApuDA, ApuDB, ApuDC, ApuDD, ApuDE, ApuDF, + ApuE0, ApuE1, ApuE2, ApuE3, ApuE4, ApuE5, ApuE6, ApuE7, + ApuE8, ApuE9, ApuEA, ApuEB, ApuEC, ApuED, ApuEE, ApuEF, + ApuF0, ApuF1, ApuF2, ApuF3, ApuF4, ApuF5, ApuF6, ApuF7, + ApuF8, ApuF9, ApuFA, ApuFB, ApuFC, ApuFD, ApuFE, ApuFF +}; + diff --git a/source/snes9x/spc700.h b/source/snes9x/spc700.h new file mode 100644 index 0000000..2bdbe63 --- /dev/null +++ b/source/snes9x/spc700.h @@ -0,0 +1,259 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _SPC700_H_ +#define _SPC700_H_ + +#ifdef SPCTOOL +#define NO_CHANNEL_STRUCT +#include "spctool/dsp.h" +#include "spctool/spc700.h" +#include "spctool/soundmod.h" +#endif + +#define Carry 1 +#define Zero 2 +#define Interrupt 4 +#define HalfCarry 8 +#define BreakFlag 16 +#define DirectPageFlag 32 +#define Overflow 64 +#define Negative 128 + +#define APUClearCarry() (IAPU._Carry = 0) +#define APUSetCarry() (IAPU._Carry = 1) +#define APUSetInterrupt() (APURegisters.P |= Interrupt) +#define APUClearInterrupt() (APURegisters.P &= ~Interrupt) +#define APUSetHalfCarry() (APURegisters.P |= HalfCarry) +#define APUClearHalfCarry() (APURegisters.P &= ~HalfCarry) +#define APUSetBreak() (APURegisters.P |= BreakFlag) +#define APUClearBreak() (APURegisters.P &= ~BreakFlag) +#define APUSetDirectPage() (APURegisters.P |= DirectPageFlag) +#define APUClearDirectPage() (APURegisters.P &= ~DirectPageFlag) +#define APUSetOverflow() (IAPU._Overflow = 1) +#define APUClearOverflow() (IAPU._Overflow = 0) + +#define APUCheckZero() (IAPU._Zero == 0) +#define APUCheckCarry() (IAPU._Carry) +#define APUCheckInterrupt() (APURegisters.P & Interrupt) +#define APUCheckHalfCarry() (APURegisters.P & HalfCarry) +#define APUCheckBreak() (APURegisters.P & BreakFlag) +#define APUCheckDirectPage() (APURegisters.P & DirectPageFlag) +#define APUCheckOverflow() (IAPU._Overflow) +#define APUCheckNegative() (IAPU._Zero & 0x80) + +#define APUClearFlags(f) (APURegisters.P &= ~(f)) +#define APUSetFlags(f) (APURegisters.P |= (f)) +#define APUCheckFlag(f) (APURegisters.P & (f)) + +typedef union +{ +#ifdef LSB_FIRST + struct { uint8 A, Y; } B; +#else + struct { uint8 Y, A; } B; +#endif + uint16 W; +} YAndA; + +struct SAPURegisters{ + uint8 P; + YAndA YA; + uint8 X; + uint8 S; + uint16 PC; +}; + +EXTERN_C struct SAPURegisters APURegisters; + +// Needed by ILLUSION OF GAIA +//#define ONE_APU_CYCLE 14 +#define ONE_APU_CYCLE 21 + +// Needed by all games written by the software company called Human +//#define ONE_APU_CYCLE_HUMAN 17 +#define ONE_APU_CYCLE_HUMAN 21 + +// 1.953us := 1.024065.54MHz + +#ifdef SPCTOOL +EXTERN_C int32 ESPC (int32); + +#define APU_EXECUTE() \ +{ \ + int32 l = (CPU.Cycles - APU.Cycles) / 14; \ + if (l > 0) \ + { \ + l -= _EmuSPC(l); \ + APU.Cycles += l * 14; \ + } \ +} + +#else + +#ifdef DEBUGGER +#define APU_EXECUTE1() \ +{ \ + if (APU.Flags & TRACE_FLAG) \ + S9xTraceAPU ();\ + APU.Cycles += S9xAPUCycles [*IAPU.PC]; \ + (*S9xApuOpcodes[*IAPU.PC]) (); \ +} +#else +#define APU_EXECUTE1() \ +{ \ + APU.Cycles += S9xAPUCycles [*IAPU.PC]; \ + (*S9xApuOpcodes[*IAPU.PC]) (); \ +} +#endif + +#define APU_EXECUTE() \ +if (IAPU.APUExecuting) \ +{\ + while (APU.Cycles <= CPU.Cycles) \ + APU_EXECUTE1(); \ +} +#endif + +#endif + diff --git a/source/snes9x/spc7110.cpp b/source/snes9x/spc7110.cpp new file mode 100644 index 0000000..45e72cf --- /dev/null +++ b/source/snes9x/spc7110.cpp @@ -0,0 +1,2411 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +//#define SPC7110_DEBUG + +#include "spc7110.h" +#include "memmap.h" +#include +#include + +//Windows includes +#ifdef __WIN32__ +#ifndef _XBOX // chdir and getcwd not supported on Xbox hardware +#include +#define chdir _chdir +#define getcwd _getcwd +#endif +#define FREEZEFOLDER GUI.FreezeFileDir +//zinx suggested this, for *nix compatibility +#define PATH_MAX MAX_PATH +#else // Unix +#include +#include +#ifdef __MACOSX__ +const char * S9xGetSPC7110Directory(void); +#else +#define FREEZEFOLDER S9xGetDirectory (PATCH_DIR) +#endif +#endif +#include "display.h" + +#ifndef NGC +extern "C" char *osd_GetPackDir(); +#endif + +//really not needed, but usually MS adds the _ to POSIX functions, +//while *nix doesn't, so this was to "un-M$" the function. +#define splitpath _splitpath + +//not much headroom, but FEOEZ has 41 tables, I think, and SPL4 has 38. +#define MAX_TABLES 48 + +//default to using 5 megs of RAM for method 3 caching. +uint16 cacheMegs=5; + +//using function pointers to initialize cache management +void (*CleanUp7110)(void)=NULL; +void (*LoadUp7110)(char*)=&SPC7110Load; +void (*Copy7110)(void)=NULL; + +//size and offset of the pack data +//offset and size of reads from pack +typedef struct SPC7110DecompressionLocationStruct +{ + uint32 offset; + uint32 size; + uint16 used_offset; + uint16 used_len; +} Data7110; + +//this maps an index.bin table to the decompression pack +typedef struct SPC7110DecompressionIndexStruct +{ + int table; + bool is_file; + Data7110 location[256]; +} Index7110; + +//this contains all the data for the decompression pack. +typedef struct SPC7110DecompressionPackStructure +{ + uint8* binfiles[MAX_TABLES]; + Index7110 tableEnts[MAX_TABLES]; + int last_table; + int idx; + uint8 last_idx; + uint16 last_offset; +} Pack7110; + + +char pfold[9]; //hack variable for log naming (each game makes a different log) +Pack7110* decompack=NULL; //decompression pack uses a fair chunk of RAM, so dynalloc it. +SPC7110Regs s7r; //SPC7110 registers, about 33KB +S7RTC rtc_f9; //FEOEZ (and Shounen Jump no SHou) RTC +void S9xUpdateRTC (); //S-RTC function hacked to work with the RTC + +//Emulate power on state +void S9xSpc7110Init() +{ + s7r.DataRomOffset=0x00100000;//handy constant! + s7r.DataRomSize=Memory.CalculatedSize-s7r.DataRomOffset; + s7r.reg4800=0; + s7r.reg4801=0; + s7r.reg4802=0; + s7r.reg4803=0; + s7r.reg4804=0; + s7r.reg4805=0; + s7r.reg4806=0; + s7r.reg4807=0; + s7r.reg4808=0; + s7r.reg4809=0; + s7r.reg480A=0; + s7r.reg480B=0; + s7r.reg480C=0; + s7r.reg4811=0; + s7r.reg4812=0; + s7r.reg4813=0; + s7r.reg4814=0; + s7r.reg4815=0; + s7r.reg4816=0; + s7r.reg4817=0; + s7r.reg4818=0; + s7r.reg4820=0; + s7r.reg4821=0; + s7r.reg4822=0; + s7r.reg4823=0; + s7r.reg4824=0; + s7r.reg4825=0; + s7r.reg4826=0; + s7r.reg4827=0; + s7r.reg4828=0; + s7r.reg4829=0; + s7r.reg482A=0; + s7r.reg482B=0; + s7r.reg482C=0; + s7r.reg482D=0; + s7r.reg482E=0; + s7r.reg482F=0; + s7r.reg4830=0; + s7r.reg4831=0; + s7r.reg4832=1; + s7r.reg4833=2; + s7r.reg4834=0; + s7r.reg4840=0; + s7r.reg4841=0; + s7r.reg4842=0; + s7r.written=0; + s7r.offset_add=0; + s7r.AlignBy=1; + +#ifndef NGC + (*LoadUp7110)(osd_GetPackDir()); +#endif + + if(Settings.SPC7110RTC) + Settings.TurboMode=false; + + s7r.bank50Internal=0; + memset(s7r.bank50,0x00,DECOMP_BUFFER_SIZE); +} + + +//full cache decompression routine (memcpy) Method 1 +void MovePackData() +{ + //log the last entry + Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]); + if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal)) + { + log->used_len=s7r.bank50Internal; + log->used_offset=decompack->last_offset; + } + + //set up for next logging + decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8); + + decompack->last_idx=s7r.reg4804; + + //start decompression + int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801; + + //the table is a offset multiplier byte and a big-endian pointer + int j= 4*s7r.reg4804; + j+=s7r.DataRomOffset; + j+=table; + + //set proper offsetting. + if(s7r.reg480B==0) + s7r.AlignBy=0; + else + { + switch(ROM[j]) + { + case 0x03: + s7r.AlignBy=8; + break; + case 0x01: + s7r.AlignBy=2; + break; + case 0x02: + s7r.AlignBy=4; + break; + case 0x00: + default: + s7r.AlignBy=1; + break; + } + } + //note that we are still setting up for the next log. + decompack->last_offset*=s7r.AlignBy; + decompack->last_offset%=DECOMP_BUFFER_SIZE; + + //find the table + if(table!=decompack->last_table) + { + int i=0; + while(itableEnts[i].table!=table) + i++; + if(i==MAX_TABLES) + { +#ifdef _XBOX + FILE* fp=fopen("T:\\sp7err.out","a"); +#else +#ifdef __MACOSX__ + FILE* fp=fopen(S9xGetFilename(".out", DEFAULT_DIR), "a"); +#else + FILE* fp=fopen("sp7err.out","a"); +#endif +#endif + + fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804); + fclose(fp); + return; + } + decompack->idx=i; + decompack->last_table=table; + } + + //copy data + if(decompack->binfiles[decompack->idx]) + { + memcpy(s7r.bank50, + &(decompack->binfiles[decompack->idx][decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset]), + decompack->tableEnts[decompack->idx].location[s7r.reg4804].size); + } +} + + +//this is similar to the last function, but it keeps the last 5 accessed files open, +// and reads the data directly. Method 2 +void ReadPackData() +{ + static int table_age_2; + static int table_age_3; + static int table_age_4; + static int table_age_5; + + int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801; + + if(table==0) + { + table_age_2=table_age_3=table_age_4=table_age_5=MAX_TABLES; + return; + } + + if(table_age_2==0&&table_age_3==0&&table_age_4==0&&table_age_5==0) + table_age_2=table_age_3=table_age_4=table_age_5=MAX_TABLES; + Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]); + if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal)) + { + log->used_len=s7r.bank50Internal; + log->used_offset=decompack->last_offset; + } + + decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8); + + decompack->last_idx=s7r.reg4804; + + int j= 4*s7r.reg4804; + j+=s7r.DataRomOffset; + j+=table; + + if(s7r.reg480B==0) + s7r.AlignBy=0; + else + { + switch(ROM[j]) + { + case 0x03: + s7r.AlignBy=8; + break; + case 0x01: + s7r.AlignBy=2; + break; + case 0x02: + s7r.AlignBy=4; + break; + case 0x00: + default: + s7r.AlignBy=1; + break; + } + } + decompack->last_offset*=s7r.AlignBy; + decompack->last_offset%=DECOMP_BUFFER_SIZE; + if(table!=decompack->last_table) + { + int i=0; + while(itableEnts[i].table!=table) + i++; + if(i==MAX_TABLES) + { + #ifdef __MACOSX__ + FILE* fp=fopen(S9xGetFilename(".out", DEFAULT_DIR), "a"); + #else + FILE* fp=fopen("sp7err.out","a"); + #endif + fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804); + fclose(fp); + return; + } + if(i!= table_age_2 && i!= table_age_3 && i!= table_age_4 && i!= table_age_5) + { + if(table_age_5!=MAX_TABLES&&decompack->binfiles[table_age_5]) + { + fclose((FILE*)(decompack->binfiles[table_age_5])); + (decompack->binfiles[table_age_5])=NULL; + } + table_age_5=table_age_4; + table_age_4=table_age_3; + table_age_3=table_age_2; + table_age_2=decompack->idx; + + #ifdef __MACOSX__ + char name[PATH_MAX + 1], bfname[11]; + strcpy(name, S9xGetSPC7110Directory()); + sprintf(bfname, "%06X.bin", table); + strcat(name, bfname); + #else + char name[PATH_MAX]; + //open file + char drive [_MAX_DRIVE + 1]; + char dir [_MAX_DIR + 1]; + char fname [_MAX_FNAME + 1]; + char ext [_MAX_EXT + 1]; + if (strlen (FREEZEFOLDER)) + { + //splitpath (Memory.ROMFilename, drive, dir, fname, ext); + strcpy (name, FREEZEFOLDER); + strcat (name, "/"); + } + else + { + splitpath (Memory.ROMFilename, drive, dir, fname, ext); + strcpy(name, drive); + //strcat(filename, "\\"); + strcat(name, dir); + } + strcat(name, pfold); + char bfname[11]; + sprintf(bfname, "%06X.bin", table); + strcat(name, "/"); + strcat(name, bfname); + #endif + + decompack->binfiles[i]=(uint8*)fopen(name, "rb"); + } + else + { + //fix tables in this case + if(table_age_5==i) + { + table_age_5=table_age_4; + table_age_4=table_age_3; + table_age_3=table_age_2; + table_age_2=decompack->idx; + } + if(table_age_4==i) + { + table_age_4=table_age_3; + table_age_3=table_age_2; + table_age_2=decompack->idx; + } + if(table_age_3==i) + { + table_age_3=table_age_2; + table_age_2=decompack->idx; + } + if(table_age_2==i) + { + table_age_2=decompack->idx; + } + } + decompack->idx=i; + decompack->last_table=table; + } + //do read here. + if(decompack->binfiles[decompack->idx]) + { + fseek((FILE*)(decompack->binfiles[decompack->idx]), decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset, 0); + fread(s7r.bank50,1, (decompack->tableEnts[decompack->idx].location[s7r.reg4804].size), (FILE*)(decompack->binfiles[decompack->idx])); + } +} + +//Cache Method 3: some entries are cached, others are file handles. +//use is_file to distinguish. +void GetPackData() +{ + Data7110* log=&(decompack->tableEnts[decompack->idx].location[decompack->last_idx]); + if((log->used_len+log->used_offset)<(decompack->last_offset+(unsigned short)s7r.bank50Internal)) + { + log->used_len=s7r.bank50Internal; + log->used_offset=decompack->last_offset; + } + + decompack->last_offset=(s7r.reg4805)|(s7r.reg4806<<8); + + decompack->last_idx=s7r.reg4804; + int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801; + + int j= 4*s7r.reg4804; + j+=s7r.DataRomOffset; + j+=table; + + if(s7r.reg480B==0) + s7r.AlignBy=0; + else + { + switch(ROM[j]) + { + case 0x03: + s7r.AlignBy=8; + break; + case 0x01: + s7r.AlignBy=2; + break; + case 0x02: + s7r.AlignBy=4; + break; + case 0x00: + default: + s7r.AlignBy=1; + break; + } + } + decompack->last_offset*=s7r.AlignBy; + decompack->last_offset%=DECOMP_BUFFER_SIZE; + if(table!=decompack->last_table) + { + int i=0; + while(itableEnts[i].table!=table) + i++; + if(i==MAX_TABLES) + { + #ifdef __MACOSX__ + FILE* fp=fopen(S9xGetFilename(".out", DEFAULT_DIR), "a"); + #else + FILE* fp=fopen("sp7err.out","a"); + #endif + fprintf(fp, "Table Entry %06X:%02X not found\n", table, s7r.reg4804); + fclose(fp); + return; + } + decompack->idx=i; + decompack->last_table=table; + } + if(decompack->binfiles[decompack->idx]) + { + if(decompack->tableEnts[decompack->idx].is_file) + { + fseek((FILE*)decompack->binfiles[decompack->idx], decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset, 0); + fread(s7r.bank50,1, (decompack->tableEnts[decompack->idx].location[s7r.reg4804].size), (FILE*)(decompack->binfiles[decompack->idx])); + } + else + { + memcpy(s7r.bank50, + &(decompack->binfiles[decompack->idx][decompack->tableEnts[decompack->idx].location[s7r.reg4804].offset]), + decompack->tableEnts[decompack->idx].location[s7r.reg4804].size); + } + } +} + +extern "C"{ +//reads SPC7110 and RTC registers. +uint8 S9xGetSPC7110(uint16 Address) +{ +#ifdef SPC7110_DEBUG + printf("%04X read\n", Address); +#endif + switch (Address) + { + //decompressed data read port. decrements 4809-A (with wrap) + //4805-6 is the offset into the bank + //AlignBy is set (afaik) at decompression time, and is the offset multiplier + //bank50internal is an internal pointer to the actual byte to read. + //so you read from offset*multiplier + bank50internal + //the offset registers cannot be incremented due to the offset multiplier. + case 0x4800: + { + unsigned short count=s7r.reg4809|(s7r.reg480A<<8); + uint32 i, j; + j=(s7r.reg4805|(s7r.reg4806<<8)); + j*=s7r.AlignBy; + i=j; + if(count >0) + count--; + else count = 0xFFFF; + s7r.reg4809=0x00ff&count; + s7r.reg480A=(0xff00&count)>>8; + i+=s7r.bank50Internal; + i%=DECOMP_BUFFER_SIZE; + s7r.reg4800=s7r.bank50[i]; + + s7r.bank50Internal++; + s7r.bank50Internal%=DECOMP_BUFFER_SIZE; +#ifdef SPC7110_DEBUG + printf("Returned %02X\n", s7r.reg4800); +#endif + } + return s7r.reg4800; + //table register low + case 0x4801: return s7r.reg4801; + //table register middle + case 0x4802: return s7r.reg4802; + //table register high + case 0x4803: return s7r.reg4803; + //index of pointer in table (each entry is 4 bytes) + case 0x4804: return s7r.reg4804; + //offset register low + case 0x4805: return s7r.reg4805; + //offset register high + case 0x4806: return s7r.reg4806; + //DMA channel (not that I see this usually set, + //regardless of what channel DMA is on) + case 0x4807: return s7r.reg4807; + //C r/w option, unknown, defval:00 is what Dark Force says + //afaict, Snes9x doesn't use this at all. + case 0x4808: return s7r.reg4808; + //C-Length low + //counts down the number of bytes left to read from the decompression buffer. + //this is set by the ROM, and wraps on bounds. + case 0x4809: return s7r.reg4809; + //C Length high + case 0x480A: return s7r.reg480A; + //Offset enable. + //if this is zero, 4805-6 are useless. Emulated by setting AlignBy to 0 + case 0x480B: + return s7r.reg480B; + //decompression finished: just emulated by switching each read. + case 0x480C: + s7r.reg480C^=0x80; + return s7r.reg480C^0x80; + + //Data access port + //reads from the data ROM (anywhere over the first 8 mbits + //behavior is complex, will document later, + //possibly missing cases, because of the number of switches in play + case 0x4810: + if(s7r.written==0) + return 0; + if((s7r.written&0x07)==0x07) + { + uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + i%=s7r.DataRomSize; + if(s7r.reg4818&0x02) + { + if(s7r.reg4818&0x08) + { + signed short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + i+=r4814; + r4814++; + s7r.reg4815=(uint8)(r4814>>8); + s7r.reg4814=(uint8)(r4814&0x00FF); + } + else + { + unsigned short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + i+=r4814; + if(r4814!=0xFFFF) + r4814++; + else r4814=0; + s7r.reg4815=(uint8)(r4814>>8); + s7r.reg4814=(uint8)(r4814&0x00FF); + + } + } + i+=s7r.DataRomOffset; + uint8 tmp=ROM[i]; + i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + + if(s7r.reg4818&0x02) + { + } + else if(s7r.reg4818&0x01) + { + if(s7r.reg4818&0x04) + { + signed short inc; + inc=(s7r.reg4817<<8)|s7r.reg4816; + + if(!(s7r.reg4818&0x10)) + i+=inc; + else + { + if(s7r.reg4818&0x08) + { + signed short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=inc; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + } + else + { + unsigned short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=inc; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + + } + } + //is signed + } + else + { + uint16 inc; + inc=(s7r.reg4817<<8)|s7r.reg4816; + if(!(s7r.reg4818&0x10)) + i+=inc; + else + { + if(s7r.reg4818&0x08) + { + signed short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=inc; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + } + else + { + unsigned short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=inc; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + + } + } + } + } + else + { + if(!(s7r.reg4818&0x10)) + i+=1; + else + { + if(s7r.reg4818&0x08) + { + signed short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=1; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + } + else + { + unsigned short r4814; + r4814=(s7r.reg4815<<8)|s7r.reg4814; + r4814+=1; + s7r.reg4815=(r4814&0xFF00)>>8; + s7r.reg4814=r4814&0xFF; + + } + } + } + +#ifdef SPC7110_DEBUG + printf("Returned %02X\n", tmp); +#endif + + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + return tmp; + } + else return 0; + //direct read address low + case 0x4811: return s7r.reg4811; + //direct read address middle + case 0x4812: return s7r.reg4812; + //direct read access high + case 0x4813: return s7r.reg4813; + //read adjust low + case 0x4814: return s7r.reg4814; + //read adjust high + case 0x4815: return s7r.reg4815; + //read increment low + case 0x4816: return s7r.reg4816; + //read increment high + case 0x4817: return s7r.reg4817; + //Data ROM command mode + //essentially, this controls the insane code of $4810 and $481A + case 0x4818: return s7r.reg4818; + //read after adjust port + //what this does, besides more nasty stuff like 4810, + //I don't know. Just assume it is a different implementation of $4810, + //if it helps your sanity + case 0x481A: + if(s7r.written==0x1F) + { + uint32 i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811); + if(s7r.reg4818&0x08) + { + short adj; + adj=((short)(s7r.reg4815<<8))|s7r.reg4814; + i+=adj; + } + else + { + uint16 adj; + adj=(s7r.reg4815<<8)|s7r.reg4814; + i+=adj; + } + + i%=s7r.DataRomSize; + i+=s7r.DataRomOffset; + uint8 tmp=ROM[i]; + i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811); + if(0x60==(s7r.reg4818&0x60)) + { + i=((s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811); + + if(!(s7r.reg4818&0x10)) + { + if(s7r.reg4818&0x08) + { + short adj; + adj=((short)(s7r.reg4815<<8))|s7r.reg4814; + i+=adj; + } + else + { + uint16 adj; + adj=(s7r.reg4815<<8)|s7r.reg4814; + i+=adj; + } + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + } + else + { + if(s7r.reg4818&0x08) + { + short adj; + adj=((short)(s7r.reg4815<<8))|s7r.reg4814; + adj+=adj; + s7r.reg4815=(adj&0xFF00)>>8; + s7r.reg4814=adj&0xFF; + } + else + { + uint16 adj; + adj=(s7r.reg4815<<8)|s7r.reg4814; + adj+=adj; + s7r.reg4815=(adj&0xFF00)>>8; + s7r.reg4814=adj&0xFF; + } + } + } +#ifdef SPC7110_DEBUG + printf("Returned %02X\n", tmp); +#endif + return tmp; + } + else return 0; + + //multiplicand low or dividend lowest + case 0x4820: return s7r.reg4820; + //multiplicand high or divdend lower + case 0x4821: return s7r.reg4821; + //dividend higher + case 0x4822: return s7r.reg4822; + //dividend highest + case 0x4823: return s7r.reg4823; + //multiplier low + case 0x4824: return s7r.reg4824; + //multiplier high + case 0x4825: return s7r.reg4825; + //divisor low + case 0x4826: return s7r.reg4826; + //divisor high + case 0x4827: return s7r.reg4827; + + //result lowest + case 0x4828: + return s7r.reg4828; + //result lower + case 0x4829: + return s7r.reg4829; + //result higher + case 0x482A: + return s7r.reg482A; + //result highest + case 0x482B: + return s7r.reg482B; + //remainder (division) low + case 0x482C: return s7r.reg482C; + //remainder (division) high + case 0x482D: return s7r.reg482D; + //signed/unsigned + case 0x482E: return s7r.reg482E; + //finished flag, emulated as an on-read toggle. + case 0x482F: + if(s7r.reg482F) + { + s7r.reg482F=0; + return 0x80; + } + return 0; + break; + + //SRAM toggle + case 0x4830: + return s7r.reg4830; + //DX bank mapping + case 0x4831: + return s7r.reg4831; + //EX bank mapping + case 0x4832: + return s7r.reg4832; + //FX bank mapping + case 0x4833: + return s7r.reg4833; + //SRAM mapping? We have no clue! + case 0x4834: + return s7r.reg4834; +//RTC enable + case 0x4840: + if(!Settings.SPC7110RTC) + return Address>>8; + return s7r.reg4840; +//command/index/value of RTC (essentially, zero unless we're in read mode + case 0x4841: + if(!Settings.SPC7110RTC) + return Address>>8; + if(rtc_f9.init) + { + S9xUpdateRTC(); + uint8 tmp=rtc_f9.reg[rtc_f9.index]; + rtc_f9.index++; + rtc_f9.index%=0x10; +#ifdef SPC7110_DEBUG + printf("$4841 returned %02X\n", tmp); +#endif + return tmp; + } + else return 0; +//RTC done flag + case 0x4842: + if(!Settings.SPC7110RTC) + return Address>>8; + s7r.reg4842^=0x80; + return s7r.reg4842^0x80; + default: +#ifdef SPC7110_DEBUG + printf("Access to Reg %04X\n", Address); +#endif + return 0x00; + } +} +} +void S9xSetSPC7110 (uint8 data, uint16 Address) +{ +#ifdef SPC7110_DEBUG + printf("%04X written to, value %02X\n", Address, data); +#endif + switch(Address) + { +//Writes to $4800 are undefined. + + //table low, middle, and high. + case 0x4801: + s7r.reg4801=data; + break; + case 0x4802: + s7r.reg4802=data; + break; + case 0x4803: + s7r.reg4803=data; + break; + + //table index (4 byte entries, bigendian with a multiplier byte) + case 0x4804: + s7r.reg4804=data; + break; + + //offset low + case 0x4805: + s7r.reg4805=data; + break; + + //offset high, starts decompression + case 0x4806: + s7r.reg4806=data; + (*Copy7110)(); + s7r.bank50Internal=0; + s7r.reg480C&=0x7F; + break; + + //DMA channel register (Is it used??) + case 0x4807: + s7r.reg4807=data; + break; + + //C r/w? I have no idea. If you get weird values written here before a bug, + //The Dumper should probably be contacted about running a test. + case 0x4808: + s7r.reg4808=data; + break; + + //C-Length low + case 0x4809: + s7r.reg4809=data; + break; + //C-Length high + case 0x480A: + s7r.reg480A=data; + break; + + //Offset enable + case 0x480B: + { + s7r.reg480B=data; + int table=(s7r.reg4803<<16)|(s7r.reg4802<<8)|s7r.reg4801; + + int j= 4*s7r.reg4804; + j+=s7r.DataRomOffset; + j+=table; + + if(s7r.reg480B==0) + s7r.AlignBy=0; + else + { + switch(ROM[j]) + { + case 0x03: + s7r.AlignBy=8; + break; + case 0x01: + s7r.AlignBy=2; + break; + case 0x02: + s7r.AlignBy=4; + break; + case 0x00: + default: + s7r.AlignBy=1; + break; + } + } +// s7r.decomp_set=true; + } + break; +//$4810 is probably read only. + + //Data port address low + case 0x4811: + s7r.reg4811=data; + s7r.written|=0x01; + break; + + //data port address middle + case 0x4812: + s7r.reg4812=data; + s7r.written|=0x02; + break; + + //data port address high + case 0x4813: + s7r.reg4813=data; + s7r.written|=0x04; + break; + + //data port adjust low (has a funky immediate increment mode) + case 0x4814: + s7r.reg4814=data; + if(s7r.reg4818&0x02) + { + if((s7r.reg4818&0x20)&&!(s7r.reg4818&0x40)) + { + s7r.offset_add|=0x01; + if(s7r.offset_add==3) + { + if(s7r.reg4818&0x10) + { + } + else + { + uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + if(s7r.reg4818&0x08) + { + i+=(signed char)s7r.reg4814; + } + else + { + i+=s7r.reg4814; + } + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + } + } + } + else if((s7r.reg4818&0x40)&&!(s7r.reg4818&0x20)) + { + s7r.offset_add|=0x01; + if(s7r.offset_add==3) + { + if(s7r.reg4818&0x10) + { + } + else + { + uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + if(s7r.reg4818&0x08) + { + short adj; + adj=((short)(s7r.reg4815<<8))|s7r.reg4814; + i+=adj; + } + else + { + uint16 adj; + adj=(s7r.reg4815<<8)|s7r.reg4814; + i+=adj; + } + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + } + } + + } + } + + s7r.written|=0x08; + break; + + //data port adjust high (has a funky immediate increment mode) + case 0x4815: + s7r.reg4815=data; + if(s7r.reg4818&0x02) + { + if(s7r.reg4818&0x20&&!(s7r.reg4818&0x40)) + { + s7r.offset_add|=0x02; + if(s7r.offset_add==3) + { + if(s7r.reg4818&0x10) + { + } + else + { + uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + + if(s7r.reg4818&0x08) + { + i+=(signed char)s7r.reg4814; + } + else + { + i+=s7r.reg4814; + } + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + } + } + } + else if(s7r.reg4818&0x40&&!(s7r.reg4818&0x20)) + { + s7r.offset_add|=0x02; + if(s7r.offset_add==3) + { + if(s7r.reg4818&0x10) + { + } + else + { + uint32 i=(s7r.reg4813<<16)|(s7r.reg4812<<8)|s7r.reg4811; + if(s7r.reg4818&0x08) + { + short adj; + adj=((short)(s7r.reg4815<<8))|s7r.reg4814; + i+=adj; + } + else + { + uint16 adj; + adj=(s7r.reg4815<<8)|s7r.reg4814; + i+=adj; + } + i%=s7r.DataRomSize; + s7r.reg4811=i&0x00FF; + s7r.reg4812=(i&0x00FF00)>>8; + s7r.reg4813=((i&0xFF0000)>>16); + } + } + } + } + s7r.written|=0x10; + break; + //data port increment low + case 0x4816: + s7r.reg4816=data; + break; + //data port increment high + case 0x4817: + s7r.reg4817=data; + break; + + //data port mode switches + //note that it starts inactive. + case 0x4818: + if((s7r.written&0x18)!=0x18) + break; + s7r.offset_add=0; + s7r.reg4818=data; + break; + + //multiplicand low or dividend lowest + case 0x4820: + s7r.reg4820=data; + break; + //multiplicand high or dividend lower + case 0x4821: + s7r.reg4821=data; + break; + //dividend higher + case 0x4822: + s7r.reg4822=data; + break; + //dividend highest + case 0x4823: + s7r.reg4823=data; + break; + //multiplier low + case 0x4824: + s7r.reg4824=data; + break; + //multiplier high (triggers operation) + case 0x4825: + s7r.reg4825=data; + if(s7r.reg482E&0x01) + { + int mul; + short m1=(short)((s7r.reg4824)|(s7r.reg4825<<8)); + short m2=(short)((s7r.reg4820)|(s7r.reg4821<<8)); + + mul=m1*m2; + s7r.reg4828=(uint8)(mul&0x000000FF); + s7r.reg4829=(uint8)((mul&0x0000FF00)>>8); + s7r.reg482A=(uint8)((mul&0x00FF0000)>>16); + s7r.reg482B=(uint8)((mul&0xFF000000)>>24); + } + else + { + uint32 mul; + uint16 m1=(uint16)((s7r.reg4824)|(s7r.reg4825<<8)); + uint16 m2=(uint16)((s7r.reg4820)|(s7r.reg4821<<8)); + + mul=m1*m2; + s7r.reg4828=(uint8)(mul&0x000000FF); + s7r.reg4829=(uint8)((mul&0x0000FF00)>>8); + s7r.reg482A=(uint8)((mul&0x00FF0000)>>16); + s7r.reg482B=(uint8)((mul&0xFF000000)>>24); + } + s7r.reg482F=0x80; + break; + //divisor low + case 0x4826: + s7r.reg4826=data; + break; + //divisor high (triggers operation) + case 0x4827: + s7r.reg4827=data; + if(s7r.reg482E&0x01) + { + int quotient; + short remainder; + int dividend=(int)(s7r.reg4820|(s7r.reg4821<<8)|(s7r.reg4822<<16)|(s7r.reg4823<<24)); + short divisor=(short)(s7r.reg4826|(s7r.reg4827<<8)); + if(divisor != 0) + { + quotient=(int)(dividend/divisor); + remainder=(short)(dividend%divisor); + } + else + { + quotient=0; + remainder=dividend&0x0000FFFF; + } + s7r.reg4828=(uint8)(quotient&0x000000FF); + s7r.reg4829=(uint8)((quotient&0x0000FF00)>>8); + s7r.reg482A=(uint8)((quotient&0x00FF0000)>>16); + s7r.reg482B=(uint8)((quotient&0xFF000000)>>24); + s7r.reg482C=(uint8)remainder&0x00FF; + s7r.reg482D=(uint8)((remainder&0xFF00)>>8); + } + else + { + uint32 quotient; + uint16 remainder; + uint32 dividend=(uint32)(s7r.reg4820|(s7r.reg4821<<8)|(s7r.reg4822<<16)|(s7r.reg4823<<24)); + uint16 divisor=(uint16)(s7r.reg4826|(s7r.reg4827<<8)); + if(divisor != 0) + { + quotient=(uint32)(dividend/divisor); + remainder=(uint16)(dividend%divisor); + } + else + { + quotient=0; + remainder=dividend&0x0000FFFF; + } + s7r.reg4828=(uint8)(quotient&0x000000FF); + s7r.reg4829=(uint8)((quotient&0x0000FF00)>>8); + s7r.reg482A=(uint8)((quotient&0x00FF0000)>>16); + s7r.reg482B=(uint8)((quotient&0xFF000000)>>24); + s7r.reg482C=(uint8)remainder&0x00FF; + s7r.reg482D=(uint8)((remainder&0xFF00)>>8); + } + s7r.reg482F=0x80; + break; + //result registers are possibly read-only + + //reset: writes here nuke the whole math unit + //Zero indicates unsigned math, resets with non-zero values turn on signed math + case 0x482E: + s7r.reg4820=s7r.reg4821=s7r.reg4822=s7r.reg4823=s7r.reg4824=s7r.reg4825=s7r.reg4826=s7r.reg4827=s7r.reg4828=s7r.reg4829=s7r.reg482A=s7r.reg482B=s7r.reg482C=s7r.reg482D=0; + s7r.reg482E=data; + break; + + //math status register possibly read only + + //SRAM toggle + case 0x4830: + Memory.SPC7110Sram(data); + s7r.reg4830=data; + break; + //Bank DX mapping + case 0x4831: + s7r.reg4831=data; + break; + //Bank EX mapping + case 0x4832: + s7r.reg4832=data; + break; + //Bank FX mapping + case 0x4833: + s7r.reg4833=data; + break; + //S-RAM mapping? who knows? + case 0x4834: + s7r.reg4834=data; + break; + //RTC Toggle + case 0x4840: + if(0==data) + { + S9xUpdateRTC(); + // rtc_f9.init=false; + // rtc_f9.index=-1; + } + if(data&0x01) + { + s7r.reg4842=0x80; + //rtc_f9.last_used=time(NULL);//???? + rtc_f9.init=false; + rtc_f9.index=-1; + } + s7r.reg4840=data; + break; + //RTC init/command/index register + case 0x4841: + if(rtc_f9.init) + { + if(-1==rtc_f9.index) + { + rtc_f9.index=data&0x0F; + break; + } + if(rtc_f9.control==0x0C) + { + rtc_f9.index=data&0x0F; + s7r.reg4842=0x80; + rtc_f9.last_used=time(NULL); + } + else + { + + if(0x0D==rtc_f9.index) + { + if(data&0x08) + { + if(rtc_f9.reg[1]<3) + { + S9xUpdateRTC(); + rtc_f9.reg[0]=0; + rtc_f9.reg[1]=0; + rtc_f9.last_used=time(NULL); + } + else + { + S9xUpdateRTC(); + rtc_f9.reg[0]=0; + rtc_f9.reg[1]=0; + rtc_f9.last_used=time(NULL)-60; + S9xUpdateRTC(); + rtc_f9.last_used=time(NULL); + } + data&=0x07; + } + if(rtc_f9.reg[0x0D]&0x01) + { + if(!(data%2)) + { + rtc_f9.reg[rtc_f9.index&0x0F]=data; + rtc_f9.last_used=time(NULL)-1; + S9xUpdateRTC(); + rtc_f9.last_used=time(NULL); + } + } + } + if(0x0F==rtc_f9.index) + { + if(data&0x01&&!(rtc_f9.reg[0x0F]&0x01)) + { + S9xUpdateRTC(); + rtc_f9.reg[0]=0; + rtc_f9.reg[1]=0; + rtc_f9.last_used=time(NULL); + } + if(data&0x02&&!(rtc_f9.reg[0x0F]&0x02)) + { + S9xUpdateRTC(); + rtc_f9.last_used=time(NULL); + } + } + rtc_f9.reg[rtc_f9.index&0x0F]=data; + s7r.reg4842=0x80; + rtc_f9.index=(rtc_f9.index+1)%0x10; + } + } + else + { + if(data==0x03||data==0x0C) + { + rtc_f9.init=true; + rtc_f9.control=data; + rtc_f9.index=-1; + } + } + break; + //writes to RTC status register aren't expected to be meaningful + default: + Address-=0x4800; + break; + //16 BIT MULTIPLIER: ($FF00) high byte, defval:00 + } +} +extern "C"{ +//emulate the SPC7110's ability to remap banks Dx, Ex, and Fx. +uint8 S9xGetSPC7110Byte(uint32 Address) +{ + uint32 i; + switch((Address&0x00F00000)>>16) + { + case 0xD0: + i=s7r.reg4831*0x00100000; + break; + case 0xE0: + i=s7r.reg4832*0x00100000; + break; + case 0xF0: + i=s7r.reg4833*0x00100000; + break; + default:i=0; + } + i+=Address&0x000FFFFF; + i+=s7r.DataRomOffset; + return ROM[i]; +} +} +/**********************************************************************************************/ +/* S9xSRTCDaysInMonth() */ +/* Return the number of days in a specific month for a certain year */ +/* copied directly for RTC functionality, separated in case of incompatibilities */ +/**********************************************************************************************/ +int S9xRTCDaysInMonth( int month, int year ) +{ + int mdays; + + switch ( month ) + { + case 2: + if ( ( year % 4 == 0 ) ) // DKJM2 only uses 199x - 22xx + mdays = 29; + else + mdays = 28; + break; + + case 4: + case 6: + case 9: + case 11: + mdays = 30; + break; + + default: // months 1,3,5,7,8,10,12 + mdays = 31; + break; + } + + return mdays; +} + + +#define DAYTICKS (60*60*24) +#define HOURTICKS (60*60) +#define MINUTETICKS 60 + + +/**********************************************************************************************/ +/* S9xUpdateRTC() */ +/* Advance the RTC time */ +/**********************************************************************************************/ + +void S9xUpdateRTC () +{ + time_t cur_systime; + long time_diff; + + // Keep track of game time by computing the number of seconds that pass on the system + // clock and adding the same number of seconds to the RTC clock structure. + + if (rtc_f9.init && 0==(rtc_f9.reg[0x0D]&0x01) && 0==(rtc_f9.reg[0x0F]&0x03)) + { + cur_systime = time (NULL); + + // This method assumes one time_t clock tick is one second + // which should work on PCs and GNU systems. + // If your tick interval is different adjust the + // DAYTICK, HOURTICK, and MINUTETICK defines + + time_diff = (long) (cur_systime - rtc_f9.last_used); + rtc_f9.last_used = cur_systime; + + if ( time_diff > 0 ) + { + int seconds; + int minutes; + int hours; + int days; + int month; + int year; + int temp_days; + + int year_hundreds; + int year_tens; + int year_ones; + + + if ( time_diff > DAYTICKS ) + { + days = time_diff / DAYTICKS; + time_diff = time_diff - days * DAYTICKS; + } + else + { + days = 0; + } + + if ( time_diff > HOURTICKS ) + { + hours = time_diff / HOURTICKS; + time_diff = time_diff - hours * HOURTICKS; + } + else + { + hours = 0; + } + + if ( time_diff > MINUTETICKS ) + { + minutes = time_diff / MINUTETICKS; + time_diff = time_diff - minutes * MINUTETICKS; + } + else + { + minutes = 0; + } + + if ( time_diff > 0 ) + { + seconds = time_diff; + } + else + { + seconds = 0; + } + + + seconds += (rtc_f9.reg[1]*10 + rtc_f9.reg[0]); + if ( seconds >= 60 ) + { + seconds -= 60; + minutes += 1; + } + + minutes += (rtc_f9.reg[3]*10 + rtc_f9.reg[2]); + if ( minutes >= 60 ) + { + minutes -= 60; + hours += 1; + } + + hours += (rtc_f9.reg[5]*10 + rtc_f9.reg[4]); + if ( hours >= 24 ) + { + hours -= 24; + days += 1; + } + + year = rtc_f9.reg[11]*10 + rtc_f9.reg[10]; + year += ( 1900 ); + month = rtc_f9.reg[8]+10*rtc_f9.reg[9]; + rtc_f9.reg[12]+=days; + days += (rtc_f9.reg[7]*10 + rtc_f9.reg[6]); + if ( days > 0 ) + { + while ( days > (temp_days = S9xRTCDaysInMonth( month, year )) ) + { + days -= temp_days; + month += 1; + if ( month > 12 ) + { + year += 1; + month = 1; + } + } + } + + year_tens = year % 100; + year_ones = year_tens % 10; + year_tens /= 10; + year_hundreds = (year - 1000) / 100; + + rtc_f9.reg[0] = seconds % 10; + rtc_f9.reg[1] = seconds / 10; + rtc_f9.reg[2] = minutes % 10; + rtc_f9.reg[3] = minutes / 10; + rtc_f9.reg[4] = hours % 10; + rtc_f9.reg[5] = hours / 10; + rtc_f9.reg[6] = days % 10; + rtc_f9.reg[7] = days / 10; + rtc_f9.reg[8] = month%10; + rtc_f9.reg[9] = month /10; + rtc_f9.reg[10] = year_ones; + rtc_f9.reg[11] = year_tens; + rtc_f9.reg[12] %= 7; + return; + } + } +} +extern "C"{ + +//allows DMA from the ROM (is this even possible on the SPC7110? +uint8* Get7110BasePtr(uint32 Address) +{ + uint32 i; + switch((Address&0x00F00000)>>16) + { + case 0xD0: + i=s7r.reg4831*0x100000; + break; + case 0xE0: + i=s7r.reg4832*0x100000; + break; + case 0xF0: + i=s7r.reg4833*0x100000; + break; + default:i=0; + } + i+=Address&0x000F0000; + return &ROM[i]; +} +//end extern +} + +//loads the index into memory. +//index.bin is little-endian +//format index (1)-table(3)-file offset(4)-length(4) +bool Load7110Index(char* filename) +{ + FILE* fp; + uint8 buffer[12]; + int table=0; + uint8 index=0; + uint32 offset=0; + uint32 size=0; + int i=0; + fp=fopen(filename, "rb"); + if(NULL==fp) + return false; + do + { + i=0; + fread(buffer, 1, 12,fp); + table=(buffer[3]<<16)|(buffer[2]<<8)|buffer[1]; + index=buffer[0]; + offset=(buffer[7]<<24)|(buffer[6]<<16)|(buffer[5]<<8)|buffer[4]; + size=(buffer[11]<<24)|(buffer[10]<<16)|(buffer[9]<<8)|buffer[8]; + while(itableEnts[i].table!=table&&decompack->tableEnts[i].table!=0) + i++; + if(i==MAX_TABLES) + return false; + //added + decompack->tableEnts[i].table=table; + //----- + decompack->tableEnts[i].location[index].offset=offset; + decompack->tableEnts[i].location[index].size=size; + decompack->tableEnts[i].location[index].used_len=0; + decompack->tableEnts[i].location[index].used_offset=0; + + } + while(!feof(fp)); + fclose(fp); + return true; +} + + +//Cache 1 load function +void SPC7110Load(char* dirname) +{ +#ifndef NGC + char temp_path[PATH_MAX]; + int i=0; + + decompack=new Pack7110; + +#ifndef _XBOX + getcwd(temp_path,PATH_MAX); +#endif + + ZeroMemory(decompack, sizeof(Pack7110)); + +#ifndef _XBOX +#ifndef NGC + if(-1==chdir(dirname)) + { + S9xMessage(0,0,"Graphics Pack not found!"); + } +#endif +#endif + +#ifndef _XBOX + Load7110Index("index.bin"); +#else + // D:\\ is always app.path in Xbox + Load7110Index("d:\\index.bin"); +#endif + + for(i=0;itableEnts[i].table!=0) + { + char binname[PATH_MAX]; +#ifndef _XBOX + sprintf(binname,"%06X.bin",decompack->tableEnts[i].table); +#else + sprintf(binname,"%s%06X.bin",filename,decompack->tableEnts[i].table); +#endif + struct stat buf; + +#ifndef NGC + if(-1!=stat(binname, &buf)) + decompack->binfiles[i]=new uint8[buf.st_size]; +#endif + FILE* fp=fopen(binname, "rb"); + if(fp) + { + fread(decompack->binfiles[i],buf.st_size,1,fp); + fclose(fp); + } + } + } + +#ifndef _XBOX +#ifndef NGC + chdir(temp_path); +#endif +#endif + + Copy7110=&MovePackData; + CleanUp7110=&Del7110Gfx; +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED); + #endif +#endif +} + +//Cache 2 load function +void SPC7110Open(char* dirname) +{ + char temp_path[PATH_MAX]; + int i=0; + + decompack=new Pack7110; + +#ifndef _XBOX + getcwd(temp_path,PATH_MAX); +#endif + + ZeroMemory(decompack, sizeof(Pack7110)); + +#ifndef _XBOX + if(-1==chdir(dirname)) + { + S9xMessage(0,0,"Graphics Pack not found!"); + } +#endif + +#ifndef _XBOX + Load7110Index("index.bin"); +#else + // D:\\ is always app.path in Xbox + Load7110Index("d:\\index.bin"); +#endif + + for (i=0; ibinfiles[i]=NULL; + + ReadPackData(); + +#ifndef _XBOX + chdir(temp_path); +#endif + + Copy7110=&ReadPackData; + CleanUp7110=&Close7110Gfx; + +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED); + #endif +#endif +} + +//Cache 3's load function +void SPC7110Grab(char* dirname) +{ + char temp_path[PATH_MAX]; + int i=0; + + decompack=new Pack7110; + +#ifndef _XBOX + getcwd(temp_path,PATH_MAX); +#endif + + int32 buffer_size=1024*1024*cacheMegs;//*some setting + + ZeroMemory(decompack, sizeof(Pack7110)); +#ifndef _XBOX + + if(-1==chdir(dirname)) + { + S9xMessage(0,0,"Graphics Pack not found!"); + } +#endif + +#ifndef _XBOX + Load7110Index("index.bin"); +#else + // D:\\ is always app.path in Xbox + Load7110Index("d:\\index.bin"); +#endif + + for(i=0;itableEnts[i].table!=0) + { + char binname[PATH_MAX]; +#ifndef _XBOX + sprintf(binname,"%06X.bin",decompack->tableEnts[i].table); +#else + sprintf(binname,"%s%06X.bin",filename,decompack->tableEnts[i].table); +#endif + struct stat buf; +//add load/no load calculations here + +#ifndef NGC + if(-1!=stat(binname, &buf)) + { + if(buf.st_sizebinfiles[i]=new uint8[buf.st_size]; + FILE* fp=fopen(binname, "rb"); + //use them here + if(fp) + { + if(buf.st_sizebinfiles[i],buf.st_size,1,fp); + fclose(fp); + buffer_size-=buf.st_size; + decompack->tableEnts[i].is_file=false; + } + else + { + decompack->binfiles[i]=(uint8*)fp; + decompack->tableEnts[i].is_file=true; + } + } + } + +#endif + } + } + +#ifndef _XBOX + chdir(temp_path); +#endif + + Copy7110=&GetPackData; + CleanUp7110=&Drop7110Gfx; + + +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_ENABLED); + #endif +#endif + +#endif + +} + +//Cache 1 clean up function +void Del7110Gfx() +{ + int i; + if(Settings.SPC7110) + { +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED); + #endif +#endif + Do7110Logging(); + } + for(i=0;ibinfiles[i]!=NULL) + { + delete []decompack->binfiles[i]; + decompack->binfiles[i]=NULL; + } + } + Settings.SPC7110=false; + Settings.SPC7110RTC=false; + if(NULL!=decompack) + delete decompack; + decompack=NULL; + CleanUp7110=NULL; + Copy7110=NULL; +} + +//Cache2 cleanup function +void Close7110Gfx() +{ + int i; + if(Settings.SPC7110) + { +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED); + #endif +#endif + Do7110Logging(); + } + for(i=0;ibinfiles[i]!=NULL) + { + fclose((FILE*)decompack->binfiles[i]); + decompack->binfiles[i]=NULL; + } + } + Settings.SPC7110=false; + Settings.SPC7110RTC=false; + if(NULL!=decompack) + delete decompack; + decompack=NULL; + CleanUp7110=NULL; + Copy7110=NULL; +} + +//cache 3's clean-up code +void Drop7110Gfx() +{ + int i; + if(Settings.SPC7110) + { +#ifdef __WIN32__ + #ifndef _XBOX + EnableMenuItem(GUI.hMenu, IDM_LOG_7110, MF_GRAYED); + #endif +#endif + Do7110Logging(); + } + for(i=0;ibinfiles[i]!=NULL) + { + if(decompack->tableEnts[i].is_file) + { + fclose((FILE*)decompack->binfiles[i]); + decompack->binfiles[i]=NULL; + } + else + { + delete []decompack->binfiles[i]; + decompack->binfiles[i]=NULL; + } + } + } + Settings.SPC7110=false; + Settings.SPC7110RTC=false; + if(NULL!=decompack) + delete decompack; + decompack=NULL; + CleanUp7110=NULL; + Copy7110=NULL; +} + +//emulate a reset. +void S9xSpc7110Reset() +{ + s7r.reg4800=0; + s7r.reg4801=0; + s7r.reg4802=0; + s7r.reg4803=0; + s7r.reg4804=0; + s7r.reg4805=0; + s7r.reg4806=0; + s7r.reg4807=0; + s7r.reg4808=0; + s7r.reg4809=0; + s7r.reg480A=0; + s7r.reg480B=0; + s7r.reg480C=0; + s7r.reg4811=0; + s7r.reg4812=0; + s7r.reg4813=0; + s7r.reg4814=0; + s7r.reg4815=0; + s7r.reg4816=0; + s7r.reg4817=0; + s7r.reg4818=0; + s7r.reg4820=0; + s7r.reg4821=0; + s7r.reg4822=0; + s7r.reg4823=0; + s7r.reg4824=0; + s7r.reg4825=0; + s7r.reg4826=0; + s7r.reg4827=0; + s7r.reg4828=0; + s7r.reg4829=0; + s7r.reg482A=0; + s7r.reg482B=0; + s7r.reg482C=0; + s7r.reg482D=0; + s7r.reg482E=0; + s7r.reg482F=0; + s7r.reg4830=0; + s7r.reg4831=0; + s7r.reg4832=1; + s7r.reg4833=2; + s7r.reg4834=0; + s7r.reg4840=0; + s7r.reg4841=0; + s7r.reg4842=0; + s7r.written=0; + s7r.offset_add=0; + s7r.AlignBy=1; + s7r.bank50Internal=0; + memset(s7r.bank50,0x00,DECOMP_BUFFER_SIZE); +} + + +//outputs a cumulative log for the game. +//there's nothing really weird here, just +//reading the old log, and writing a new one. +//note the logs are explicitly little-endian, not host byte order. +void Do7110Logging() +{ + uint8 ent_temp; + FILE* flog; + int entries=0; + + if(Settings.SPC7110) + { + //flush last read into logging + (*Copy7110)(); + +#ifdef __MACOSX__ + char name[PATH_MAX + 1]; + strcpy(name, S9xGetFilename(".dat", DEFAULT_DIR)); + flog = fopen(name, "rb"); +#else + if(!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21)) + { +#ifdef _XBOX + flog=fopen("T:\\spl4-sp7.dat","rb"); +#else + flog=fopen("spl4-sp7.dat","rb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ",21)) + { +#ifdef _XBOX + flog=fopen("T:\\smht-sp7.dat","rb"); +#else + flog=fopen("smht-sp7.dat","rb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21)) + { +#ifdef _XBOX + flog=fopen("T:\\feoezsp7.dat","rb"); +#else + flog=fopen("feoezsp7.dat","rb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO",21)) + { +#ifdef _XBOX + flog=fopen("T:\\sjumpsp7.dat","rb"); +#else + flog=fopen("sjumpsp7.dat","rb"); +#endif + } + else + { +#ifdef _XBOX + flog=fopen("T:\\misc-sp7.dat","rb"); +#else + flog=fopen("misc-sp7.dat","rb"); +#endif + } +#endif + + if(flog) + { + uint8 buffer[8]; + int table=0; + uint16 offset=0; + uint16 length=0; + fseek(flog, 35,0); + do + { + int i=0; + Data7110 *log=NULL; + fread(buffer, 1, 8, flog); + table=buffer[0]|(buffer[1]<<8)|(buffer[2]<<16); + offset=buffer[6]|(buffer[7]<<8); + length=buffer[4]|(buffer[5]<<8); + while(itableEnts[i].table==table) + { + log=&(decompack->tableEnts[i].location[(buffer[3])]); + if((log->used_offset+log->used_len)<(offset+length)) + { + log->used_offset=offset; + log->used_len=length; + } + } + i++; + } + } + while(!feof(flog)); + fclose(flog); + } + +#ifdef __MACOSX__ + strcpy(name, S9xGetFilename(".dat", DEFAULT_DIR)); + flog = fopen(name, "rb"); +#else + if(!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21)) + { +#ifdef _XBOX // cwd could be the dvd-rom, so write to T:\\ which is storage region for each title + flog=fopen("T:\\spl4-sp7.dat","wb"); +#else + flog=fopen("spl4-sp7.dat","wb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ",21)) + { +#ifdef _XBOX + flog=fopen("T:\\smht-sp7.dat","wb"); +#else + flog=fopen("smht-sp7.dat","wb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21)) + { +#ifdef _XBOX + flog=fopen("T:\\feoezsp7.dat","wb"); +#else + flog=fopen("feoezsp7.dat","wb"); +#endif + } + else if(!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO",21)) + { +#ifdef _XBOX + flog=fopen("T:\\sjumpsp7.dat","wb"); +#else + flog=fopen("sjumpsp7.dat","wb"); +#endif + } + else + { +#ifdef _XBOX + flog=fopen("T:\\misc-sp7.dat","wb"); +#else + flog=fopen("misc-sp7.dat","wb"); +#endif + } +#endif + //count entries + if(flog) + { + int j=0; + int temp=0; + for(j=0;jtableEnts[j].location[k].used_len!=0) + entries++; + } + } + ent_temp=entries&0xFF; + fwrite(&ent_temp,1,1,flog); + ent_temp=(entries>>8)&0xFF; + fwrite(&ent_temp,1,1,flog); + ent_temp=(entries>>16)&0xFF; + fwrite(&ent_temp,1,1,flog); + ent_temp=(entries>>24)&0xFF; + fwrite(&ent_temp,1,1,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + + ent_temp=0; + fwrite(&ent_temp,1,1,flog); + ent_temp=0; + fwrite(&ent_temp,1,1,flog); + ent_temp=0; + fwrite(&ent_temp,1,1,flog); + + for(j=0;jtableEnts[j].location[k].used_len!=0) + { + ent_temp=decompack->tableEnts[j].table&0xFF; + fwrite(&ent_temp,1,1,flog);//801 + ent_temp=(decompack->tableEnts[j].table>>8)&0xFF;; + fwrite(&ent_temp,1,1,flog);//802 + ent_temp=(decompack->tableEnts[j].table>>16)&0xFF;; + fwrite(&ent_temp,1,1,flog);//803 + ent_temp=k&0xFF; + fwrite(&ent_temp,1,1,flog);//804 + ent_temp=decompack->tableEnts[j].location[k].used_len&0xFF; + fwrite(&ent_temp,1,1,flog);//lsb of + ent_temp=(decompack->tableEnts[j].location[k].used_len>>8)&0xFF; + fwrite(&ent_temp,1,1,flog);//msb of + ent_temp=(decompack->tableEnts[j].location[k].used_offset)&0xFF; + fwrite(&ent_temp,1,1,flog);//lsb of + ent_temp=(decompack->tableEnts[j].location[k].used_offset>>8)&0xFF; + fwrite(&ent_temp,1,1,flog);//msb of + } + } + } + fwrite(&temp,1,4,flog); + fwrite(&temp,1,4,flog); + fclose(flog); + } + } +} +bool8 S9xSaveSPC7110RTC (S7RTC *rtc_f9) +{ + FILE* fp; + + if((fp=fopen(S9xGetFilename(".rtc", SRAM_DIR), "wb"))==NULL) + return (FALSE); + int i=0; + uint8 temp=0; + for (i=0;i<16;i++) + fwrite(&rtc_f9->reg[i],1,1,fp); + temp=rtc_f9->index&0x00FF; + fwrite(&temp,1,1,fp); + temp=(rtc_f9->index)>>8; + fwrite(&temp,1,1,fp); + temp=(uint8)rtc_f9->control; + fwrite(&temp,1,1,fp); + temp=(uint8)rtc_f9->init; + fwrite(&temp,1,1,fp); + temp=rtc_f9->last_used&0x00FF; + fwrite(&temp,1,1,fp); + temp=(rtc_f9->last_used>>8)&0x00FF; + fwrite(&temp,1,1,fp); + temp=(rtc_f9->last_used>>16)&0x00FF; + fwrite(&temp,1,1,fp); + temp=(rtc_f9->last_used>>24)&0x00FF;; + fwrite(&temp,1,1,fp); + fclose(fp); + return (TRUE); +} + +bool8 S9xLoadSPC7110RTC (S7RTC *rtc_f9) +{ + FILE* fp; + + if((fp=fopen(S9xGetFilename(".rtc", SRAM_DIR), "rb"))==NULL) + return (FALSE); + for (int i=0; i<16;i++) + { + fread(&(rtc_f9->reg[i]),1,1,fp); + } + uint8 temp=0; + fread(&temp,1,1,fp); + rtc_f9->index=temp; + fread(&temp,1,1,fp); + rtc_f9->index|=(temp<<8); + fread(&rtc_f9->control,1,1,fp); + fread(&rtc_f9->init,1,1,fp); + + fread(&temp,1,1,fp); + rtc_f9->last_used=temp; + fread(&temp,1,1,fp); + rtc_f9->last_used|=(temp<<8); + fread(&temp,1,1,fp); + rtc_f9->last_used|=(temp<<16); + fread(&temp,1,1,fp); + rtc_f9->last_used|=(temp<<24); + fclose(fp); + return (TRUE); +} + diff --git a/source/snes9x/spc7110.h b/source/snes9x/spc7110.h new file mode 100644 index 0000000..2db39d4 --- /dev/null +++ b/source/snes9x/spc7110.h @@ -0,0 +1,250 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _spc7110_h +#define _spc7110_h +#include "port.h" + +#define DECOMP_BUFFER_SIZE 0x10000 + +extern void (*LoadUp7110)(char*); +extern void (*CleanUp7110)(void); +extern void (*Copy7110)(void); + +extern uint16 cacheMegs; + +void Del7110Gfx(void); +void Close7110Gfx(void); +void Drop7110Gfx(void); +extern "C"{ +uint8 S9xGetSPC7110(uint16 Address); +uint8 S9xGetSPC7110Byte(uint32 Address); +uint8* Get7110BasePtr(uint32); +} +void S9xSetSPC7110 (uint8 data, uint16 Address); +void S9xSpc7110Init(); +uint8* Get7110BasePtr(uint32); +void S9xSpc7110Reset(); +void S9xUpdateRTC (); +void Do7110Logging(); +int S9xRTCDaysInMonth( int month, int year ); + +//These are platform-dependant functions, but should work on +//most systems that use GNU compilers, and on Win32. +void SPC7110Load(char*); +void SPC7110Open(char*); +void SPC7110Grab(char*); + +typedef struct SPC7110RTC +{ + unsigned char reg[16]; + short index; + uint8 control; + bool init; + time_t last_used; +} S7RTC; + +typedef struct SPC7110EmuVars +{ + unsigned char reg4800; + unsigned char reg4801; + unsigned char reg4802; + unsigned char reg4803; + unsigned char reg4804; + unsigned char reg4805; + unsigned char reg4806; + unsigned char reg4807; + unsigned char reg4808; + unsigned char reg4809; + unsigned char reg480A; + unsigned char reg480B; + unsigned char reg480C; + unsigned char reg4811; + unsigned char reg4812; + unsigned char reg4813; + unsigned char reg4814; + unsigned char reg4815; + unsigned char reg4816; + unsigned char reg4817; + unsigned char reg4818; + unsigned char reg4820; + unsigned char reg4821; + unsigned char reg4822; + unsigned char reg4823; + unsigned char reg4824; + unsigned char reg4825; + unsigned char reg4826; + unsigned char reg4827; + unsigned char reg4828; + unsigned char reg4829; + unsigned char reg482A; + unsigned char reg482B; + unsigned char reg482C; + unsigned char reg482D; + unsigned char reg482E; + unsigned char reg482F; + unsigned char reg4830; + unsigned char reg4831; + unsigned char reg4832; + unsigned char reg4833; + unsigned char reg4834; + unsigned char reg4840; + unsigned char reg4841; + unsigned char reg4842; + uint8 AlignBy; + uint8 written; + uint8 offset_add; + uint32 DataRomOffset; + uint32 DataRomSize; + uint32 bank50Internal; + uint8 bank50[DECOMP_BUFFER_SIZE]; + +} SPC7110Regs; +extern SPC7110Regs s7r; +extern S7RTC rtc_f9; +// These are defined in spc7110.cpp +bool8 S9xSaveSPC7110RTC (S7RTC *rtc_f9); +bool8 S9xLoadSPC7110RTC (S7RTC *rtc_f9); + +#endif + diff --git a/source/snes9x/srtc.cpp b/source/snes9x/srtc.cpp new file mode 100644 index 0000000..319de1c --- /dev/null +++ b/source/snes9x/srtc.cpp @@ -0,0 +1,636 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include "snes9x.h" +#include "srtc.h" +#include "memmap.h" + +/*** The format of the rtc_data structure is: + +Index Description Range (nibble) +----- -------------- --------------------------------------- + + 0 Seconds low 0-9 + 1 Seconds high 0-5 + + 2 Minutes low 0-9 + 3 Minutes high 0-5 + + 4 Hour low 0-9 + 5 Hour high 0-2 + + 6 Day low 0-9 + 7 Day high 0-3 + + 8 Month 1-C (0xC is December, 12th month) + + 9 Year ones 0-9 + A Year tens 0-9 + B Year High 9-B (9=19xx, A=20xx, B=21xx) + + C Day of week 0-6 (0=Sunday, 1=Monday,...,6=Saturday) + +***/ + +SRTC_DATA rtc; + + +static int month_keys[12] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 }; + + +/********************************************************************************************* + * + * Note, if you are doing a save state for this game: + * + * On save: + * + * Call S9xUpdateSrtcTime and save the rtc data structure. + * + * On load: + * + * restore the rtc data structure + * rtc.system_timestamp = time (NULL); + * + * + *********************************************************************************************/ + + +void S9xResetSRTC () +{ + rtc.index = -1; + rtc.mode = MODE_READ; +} + +void S9xHardResetSRTC () +{ + ZeroMemory (&rtc, sizeof (rtc)); + rtc.index = -1; + rtc.mode = MODE_READ; + rtc.count_enable = FALSE; + rtc.needs_init = TRUE; + + // Get system timestamp + rtc.system_timestamp = time (NULL); +} + +/**********************************************************************************************/ +/* S9xSRTCComputeDayOfWeek() */ +/* Return 0-6 for Sunday-Saturday */ +/**********************************************************************************************/ +unsigned int S9xSRTCComputeDayOfWeek () +{ + unsigned year = rtc.data[10]*10 + rtc.data[9]; + unsigned month = rtc.data[8]; + unsigned day = rtc.data[7]*10 + rtc.data[6]; + unsigned day_of_week; + + year += (rtc.data[11] - 9) * 100; + + // Range check the month for valid array indicies + if ( month > 12 ) + month = 1; + + day_of_week = year + (year / 4) + month_keys[month-1] + day - 1; + + if(( year % 4 == 0 ) && ( month <= 2 ) ) + day_of_week--; + + day_of_week %= 7; + + return day_of_week; +} + + +/**********************************************************************************************/ +/* S9xSRTCDaysInMonth() */ +/* Return the number of days in a specific month for a certain year */ +/**********************************************************************************************/ +int S9xSRTCDaysInMmonth( int month, int year ) +{ + int mdays; + + switch ( month ) + { + case 2: + if ( ( year % 4 == 0 ) ) // DKJM2 only uses 199x - 22xx + mdays = 29; + else + mdays = 28; + break; + + case 4: + case 6: + case 9: + case 11: + mdays = 30; + break; + + default: // months 1,3,5,7,8,10,12 + mdays = 31; + break; + } + + return mdays; +} + + +#define DAYTICKS (60*60*24) +#define HOURTICKS (60*60) +#define MINUTETICKS 60 + + +/**********************************************************************************************/ +/* S9xUpdateSrtcTime() */ +/* Advance the S-RTC time if counting is enabled */ +/**********************************************************************************************/ +void S9xUpdateSrtcTime () +{ + time_t cur_systime; + long time_diff; + + // Keep track of game time by computing the number of seconds that pass on the system + // clock and adding the same number of seconds to the S-RTC clock structure. + // I originally tried using mktime and localtime library functions to keep track + // of time but some of the GNU time functions fail when the year goes to 2099 + // (and maybe less) and this would have caused a bug with DKJM2 so I'm doing + // it this way to get around that problem. + + // Note: Dai Kaijyu Monogatari II only allows dates in the range 1996-21xx. + + if (rtc.count_enable && !rtc.needs_init) + { + cur_systime = time (NULL); + + // This method assumes one time_t clock tick is one second + // which should work on PCs and GNU systems. + // If your tick interval is different adjust the + // DAYTICK, HOURTICK, and MINUTETICK defines + + time_diff = (long) (cur_systime - rtc.system_timestamp); + rtc.system_timestamp = cur_systime; + + if ( time_diff > 0 ) + { + int seconds; + int minutes; + int hours; + int days; + int month; + int year; + int temp_days; + + int year_hundreds; + int year_tens; + int year_ones; + + + if ( time_diff > DAYTICKS ) + { + days = time_diff / DAYTICKS; + time_diff = time_diff - days * DAYTICKS; + } + else + { + days = 0; + } + + if ( time_diff > HOURTICKS ) + { + hours = time_diff / HOURTICKS; + time_diff = time_diff - hours * HOURTICKS; + } + else + { + hours = 0; + } + + if ( time_diff > MINUTETICKS ) + { + minutes = time_diff / MINUTETICKS; + time_diff = time_diff - minutes * MINUTETICKS; + } + else + { + minutes = 0; + } + + if ( time_diff > 0 ) + { + seconds = time_diff; + } + else + { + seconds = 0; + } + + + seconds += (rtc.data[1]*10 + rtc.data[0]); + if ( seconds >= 60 ) + { + seconds -= 60; + minutes += 1; + } + + minutes += (rtc.data[3]*10 + rtc.data[2]); + if ( minutes >= 60 ) + { + minutes -= 60; + hours += 1; + } + + hours += (rtc.data[5]*10 + rtc.data[4]); + if ( hours >= 24 ) + { + hours -= 24; + days += 1; + } + + if ( days > 0 ) + { + year = rtc.data[10]*10 + rtc.data[9]; + year += ( 1000 + rtc.data[11] * 100 ); + + month = rtc.data[8]; + days += (rtc.data[7]*10 + rtc.data[6]); + while ( days > (temp_days = S9xSRTCDaysInMmonth( month, year )) ) + { + days -= temp_days; + month += 1; + if ( month > 12 ) + { + year += 1; + month = 1; + } + } + + year_tens = year % 100; + year_ones = year_tens % 10; + year_tens /= 10; + year_hundreds = (year - 1000) / 100; + + rtc.data[6] = days % 10; + rtc.data[7] = days / 10; + rtc.data[8] = month; + rtc.data[9] = year_ones; + rtc.data[10] = year_tens; + rtc.data[11] = year_hundreds; + rtc.data[12] = S9xSRTCComputeDayOfWeek (); + } + + rtc.data[0] = seconds % 10; + rtc.data[1] = seconds / 10; + rtc.data[2] = minutes % 10; + rtc.data[3] = minutes / 10; + rtc.data[4] = hours % 10; + rtc.data[5] = hours / 10; + + return; + } + } +} + + +/**********************************************************************************************/ +/* S9xSetSRTC() */ +/* This function sends data to the S-RTC used in Dai Kaijyu Monogatari II */ +/**********************************************************************************************/ +void S9xSetSRTC (uint8 data, uint16 Address) +{ + + data &= 0x0F; // Data is only 4-bits, mask out unused bits. + + if( data >= 0xD ) + { + // It's an RTC command + + switch ( data ) + { + case 0xD: + rtc.mode = MODE_READ; + rtc.index = -1; + break; + + case 0xE: + rtc.mode = MODE_COMMAND; + break; + + default: + // Ignore the write if it's an 0xF ??? + // Probably should switch back to read mode -- but this + // sequence never occurs in DKJM2 + break; + } + + return; + } + + if ( rtc.mode == MODE_LOAD_RTC ) + { + if ( (rtc.index >= 0) && (rtc.index < MAX_RTC_INDEX) ) + { + rtc.data[rtc.index++] = data; + + if ( rtc.index == MAX_RTC_INDEX ) + { + // We have all the data for the RTC load + + rtc.system_timestamp = time (NULL); // Get local system time + + // Get the day of the week + rtc.data[rtc.index++] = S9xSRTCComputeDayOfWeek (); + + // Start RTC counting again + rtc.count_enable = TRUE; + rtc.needs_init = FALSE; + } + + return; + } + else + { + // Attempting to write too much data + // error(); // ignore?? + } + } + else if ( rtc.mode == MODE_COMMAND ) + { + switch( data ) + { + case COMMAND_CLEAR_RTC: + // Disable RTC counter + rtc.count_enable = FALSE; + + ZeroMemory (rtc.data, MAX_RTC_INDEX+1); + rtc.index = -1; + rtc.mode = MODE_COMMAND_DONE; + break; + + case COMMAND_LOAD_RTC: + // Disable RTC counter + rtc.count_enable = FALSE; + + rtc.index = 0; // Setup for writing + rtc.mode = MODE_LOAD_RTC; + break; + + default: + rtc.mode = MODE_COMMAND_DONE; + // unrecognized command - need to implement. + } + + return; + } + else + { + if ( rtc.mode == MODE_READ ) + { + // Attempting to write while in read mode. Ignore. + } + + if ( rtc.mode == MODE_COMMAND_DONE ) + { + // Maybe this isn't an error. Maybe we should kick off + // a new E command. But is this valid? + } + } +} + +/**********************************************************************************************/ +/* S9xGetSRTC() */ +/* This function retrieves data from the S-RTC */ +/**********************************************************************************************/ +uint8 S9xGetSRTC (uint16 Address) +{ + if ( rtc.mode == MODE_READ ) + { + if ( rtc.index < 0 ) + { + S9xUpdateSrtcTime (); // Only update it if the game reads it + rtc.index++; + return ( 0x0f ); // Send start marker. + } + else if (rtc.index > MAX_RTC_INDEX) + { + rtc.index = -1; // Setup for next set of reads + return ( 0x0f ); // Data done marker. + } + else + { + // Feed out the data + return rtc.data[rtc.index++]; + } + } + else + { + return 0x0; + } +} + +void S9xSRTCPreSaveState () +{ + if (Settings.SRTC) + { + S9xUpdateSrtcTime (); + + int s = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (s > 0x20000) + s = 0x20000; + + SRAM [s + 0] = rtc.needs_init; + SRAM [s + 1] = rtc.count_enable; + memmove (&SRAM [s + 2], rtc.data, MAX_RTC_INDEX + 1); + SRAM [s + 3 + MAX_RTC_INDEX] = rtc.index; + SRAM [s + 4 + MAX_RTC_INDEX] = rtc.mode; + +#ifdef LSB_FIRST + memmove (&SRAM [s + 5 + MAX_RTC_INDEX], &rtc.system_timestamp, 8); +#else +#ifndef NGC + SRAM [s + 5 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 0); + SRAM [s + 6 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 8); + SRAM [s + 7 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 16); + SRAM [s + 8 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 24); + SRAM [s + 9 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 32); + SRAM [s + 10 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 40); + SRAM [s + 11 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 48); + SRAM [s + 12 + MAX_RTC_INDEX] = (uint8) (rtc.system_timestamp >> 56); +#endif +#endif + } +} + +void S9xSRTCPostLoadState () +{ + if (Settings.SRTC) + { + int s = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (s > 0x20000) + s = 0x20000; + + rtc.needs_init = SRAM [s + 0]; + rtc.count_enable = SRAM [s + 1]; + memmove (rtc.data, &SRAM [s + 2], MAX_RTC_INDEX + 1); + rtc.index = SRAM [s + 3 + MAX_RTC_INDEX]; + rtc.mode = SRAM [s + 4 + MAX_RTC_INDEX]; + +#ifdef LSB_FIRST + memmove (&rtc.system_timestamp, &SRAM [s + 5 + MAX_RTC_INDEX], 8); +#else +#ifndef NGC + rtc.system_timestamp |= (SRAM [s + 5 + MAX_RTC_INDEX] << 0); + rtc.system_timestamp |= (SRAM [s + 6 + MAX_RTC_INDEX] << 8); + rtc.system_timestamp |= (SRAM [s + 7 + MAX_RTC_INDEX] << 16); + rtc.system_timestamp |= (SRAM [s + 8 + MAX_RTC_INDEX] << 24); + rtc.system_timestamp |= (SRAM [s + 9 + MAX_RTC_INDEX] << 32); + rtc.system_timestamp |= (SRAM [s + 10 + MAX_RTC_INDEX] << 40); + rtc.system_timestamp |= (SRAM [s + 11 + MAX_RTC_INDEX] << 48); + rtc.system_timestamp |= (SRAM [s + 12 + MAX_RTC_INDEX] << 56); +#endif +#endif + S9xUpdateSrtcTime (); + } +} + diff --git a/source/snes9x/srtc.h b/source/snes9x/srtc.h new file mode 100644 index 0000000..f626779 --- /dev/null +++ b/source/snes9x/srtc.h @@ -0,0 +1,212 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _srtc_h_ +#define _srtc_h_ + +#include + +#define MAX_RTC_INDEX 0xC + +#define MODE_READ 0 +#define MODE_LOAD_RTC 1 +#define MODE_COMMAND 2 +#define MODE_COMMAND_DONE 3 + +#define COMMAND_LOAD_RTC 0 +#define COMMAND_CLEAR_RTC 4 + + +/*** The format of the rtc_data structure is: + +Index Description Range (nibble) +----- -------------- --------------------------------------- + + 0 Seconds low 0-9 + 1 Seconds high 0-5 + + 2 Minutes low 0-9 + 3 Minutes high 0-5 + + 4 Hour low 0-9 + 5 Hour high 0-2 + + 6 Day low 0-9 + 7 Day high 0-3 + + 8 Month 1-C (0xC is December, 12th month) + + 9 Year ones 0-9 + A Year tens 0-9 + B Year High 9-B (9=19xx, A=20xx, B=21xx) + + C Day of week 0-6 (0=Sunday, 1=Monday,...,6=Saturday) + +***/ + +typedef struct +{ + bool8 needs_init; + bool8 count_enable; // Does RTC mark time or is it frozen + uint8 data [MAX_RTC_INDEX+1]; + int8 index; + uint8 mode; + + time_t system_timestamp; // Of latest RTC load time + uint32 pad; +} SRTC_DATA; + +extern SRTC_DATA rtc; + +void S9xUpdateSrtcTime (); +void S9xSetSRTC (uint8 data, uint16 Address); +uint8 S9xGetSRTC (uint16 Address); +void S9xSRTCPreSaveState (); +void S9xSRTCPostLoadState (); +void S9xResetSRTC (); +void S9xHardResetSRTC (); + +#define SRTC_SRAM_PAD (4 + 8 + 1 + MAX_RTC_INDEX) + +#endif // _srtc_h + diff --git a/source/snes9x/tile.cpp b/source/snes9x/tile.cpp new file mode 100644 index 0000000..b91e1d6 --- /dev/null +++ b/source/snes9x/tile.cpp @@ -0,0 +1,1302 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +// This file includes itself multiple times. The other option would be to have +// 4 files, where A includes B, and B includes C 3 times, and C includes D 5 +// times. Look for the following marker to find where the divisions are. +/*===========================================================================*/ + +#ifndef _NEWTILE_CPP // Top-level compilation +#define _NEWTILE_CPP + +#include "snes9x.h" +#include "gfx.h" +#include "ppu.h" + +static uint32 pixbit[8][16]; +static uint8 hrbit_odd[256]; +static uint8 hrbit_even[256]; + +void S9xInitTileRenderer(void){ + register int i; + + for(i=0; i<16; i++) { + register uint32 b = 0; + +#if defined(LSB_FIRST) + if (i & 8) + b |= 1; + if (i & 4) + b |= 1<<8; + if (i & 2) + b |= 1<<16; + if (i & 1) + b |= 1<<24; +#else + if (i & 8) + b |= 1<<24; + if (i & 4) + b |= 1<<16; + if (i & 2) + b |= 1<<8; + if (i & 1) + b |= 1; +#endif + + for(uint8 bitshift=0; bitshift<8; bitshift++) { + pixbit[bitshift][i]=b<> 4]; \ + p2 |= pixbit[(i)][pix & 0xf]; \ + } + +static uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32) +{ + register uint8 *tp = &Memory.VRAM[TileAddr]; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + for (line = 8; line != 0; line--, tp += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT(0, 0); + DOBIT(1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +static uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32) +{ + register uint8 *tp = &Memory.VRAM[TileAddr]; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + for (line = 8; line != 0; line--, tp += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT( 0, 0); + DOBIT( 1, 1); + DOBIT(16, 2); + DOBIT(17, 3); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +static uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32) +{ + register uint8 *tp = &Memory.VRAM[TileAddr]; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + for (line = 8; line != 0; line--, tp += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT( 0, 0); + DOBIT( 1, 1); + DOBIT(16, 2); + DOBIT(17, 3); + DOBIT(32, 4); + DOBIT(33, 5); + DOBIT(48, 6); + DOBIT(49, 7); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +#undef DOBIT +#define DOBIT(n, i) \ + if ((pix = hrbit_odd[*(tp1 + (n))])) \ + p1 |= pixbit[(i)][pix]; \ + if ((pix = hrbit_odd[*(tp2 + (n))])) \ + p2 |= pixbit[(i)][pix]; + +static uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) +{ + register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + if(Tile==0x3ff){ + tp2=tp1-(0x3ff<<4); + } else { + tp2=tp1+(1<<4); + } + + for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT(0, 0); + DOBIT(1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +static uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile) +{ + register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + if(Tile==0x3ff){ + tp2=tp1-(0x3ff<<5); + } else { + tp2=tp1+(1<<5); + } + + for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT( 0, 0); + DOBIT( 1, 1); + DOBIT(16, 2); + DOBIT(17, 3); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +#undef DOBIT +#define DOBIT(n, i) \ + if ((pix = hrbit_even[*(tp1 + (n))])) \ + p1 |= pixbit[(i)][pix]; \ + if ((pix = hrbit_even[*(tp2 + (n))])) \ + p2 |= pixbit[(i)][pix]; + +static uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) +{ + register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + if(Tile==0x3ff){ + tp2=tp1-(0x3ff<<4); + } else { + tp2=tp1+(1<<4); + } + + for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT(0, 0); + DOBIT(1, 1); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +static uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile) +{ + register uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2; + uint32 *p = (uint32 *) pCache; + uint32 non_zero = 0; + uint8 line; + + if(Tile==0x3ff){ + tp2=tp1-(0x3ff<<5); + } else { + tp2=tp1+(1<<5); + } + + for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2) + { + uint32 p1 = 0; + uint32 p2 = 0; + register uint8 pix; + DOBIT( 0, 0); + DOBIT( 1, 1); + DOBIT(16, 2); + DOBIT(17, 3); + *p++ = p1; + *p++ = p2; + non_zero |= p1 | p2; + } + return (non_zero ? TRUE : BLANK_TILE); +} + +#undef DOBIT + +/*****************************************************************************/ +// First-level include: get all the renderers +#include "tile.cpp" + + +/*****************************************************************************/ +// Functions to select which converter and renderer to use. + +void S9xSelectTileRenderers(int BGMode, bool8 sub, bool8 obj){ + void (**DT)(uint32,uint32,uint32,uint32); + void (**DCT)(uint32,uint32,uint32,uint32,uint32,uint32); + void (**DMP)(uint32,uint32,uint32,uint32,uint32,uint32); + void (**DB)(uint32,uint32,uint32); + void (**DM7BG1)(uint32,uint32,int); + void (**DM7BG2)(uint32,uint32,int); + bool8 M7M1, M7M2; + + M7M1=PPU.BGMosaic[0] && PPU.Mosaic>1; + M7M2=PPU.BGMosaic[1] && PPU.Mosaic>1; + + if(!IPPU.DoubleWidthPixels){ + DT=Renderers_DrawTile16Normal1x1; + DCT=Renderers_DrawClippedTile16Normal1x1; + DMP=Renderers_DrawMosaicPixel16Normal1x1; + DB=Renderers_DrawBackdrop16Normal1x1; + DM7BG1=M7M1?Renderers_DrawMode7MosaicBG1Normal1x1:Renderers_DrawMode7BG1Normal1x1; + DM7BG2=M7M2?Renderers_DrawMode7MosaicBG2Normal1x1:Renderers_DrawMode7BG2Normal1x1; + GFX.LinesPerTile = 8; + } else { + bool8 hires, interlace; + if(obj){ // OBJ + hires=(BGMode==5 || BGMode==6 || IPPU.PseudoHires); + interlace=IPPU.InterlaceOBJ; + } else if(BGMode==5 || BGMode==6){ + hires=TRUE; + interlace=IPPU.Interlace; + } else { + hires=IPPU.PseudoHires; + interlace=FALSE; + } + if(sub) hires=FALSE; + + if(hires && interlace){ + DT=Renderers_DrawTile16HiresInterlace; + DCT=Renderers_DrawClippedTile16HiresInterlace; + DMP=Renderers_DrawMosaicPixel16HiresInterlace; + DB=Renderers_DrawBackdrop16Hires; + DM7BG1=M7M1?Renderers_DrawMode7MosaicBG1Hires:Renderers_DrawMode7BG1Hires; + DM7BG2=M7M2?Renderers_DrawMode7MosaicBG2Hires:Renderers_DrawMode7BG2Hires; + GFX.LinesPerTile = 4; + } else if(hires){ + DT=Renderers_DrawTile16Hires; + DCT=Renderers_DrawClippedTile16Hires; + DMP=Renderers_DrawMosaicPixel16Hires; + DB=Renderers_DrawBackdrop16Hires; + DM7BG1=M7M1?Renderers_DrawMode7MosaicBG1Hires:Renderers_DrawMode7BG1Hires; + DM7BG2=M7M2?Renderers_DrawMode7MosaicBG2Hires:Renderers_DrawMode7BG2Hires; + GFX.LinesPerTile = 8; + } else if(interlace){ + DT=Renderers_DrawTile16Interlace; + DCT=Renderers_DrawClippedTile16Interlace; + DMP=Renderers_DrawMosaicPixel16Interlace; + DB=Renderers_DrawBackdrop16Normal2x1; + DM7BG1=M7M1?Renderers_DrawMode7MosaicBG1Normal2x1:Renderers_DrawMode7BG1Normal2x1; + DM7BG2=M7M2?Renderers_DrawMode7MosaicBG2Normal2x1:Renderers_DrawMode7BG2Normal2x1; + GFX.LinesPerTile = 4; + } else { + DT=Renderers_DrawTile16Normal2x1; + DCT=Renderers_DrawClippedTile16Normal2x1; + DMP=Renderers_DrawMosaicPixel16Normal2x1; + DB=Renderers_DrawBackdrop16Normal2x1; + DM7BG1=M7M1?Renderers_DrawMode7MosaicBG1Normal2x1:Renderers_DrawMode7BG1Normal2x1; + DM7BG2=M7M2?Renderers_DrawMode7MosaicBG2Normal2x1:Renderers_DrawMode7BG2Normal2x1; + GFX.LinesPerTile = 8; + } + } + + GFX.DrawTileNomath=DT[0]; + GFX.DrawClippedTileNomath=DCT[0]; + GFX.DrawMosaicPixelNomath=DMP[0]; + GFX.DrawBackdropNomath=DB[0]; + GFX.DrawMode7BG1Nomath=DM7BG1[0]; + GFX.DrawMode7BG2Nomath=DM7BG2[0]; + + int i; + if(!Settings.Transparency){ + i=0; + } else { + i=((Memory.FillRAM[0x2131]&0x80)?4:1); + if(Memory.FillRAM[0x2131]&0x40){ + i++; + if(Memory.FillRAM[0x2130]&2) i++; + } + } + GFX.DrawTileMath=DT[i]; + GFX.DrawClippedTileMath=DCT[i]; + GFX.DrawMosaicPixelMath=DMP[i]; + GFX.DrawBackdropMath=DB[i]; + GFX.DrawMode7BG1Math=DM7BG1[i]; + GFX.DrawMode7BG2Math=DM7BG2[i]; +} + +void S9xSelectTileConverter(int depth, bool8 hires, bool8 sub, bool8 mosaic){ + switch(depth){ + case 8: + BG.ConvertTile = BG.ConvertTileFlip = ConvertTile8; + BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_8BIT]; + BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_8BIT]; + BG.TileShift = 6; + BG.PaletteShift = 0; + BG.PaletteMask = 0; + BG.DirectColourMode = (Memory.FillRAM[0x2130]&1); + break; + case 4: + if(hires){ + if(sub || mosaic){ + BG.ConvertTile = ConvertTile4h_even; + BG.Buffer = IPPU.TileCache[TILE_4BIT_EVEN]; + BG.Buffered = IPPU.TileCached[TILE_4BIT_EVEN]; + BG.ConvertTileFlip = ConvertTile4h_odd; + BG.BufferFlip = IPPU.TileCache[TILE_4BIT_ODD]; + BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_ODD]; + } else { + BG.ConvertTile = ConvertTile4h_odd; + BG.Buffer = IPPU.TileCache[TILE_4BIT_ODD]; + BG.Buffered = IPPU.TileCached[TILE_4BIT_ODD]; + BG.ConvertTileFlip = ConvertTile4h_even; + BG.BufferFlip = IPPU.TileCache[TILE_4BIT_EVEN]; + BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_EVEN]; + } + } else { + BG.ConvertTile = BG.ConvertTileFlip = ConvertTile4; + BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_4BIT]; + BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_4BIT]; + } + BG.TileShift = 5; + BG.PaletteShift = 10-4; + BG.PaletteMask = 7<<4; + BG.DirectColourMode = FALSE; + break; + case 2: + if(hires){ + if(sub || mosaic){ + BG.ConvertTile = ConvertTile2h_even; + BG.Buffer = IPPU.TileCache[TILE_2BIT_EVEN]; + BG.Buffered = IPPU.TileCached[TILE_2BIT_EVEN]; + BG.ConvertTileFlip = ConvertTile2h_odd; + BG.BufferFlip = IPPU.TileCache[TILE_2BIT_ODD]; + BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_ODD]; + } else { + BG.ConvertTile = ConvertTile2h_odd; + BG.Buffer = IPPU.TileCache[TILE_2BIT_ODD]; + BG.Buffered = IPPU.TileCached[TILE_2BIT_ODD]; + BG.ConvertTileFlip = ConvertTile2h_even; + BG.BufferFlip = IPPU.TileCache[TILE_2BIT_EVEN]; + BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_EVEN]; + } + } else { + BG.ConvertTile = BG.ConvertTileFlip = ConvertTile2; + BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_2BIT]; + BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_2BIT]; + } + BG.TileShift = 4; + BG.PaletteShift = 10-2; + BG.PaletteMask = 7<<2; + BG.DirectColourMode = FALSE; + break; + } +} + +/*===========================================================================*/ +#else +#ifndef NAME1 // First-level: Get all renderers +/*===========================================================================*/ + +#define GET_CACHED_TILE() \ + uint32 TileNumber; \ + uint32 TileAddr = BG.TileAddress + ((Tile & 0x3ff) << BG.TileShift); \ + if ((Tile & 0x100)) \ + TileAddr += BG.NameSelect; \ + TileAddr &= 0xffff; \ + TileNumber = (TileAddr >> BG.TileShift); \ + if((Tile & H_FLIP)) { \ + pCache = &BG.BufferFlip[TileNumber << 6]; \ + if(!BG.BufferedFlip[TileNumber]) \ + BG.BufferedFlip[TileNumber] = BG.ConvertTileFlip (pCache, TileAddr, Tile&0x3ff); \ + } else { \ + pCache = &BG.Buffer[TileNumber << 6]; \ + if(!BG.Buffered[TileNumber]) \ + BG.Buffered[TileNumber] = BG.ConvertTile (pCache, TileAddr, Tile&0x3ff); \ + } + +#define IS_BLANK_TILE() \ + (BG.Buffered[TileNumber] == BLANK_TILE) + +#define SELECT_PALETTE() \ + if(BG.DirectColourMode) { \ + if(IPPU.DirectColourMapsNeedRebuild) S9xBuildDirectColourMaps(); \ + GFX.RealScreenColors = DirectColourMaps[(Tile>>10) & 7]; \ + } else { \ + GFX.RealScreenColors = &IPPU.ScreenColors[((Tile >> BG.PaletteShift) & BG.PaletteMask) + BG.StartPalette]; \ + } \ + GFX.ScreenColors = GFX.ClipColors?BlackColourMap:GFX.RealScreenColors; + +#define NOMATH(Op, Main, Sub, SD) (Main) +#define REGMATH(Op, Main, Sub, SD) (COLOR_##Op((Main),((SD)&0x20)?(Sub):GFX.FixedColour)) +#define MATHF1_2(Op, Main, Sub, SD) (GFX.ClipColors?(COLOR_##Op((Main),GFX.FixedColour)):(COLOR_##Op##1_2((Main),GFX.FixedColour))) +#define MATHS1_2(Op, Main, Sub, SD) (GFX.ClipColors?REGMATH(Op,Main,Sub,SD):(((SD)&0x20)?COLOR_##Op##1_2((Main),(Sub)):COLOR_##Op((Main),GFX.FixedColour))) + +/*****************************************************************************/ +// Basic routine to render an unclipped tile. Input parameters: +// BPSTART = either StartLine or (StartLine*2 + BG.InterlaceLine), so +// interlace modes can render every other line from the tile. +// PITCH = 1 or 2, again so interlace can count lines properly. +// DRAW_PIXEL(N,M) is a routine to actually draw the pixel. N is the pixel in +// the row to draw, and M is a test which if false means the pixel should +// be skipped. +// Z1 is the "draw if Z1>cur_depth". +// Z2 is the "cur_depth = new_depth". OBJ need the two separate. +// Pix is the pixel to draw. + +#define Z1 GFX.Z1 +#define Z2 GFX.Z2 +#define DRAW_TILE() \ + uint8 *pCache; \ + register int32 l; \ + register uint8 *bp, Pix; \ +\ + GET_CACHED_TILE(); \ + if(IS_BLANK_TILE()) return; \ + SELECT_PALETTE(); \ +\ + if (!(Tile & (V_FLIP | H_FLIP))) { \ + bp = pCache + BPSTART; \ + for(l = LineCount; l > 0; l--, bp += 8*PITCH, Offset += GFX.PPL) { \ + DRAW_PIXEL(0,Pix=bp[0]); \ + DRAW_PIXEL(1,Pix=bp[1]); \ + DRAW_PIXEL(2,Pix=bp[2]); \ + DRAW_PIXEL(3,Pix=bp[3]); \ + DRAW_PIXEL(4,Pix=bp[4]); \ + DRAW_PIXEL(5,Pix=bp[5]); \ + DRAW_PIXEL(6,Pix=bp[6]); \ + DRAW_PIXEL(7,Pix=bp[7]); \ + } \ + } else if(!(Tile & V_FLIP)) { \ + bp = pCache + BPSTART; \ + for(l = LineCount; l > 0; l--, bp += 8*PITCH, Offset += GFX.PPL) { \ + DRAW_PIXEL(0,Pix=bp[7]); \ + DRAW_PIXEL(1,Pix=bp[6]); \ + DRAW_PIXEL(2,Pix=bp[5]); \ + DRAW_PIXEL(3,Pix=bp[4]); \ + DRAW_PIXEL(4,Pix=bp[3]); \ + DRAW_PIXEL(5,Pix=bp[2]); \ + DRAW_PIXEL(6,Pix=bp[1]); \ + DRAW_PIXEL(7,Pix=bp[0]); \ + } \ + } else if(!(Tile & H_FLIP)) { \ + bp = pCache + 56 - BPSTART; \ + for(l = LineCount; l > 0; l--, bp -= 8*PITCH, Offset += GFX.PPL) { \ + DRAW_PIXEL(0,Pix=bp[0]); \ + DRAW_PIXEL(1,Pix=bp[1]); \ + DRAW_PIXEL(2,Pix=bp[2]); \ + DRAW_PIXEL(3,Pix=bp[3]); \ + DRAW_PIXEL(4,Pix=bp[4]); \ + DRAW_PIXEL(5,Pix=bp[5]); \ + DRAW_PIXEL(6,Pix=bp[6]); \ + DRAW_PIXEL(7,Pix=bp[7]); \ + } \ + } else { \ + bp = pCache + 56 - BPSTART; \ + for(l = LineCount; l > 0; l--, bp -= 8*PITCH, Offset += GFX.PPL) { \ + DRAW_PIXEL(0,Pix=bp[7]); \ + DRAW_PIXEL(1,Pix=bp[6]); \ + DRAW_PIXEL(2,Pix=bp[5]); \ + DRAW_PIXEL(3,Pix=bp[4]); \ + DRAW_PIXEL(4,Pix=bp[3]); \ + DRAW_PIXEL(5,Pix=bp[2]); \ + DRAW_PIXEL(6,Pix=bp[1]); \ + DRAW_PIXEL(7,Pix=bp[0]); \ + } \ + } + +#define NAME1 DrawTile16 +#define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 LineCount + +// Second-level include: Get the DrawTile16 renderers +#include "tile.cpp" + +#undef NAME1 +#undef ARGS +#undef DRAW_TILE +#undef Z1 +#undef Z2 + +/*****************************************************************************/ +// Basic routine to render a clipped tile. Inputs same as above. + +#define Z1 GFX.Z1 +#define Z2 GFX.Z2 +#define DRAW_TILE() \ + uint8 *pCache; \ + register int32 l; \ + register uint8 *bp, Pix, w; \ +\ + GET_CACHED_TILE(); \ + if(IS_BLANK_TILE()) return; \ + SELECT_PALETTE(); \ +\ + if (!(Tile & (V_FLIP | H_FLIP))) { \ + bp = pCache + BPSTART; \ + for(l = LineCount; l > 0; l--, bp += 8*PITCH, Offset += GFX.PPL) { \ + w=Width; \ + switch(StartPixel){ \ + case 0: DRAW_PIXEL(0,Pix=bp[0]); if(!--w) break; \ + case 1: DRAW_PIXEL(1,Pix=bp[1]); if(!--w) break; \ + case 2: DRAW_PIXEL(2,Pix=bp[2]); if(!--w) break; \ + case 3: DRAW_PIXEL(3,Pix=bp[3]); if(!--w) break; \ + case 4: DRAW_PIXEL(4,Pix=bp[4]); if(!--w) break; \ + case 5: DRAW_PIXEL(5,Pix=bp[5]); if(!--w) break; \ + case 6: DRAW_PIXEL(6,Pix=bp[6]); if(!--w) break; \ + case 7: DRAW_PIXEL(7,Pix=bp[7]); break; \ + } \ + } \ + } else if(!(Tile & V_FLIP)) { \ + bp = pCache + BPSTART; \ + for(l = LineCount; l > 0; l--, bp += 8*PITCH, Offset += GFX.PPL) { \ + w=Width; \ + switch(StartPixel){ \ + case 0: DRAW_PIXEL(0,Pix=bp[7]); if(!--w) break; \ + case 1: DRAW_PIXEL(1,Pix=bp[6]); if(!--w) break; \ + case 2: DRAW_PIXEL(2,Pix=bp[5]); if(!--w) break; \ + case 3: DRAW_PIXEL(3,Pix=bp[4]); if(!--w) break; \ + case 4: DRAW_PIXEL(4,Pix=bp[3]); if(!--w) break; \ + case 5: DRAW_PIXEL(5,Pix=bp[2]); if(!--w) break; \ + case 6: DRAW_PIXEL(6,Pix=bp[1]); if(!--w) break; \ + case 7: DRAW_PIXEL(7,Pix=bp[0]); break; \ + } \ + } \ + } else if(!(Tile & H_FLIP)) { \ + bp = pCache + 56 - BPSTART; \ + for(l = LineCount; l > 0; l--, bp -= 8*PITCH, Offset += GFX.PPL) { \ + w=Width; \ + switch(StartPixel){ \ + case 0: DRAW_PIXEL(0,Pix=bp[0]); if(!--w) break; \ + case 1: DRAW_PIXEL(1,Pix=bp[1]); if(!--w) break; \ + case 2: DRAW_PIXEL(2,Pix=bp[2]); if(!--w) break; \ + case 3: DRAW_PIXEL(3,Pix=bp[3]); if(!--w) break; \ + case 4: DRAW_PIXEL(4,Pix=bp[4]); if(!--w) break; \ + case 5: DRAW_PIXEL(5,Pix=bp[5]); if(!--w) break; \ + case 6: DRAW_PIXEL(6,Pix=bp[6]); if(!--w) break; \ + case 7: DRAW_PIXEL(7,Pix=bp[7]); break; \ + } \ + } \ + } else { \ + bp = pCache + 56 - BPSTART; \ + for(l = LineCount; l > 0; l--, bp -= 8*PITCH, Offset += GFX.PPL) { \ + w=Width; \ + switch(StartPixel){ \ + case 0: DRAW_PIXEL(0,Pix=bp[7]); if(!--w) break; \ + case 1: DRAW_PIXEL(1,Pix=bp[6]); if(!--w) break; \ + case 2: DRAW_PIXEL(2,Pix=bp[5]); if(!--w) break; \ + case 3: DRAW_PIXEL(3,Pix=bp[4]); if(!--w) break; \ + case 4: DRAW_PIXEL(4,Pix=bp[3]); if(!--w) break; \ + case 5: DRAW_PIXEL(5,Pix=bp[2]); if(!--w) break; \ + case 6: DRAW_PIXEL(6,Pix=bp[1]); if(!--w) break; \ + case 7: DRAW_PIXEL(7,Pix=bp[0]); break; \ + } \ + } \ + } + +#define NAME1 DrawClippedTile16 +#define ARGS uint32 Tile, uint32 Offset, uint32 StartPixel, uint32 Width, uint32 StartLine, uint32 LineCount + +// Second-level include: Get the DrawClippedTile16 renderers +#include "tile.cpp" + +#undef NAME1 +#undef ARGS +#undef DRAW_TILE +#undef Z1 +#undef Z2 + +/*****************************************************************************/ +// Basic routine to render a single mosaic pixel. DRAW_PIXEL, BPSTART, Z1, Z2 +// and Pix are the same as above, but PITCH is not used. + +#define Z1 GFX.Z1 +#define Z2 GFX.Z2 +#define DRAW_TILE() \ + uint8 *pCache; \ + register int32 l, w; \ + register uint8 Pix; \ +\ + GET_CACHED_TILE(); \ + if(IS_BLANK_TILE()) return; \ + SELECT_PALETTE(); \ +\ + if (Tile & H_FLIP) StartPixel = 7 - StartPixel; \ + if (Tile & V_FLIP) { \ + Pix = pCache[56 - BPSTART + StartPixel]; \ + } else { \ + Pix = pCache[BPSTART + StartPixel]; \ + } \ + if(Pix){ \ + for(l = LineCount; l > 0; l--, Offset += GFX.PPL) { \ + for(w = Width-1; w>=0; w--) { \ + DRAW_PIXEL(w,1); \ + } \ + } \ + } + +#define NAME1 DrawMosaicPixel16 +#define ARGS uint32 Tile, uint32 Offset, uint32 StartLine, uint32 StartPixel, uint32 Width, uint32 LineCount + +// Second-level include: Get the DrawMosaicPixel16 renderers +#include "tile.cpp" + +#undef NAME1 +#undef ARGS +#undef DRAW_TILE +#undef Z1 +#undef Z2 + +/*****************************************************************************/ +// Basic routine to render the backdrop. DRAW_PIXEL is the same as above, but +// since we're just replicating a single pixel there's no need for PITCH or +// BPSTART (or interlace at all, really). The backdrop is always depth=1, so +// Z1=Z2=1. And backdrop is always color 0. + +#define NO_INTERLACE 1 +#define Z1 1 +#define Z2 1 +#define Pix 0 +#define DRAW_TILE() \ + register uint32 l, x; \ +\ + GFX.RealScreenColors = IPPU.ScreenColors; \ + GFX.ScreenColors = GFX.ClipColors?BlackColourMap:GFX.RealScreenColors; \ +\ + for(l=GFX.StartY; l<=GFX.EndY; l++, Offset+=GFX.PPL) { \ + for(x=Left; xM7HOFS << 19) >> 19; \ + int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \ +\ + int32 CentreX = ((int32) l->CentreX << 19) >> 19; \ + int32 CentreY = ((int32) l->CentreY << 19) >> 19; \ +\ + if (PPU.Mode7VFlip) { \ + starty = 255 - (int) (Line+1); \ + } else { \ + starty = Line+1; \ + } \ +\ + yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \ +\ + int BB = ((l->MatrixB*starty)&~63) + ((l->MatrixB*yy)&~63) + (CentreX << 8); \ + int DD = ((l->MatrixD*starty)&~63) + ((l->MatrixD*yy)&~63) + (CentreY << 8); \ +\ + if(PPU.Mode7HFlip) { \ + startx = Right - 1; \ + aa = -l->MatrixA; \ + cc = -l->MatrixC; \ + } else { \ + startx = Left; \ + aa = l->MatrixA; \ + cc = l->MatrixC; \ + } \ +\ + int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \ + int AA = l->MatrixA*startx + ((l->MatrixA*xx)&~63); \ + int CC = l->MatrixC*startx + ((l->MatrixC*xx)&~63); \ + uint8 Pix; \ +\ + if(!PPU.Mode7Repeat) { \ + for(uint32 x = Left; x> 8) & 0x3ff; \ + int Y = ((CC + DD) >> 8) & 0x3ff; \ + uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ + uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ + DRAW_PIXEL(x, Pix=(b&MASK)); \ + } \ + } else { \ + for(uint32 x = Left; x> 8); \ + int Y = ((CC + DD) >> 8); \ +\ + uint8 b; \ + if (((X | Y) & ~0x3ff) == 0) { \ + uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ + b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ + } else if(PPU.Mode7Repeat == 3) { \ + b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \ + } else { \ + continue; \ + } \ + DRAW_PIXEL(x, Pix=(b&MASK)); \ + } \ + } \ + } + +#define DRAW_TILE_MOSAIC() \ + uint8 *VRAM1 = Memory.VRAM + 1; \ +\ + if(DCMODE) { \ + if(IPPU.DirectColourMapsNeedRebuild) S9xBuildDirectColourMaps(); \ + GFX.RealScreenColors = DirectColourMaps[0]; \ + } else { \ + GFX.RealScreenColors = IPPU.ScreenColors; \ + } \ + GFX.ScreenColors = GFX.ClipColors?BlackColourMap:GFX.RealScreenColors; \ +\ + int aa, cc; \ + int startx, StartY=GFX.StartY; \ + int HMosaic=1, VMosaic=1, MosaicStart=0; \ + int32 MLeft=Left, MRight=Right; \ + if(PPU.BGMosaic[0]){ \ + VMosaic=PPU.Mosaic; \ + MosaicStart=((uint32)GFX.StartY-PPU.MosaicStart)%VMosaic; \ + StartY-=MosaicStart; \ + } \ + if(PPU.BGMosaic[BG]){ \ + HMosaic=PPU.Mosaic; \ + MLeft-=MLeft%HMosaic; \ + MRight+=HMosaic-1; MRight-=MRight%HMosaic; \ + } \ +\ + uint32 Offset = StartY * GFX.PPL; \ + struct SLineMatrixData *l = &LineMatrixData[StartY]; \ +\ + for(uint32 Line = StartY; Line <= GFX.EndY; Line+=VMosaic, Offset+=VMosaic*GFX.PPL, l+=VMosaic) { \ + if(Line+VMosaic>GFX.EndY) VMosaic=GFX.EndY-Line+1; \ + int yy, starty; \ +\ + int32 HOffset = ((int32) l->M7HOFS << 19) >> 19; \ + int32 VOffset = ((int32) l->M7VOFS << 19) >> 19; \ +\ + int32 CentreX = ((int32) l->CentreX << 19) >> 19; \ + int32 CentreY = ((int32) l->CentreY << 19) >> 19; \ +\ + if (PPU.Mode7VFlip) { \ + starty = 255 - (int) (Line+1); \ + } else { \ + starty = Line+1; \ + } \ +\ + yy = CLIP_10_BIT_SIGNED(VOffset - CentreY); \ +\ + int BB = ((l->MatrixB*starty)&~63) + ((l->MatrixB*yy)&~63) + (CentreX << 8); \ + int DD = ((l->MatrixD*starty)&~63) + ((l->MatrixD*yy)&~63) + (CentreY << 8); \ +\ + if(PPU.Mode7HFlip) { \ + startx = MRight - 1; \ + aa = -l->MatrixA; \ + cc = -l->MatrixC; \ + } else { \ + startx = MLeft; \ + aa = l->MatrixA; \ + cc = l->MatrixC; \ + } \ +\ + int xx = CLIP_10_BIT_SIGNED(HOffset - CentreX); \ + int AA = l->MatrixA*startx + ((l->MatrixA*xx)&~63); \ + int CC = l->MatrixC*startx + ((l->MatrixC*xx)&~63); \ + uint8 Pix; \ + uint8 ctr=1; \ +\ + if(!PPU.Mode7Repeat) { \ + for(int32 x = MLeft; x> 8) & 0x3ff; \ + int Y = ((CC + DD) >> 8) & 0x3ff; \ + uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ + uint8 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ + if((Pix=(b&MASK))){ \ + for(int32 h=MosaicStart; h=x; w--){ \ + DRAW_PIXEL(w+h*GFX.PPL, (w>=(int32)Left && w<(int32)Right)); \ + } \ + } \ + } \ + } \ + } else { \ + for(int32 x = MLeft; x> 8); \ + int Y = ((CC + DD) >> 8); \ +\ + uint8 b; \ + if (((X | Y) & ~0x3ff) == 0) { \ + uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \ + b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \ + } else if(PPU.Mode7Repeat == 3) { \ + b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \ + } else { \ + continue; \ + } \ + if((Pix=(b&MASK))){ \ + for(int32 h=MosaicStart; h=x; w--){ \ + DRAW_PIXEL(w+h*GFX.PPL, (w>=(int32)Left && w<(int32)Right)); \ + } \ + } \ + } \ + } \ + } \ + MosaicStart=0; \ + } + +#define DRAW_TILE() DRAW_TILE_NORMAL() +#define NAME1 DrawMode7BG1 +#define ARGS uint32 Left, uint32 Right, int D + +// Second-level include: Get the DrawMode7BG1 renderers +#include "tile.cpp" + +#undef NAME1 +#undef DRAW_TILE +#define DRAW_TILE() DRAW_TILE_MOSAIC() +#define NAME1 DrawMode7MosaicBG1 + +// Second-level include: Get the DrawMode7MosaicBG1 renderers +#include "tile.cpp" + +#undef DRAW_TILE +#undef NAME1 +#undef Z1 +#undef Z2 +#undef MASK +#undef DCMODE +#undef BG + +#define NAME1 DrawMode7BG2 +#define DRAW_TILE() DRAW_TILE_NORMAL() +#define Z1 D+((b&0x80)?11:3) +#define Z2 D+((b&0x80)?11:3) +#define MASK 0x7f +#define DCMODE 0 +#define BG 1 + +// Second-level include: Get the DrawMode7BG2 renderers +#include "tile.cpp" + +#undef NAME1 +#undef DRAW_TILE +#define DRAW_TILE() DRAW_TILE_MOSAIC() +#define NAME1 DrawMode7MosaicBG2 + +// Second-level include: Get the DrawMode7MosaicBG2 renderers +#include "tile.cpp" + +#undef MASK +#undef DCMODE +#undef BG +#undef NAME1 +#undef ARGS +#undef DRAW_TILE +#undef DRAW_TILE_NORMAL +#undef DRAW_TILE_MOSAIC +#undef Z1 +#undef Z2 +#undef NO_INTERLACE + +/*===========================================================================*/ +#else // Second-level: Get all NAME1 renderers +#ifndef NAME2 +/*===========================================================================*/ + +#define BPSTART StartLine +#define PITCH 1 + +// The 1x1 pixel plotter, for speedhacking modes. +#define DRAW_PIXEL(N,M) \ + if(Z1>GFX.DB[Offset+N] && (M)){ \ + GFX.S[Offset+N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset+N], GFX.SubZBuffer[Offset+N]); \ + GFX.DB[Offset+N] = Z2; \ + } +#define NAME2 Normal1x1 +// Third-level include: get the Normal1x1 renderers +#include "tile.cpp" +#undef NAME2 +#undef DRAW_PIXEL + +// The 2x1 pixel plotter, for normal rendering when we've used hires/interlace +// already this frame. +#define DRAW_PIXEL_N2x1(N,M) \ + if(Z1>GFX.DB[Offset+2*N] && (M)){ \ + GFX.S[Offset+2*N] = GFX.S[Offset+2*N+1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset+2*N], GFX.SubZBuffer[Offset+2*N]); \ + GFX.DB[Offset+2*N] = GFX.DB[Offset+2*N+1] = Z2; \ + } +#define DRAW_PIXEL(N,M) DRAW_PIXEL_N2x1(N,M) +#define NAME2 Normal2x1 +// Third-level include: get the Normal2x1 renderers +#include "tile.cpp" +#undef NAME2 +#undef DRAW_PIXEL + +// Hires pixel plotter, this combines the main and subscreen pixels as +// appropriate to render hires or pseudo-hires images. Use it only on the main +// screen, subscreen should use Normal2x1 instead. +/* Hires math: + * Main pixel is mathed as normal: Main(x,y)*Sub(x,y) + * Sub pixel is mathed somewhat weird: Basically, for Sub(x+1,y) we apply the + * same operation we applied to Main(x,y) (e.g. no math, add fixed, add1/2 + * subscreen) using Main(x,y) as the "corresponding subscreen pixel". + * Also, color window clipping clips Sub(x+1,y) iff Main(x,y) is clipped, + * not Main(x+1,y). + * We don't know how Sub(0,y) is handled. + */ +#define DRAW_PIXEL_H2x1(N,M) \ + if(Z1>GFX.DB[Offset+2*N] && (M)){ \ + GFX.S[Offset+2*N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset+2*N], GFX.SubZBuffer[Offset+2*N]); \ + GFX.S[Offset+2*N+1] = MATH((GFX.ClipColors?0:GFX.SubScreen[Offset+2*N+2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset+2*N]); \ + GFX.DB[Offset+2*N] = GFX.DB[Offset+2*N+1] = Z2; \ + } +#define DRAW_PIXEL(N,M) DRAW_PIXEL_H2x1(N,M) +#define NAME2 Hires +// Third-level include: get the Hires renderers +#include "tile.cpp" +#undef NAME2 +#undef DRAW_PIXEL + +/* Interlace: Only draw every other line, so we'll redefine BPSTART and PITCH + * to do so. Otherwise, it's the same as Normal2x1/Hires2x1. + */ + +#undef BPSTART +#undef PITCH +#define BPSTART (StartLine*2+BG.InterlaceLine) +#define PITCH 2 + +#ifndef NO_INTERLACE + +#define DRAW_PIXEL(N,M) DRAW_PIXEL_N2x1(N,M) +#define NAME2 Interlace +// Third-level include: get the Interlace renderers +#include "tile.cpp" +#undef NAME2 +#undef DRAW_PIXEL + +#define DRAW_PIXEL(N,M) DRAW_PIXEL_H2x1(N,M) +#define NAME2 HiresInterlace +// Third-level include: get the HiresInterlace renderers +#include "tile.cpp" +#undef NAME2 +#undef DRAW_PIXEL + +#endif /* NO_INTERLACE */ + +#undef BPSTART +#undef PITCH + +/*===========================================================================*/ +#else // Third-level: Renderers for each math mode for NAME1 + NAME2 +/*===========================================================================*/ + +#define CONCAT3(A,B,C) A##B##C +#define MAKENAME(A,B,C) CONCAT3(A,B,C) + +static void MAKENAME(NAME1,_,NAME2) (ARGS) +{ +#define MATH(A,B,C) NOMATH(x,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,Add_,NAME2) (ARGS) +{ +#define MATH(A,B,C) REGMATH(ADD,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,AddF1_2_,NAME2) (ARGS) +{ +#define MATH(A,B,C) MATHF1_2(ADD,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,AddS1_2_,NAME2) (ARGS) +{ +#define MATH(A,B,C) MATHS1_2(ADD,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,Sub_,NAME2) (ARGS) +{ +#define MATH(A,B,C) REGMATH(SUB,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,SubF1_2_,NAME2) (ARGS) +{ +#define MATH(A,B,C) MATHF1_2(SUB,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void MAKENAME(NAME1,SubS1_2_,NAME2) (ARGS) +{ +#define MATH(A,B,C) MATHS1_2(SUB,A,B,C) + DRAW_TILE(); +#undef MATH +} + +static void (*MAKENAME(Renderers_,NAME1,NAME2)[7])(ARGS)={ + MAKENAME(NAME1,_,NAME2), + MAKENAME(NAME1,Add_,NAME2), + MAKENAME(NAME1,AddF1_2_,NAME2), + MAKENAME(NAME1,AddS1_2_,NAME2), + MAKENAME(NAME1,Sub_,NAME2), + MAKENAME(NAME1,SubF1_2_,NAME2), + MAKENAME(NAME1,SubS1_2_,NAME2) +}; + +#undef MAKENAME +#undef CONCAT3 + +#endif +#endif +#endif diff --git a/source/snes9x/tile.h b/source/snes9x/tile.h new file mode 100644 index 0000000..0f35141 --- /dev/null +++ b/source/snes9x/tile.h @@ -0,0 +1,151 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _TILE_H_ +#define _TILE_H_ + +void S9xInitTileRenderer(void); +void S9xSelectTileRenderers(int BGMode, bool8 sub, bool8 obj); +void S9xSelectTileConverter(int depth, bool8 hires, bool8 sub, bool8 mosaic); + +#endif diff --git a/source/snes9x/unused/cheats.cpp b/source/snes9x/unused/cheats.cpp new file mode 100644 index 0000000..50907f3 --- /dev/null +++ b/source/snes9x/unused/cheats.cpp @@ -0,0 +1,499 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include +#include +#include "snes9x.h" +#include "cheats.h" +#include "memmap.h" + +static bool8 S9xAllHex (const char *code, int len) +{ + for (int i = 0; i < len; i++) + if ((code [i] < '0' || code [i] > '9') && + (code [i] < 'a' || code [i] > 'f') && + (code [i] < 'A' || code [i] > 'F')) + return (FALSE); + + return (TRUE); +} + +const char *S9xProActionReplayToRaw (const char *code, uint32 &address, uint8 &byte) +{ + uint32 data = 0; + if (strlen (code) != 8 || !S9xAllHex (code, 8) || + sscanf (code, "%x", &data) != 1) + return ("Invalid Pro Action Replay code - should be 8 hex digits in length."); + + address = data >> 8; + byte = (uint8) data; + return (NULL); +} + +const char *S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram, + uint8 &num_bytes, uint8 bytes[3]) +{ + char tmp [15]; + if (strlen (code) != 14) + return ("Invalid Gold Finger code should be 14 hex digits in length."); + + strncpy (tmp, code, 5); + tmp [5] = 0; + if (sscanf (tmp, "%x", &address) != 1) + return ("Invalid Gold Finger code."); + + int i; + for (i = 0; i < 3; i++) + { + strncpy (tmp, code + 5 + i * 2, 2); + tmp [2] = 0; + unsigned int byte; + if (sscanf (tmp, "%x", &byte) != 1) + break; + bytes [i] = (uint8) byte; + } + num_bytes = i; + sram = code [13] == '1'; + return (NULL); +} + +const char *S9xGameGenieToRaw (const char *code, uint32 &address, uint8 &byte) +{ + char new_code [12]; + + if (strlen (code) != 9 || *(code + 4) != '-' || !S9xAllHex (code, 4) || + !S9xAllHex (code + 5, 4)) + return ("Invalid Game Genie(tm) code - should be 'xxxx-xxxx'."); + + strcpy (new_code, "0x"); + strncpy (new_code + 2, code, 4); + strcpy (new_code + 6, code + 5); + + static char *real_hex = "0123456789ABCDEF"; + static char *genie_hex = "DF4709156BC8A23E"; + + for (int i = 2; i < 10; i++) + { + if (islower (new_code [i])) + new_code [i] = toupper (new_code [i]); + int j; + for (j = 0; j < 16; j++) + { + if (new_code [i] == genie_hex [j]) + { + new_code [i] = real_hex [j]; + break; + } + } + if (j == 16) + return ("Invalid hex-character in Game Genie(tm) code"); + } + uint32 data = 0; + sscanf (new_code, "%x", &data); + byte = (uint8)(data >> 24); + address = data & 0xffffff; + address = ((address & 0x003c00) << 10) + + ((address & 0x00003c) << 14) + + ((address & 0xf00000) >> 8) + + ((address & 0x000003) << 10) + + ((address & 0x00c000) >> 6) + + ((address & 0x0f0000) >> 12) + + ((address & 0x0003c0) >> 6); + + return (NULL); +} + +void S9xStartCheatSearch (SCheatData *d) +{ + memmove (d->CWRAM, d->RAM, 0x20000); + memmove (d->CSRAM, d->SRAM, 0x10000); + memmove (d->CIRAM, &d->FillRAM [0x3000], 0x2000); + memset ((char *) d->WRAM_BITS, 0xff, 0x20000 >> 3); + memset ((char *) d->SRAM_BITS, 0xff, 0x10000 >> 3); + memset ((char *) d->IRAM_BITS, 0xff, 0x2000 >> 3); +} + +#define BIT_CLEAR(a,v) \ +(a)[(v) >> 5] &= ~(1 << ((v) & 31)) + +#define BIT_SET(a,v) \ +(a)[(v) >> 5] |= 1 << ((v) & 31) + +#define TEST_BIT(a,v) \ +((a)[(v) >> 5] & (1 << ((v) & 31))) + +#ifdef NGC +#undef _C /*** Stops powerpc-gekko-g++ complaining -;) ***/ +#endif + +#define _C(c,a,b) \ +((c) == S9X_LESS_THAN ? (a) < (b) : \ + (c) == S9X_GREATER_THAN ? (a) > (b) : \ + (c) == S9X_LESS_THAN_OR_EQUAL ? (a) <= (b) : \ + (c) == S9X_GREATER_THAN_OR_EQUAL ? (a) >= (b) : \ + (c) == S9X_EQUAL ? (a) == (b) : \ + (a) != (b)) + +#define _D(s,m,o) \ +((s) == S9X_8_BITS ? (uint8) (*((m) + (o))) : \ + (s) == S9X_16_BITS ? ((uint16) (*((m) + (o)) + (*((m) + (o) + 1) << 8))) : \ + (s) == S9X_24_BITS ? ((uint32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16))) : \ +((uint32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16) + (*((m) + (o) + 3) << 24)))) + +#define _DS(s,m,o) \ +((s) == S9X_8_BITS ? ((int8) *((m) + (o))) : \ + (s) == S9X_16_BITS ? ((int16) (*((m) + (o)) + (*((m) + (o) + 1) << 8))) : \ + (s) == S9X_24_BITS ? (((int32) ((*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16)) << 8)) >> 8): \ + ((int32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16) + (*((m) + (o) + 3) << 24)))) + +void S9xSearchForChange (SCheatData *d, S9xCheatComparisonType cmp, + S9xCheatDataSize size, bool8 is_signed, bool8 update) +{ + int l; + + switch (size) + { + case S9X_8_BITS: l = 0; break; + case S9X_16_BITS: l = 1; break; + case S9X_24_BITS: l = 2; break; + default: + case S9X_32_BITS: l = 3; break; + } + + int i; + if (is_signed) + { + for (i = 0; i < 0x20000 - l; i++) + { + if (TEST_BIT (d->WRAM_BITS, i) && + _C(cmp, _DS(size, d->RAM, i), _DS(size, d->CWRAM, i))) + { + if (update) + d->CWRAM [i] = d->RAM [i]; + } + else + BIT_CLEAR (d->WRAM_BITS, i); + } + + for (i = 0; i < 0x10000 - l; i++) + { + if (TEST_BIT (d->SRAM_BITS, i) && + _C(cmp, _DS(size, d->SRAM, i), _DS(size, d->CSRAM, i))) + { + if (update) + d->CSRAM [i] = d->SRAM [i]; + } + else + BIT_CLEAR (d->SRAM_BITS, i); + } + + for (i = 0; i < 0x2000 - l; i++) + { + if (TEST_BIT (d->IRAM_BITS, i) && + _C(cmp, _DS(size, d->FillRAM + 0x3000, i), _DS(size, d->CIRAM, i))) + { + if (update) + d->CIRAM [i] = d->FillRAM [i + 0x3000]; + } + else + BIT_CLEAR (d->IRAM_BITS, i); + } + } + else + { + for (i = 0; i < 0x20000 - l; i++) + { + if (TEST_BIT (d->WRAM_BITS, i) && + _C(cmp, _D(size, d->RAM, i), _D(size, d->CWRAM, i))) + { + if (update) + d->CWRAM [i] = d->RAM [i]; + } + else + BIT_CLEAR (d->WRAM_BITS, i); + } + + for (i = 0; i < 0x10000 - l; i++) + { + if (TEST_BIT (d->SRAM_BITS, i) && + _C(cmp, _D(size, d->SRAM, i), _D(size, d->CSRAM, i))) + { + if (update) + d->CSRAM [i] = d->SRAM [i]; + } + else + BIT_CLEAR (d->SRAM_BITS, i); + } + + for (i = 0; i < 0x2000 - l; i++) + { + if (TEST_BIT (d->IRAM_BITS, i) && + _C(cmp, _D(size, d->FillRAM + 0x3000, i), _D(size, d->CIRAM, i))) + { + if (update) + d->CIRAM [i] = d->FillRAM [i + 0x3000]; + } + else + BIT_CLEAR (d->IRAM_BITS, i); + } + } +} + +void S9xSearchForValue (SCheatData *d, S9xCheatComparisonType cmp, + S9xCheatDataSize size, uint32 value, + bool8 is_signed, bool8 update) +{ + int l; + + switch (size) + { + case S9X_8_BITS: l = 0; break; + case S9X_16_BITS: l = 1; break; + case S9X_24_BITS: l = 2; break; + default: + case S9X_32_BITS: l = 3; break; + } + + int i; + + if (is_signed) + { + for (i = 0; i < 0x20000 - l; i++) + { + if (TEST_BIT (d->WRAM_BITS, i) && + _C(cmp, _DS(size, d->RAM, i), (int32) value)) + { + if (update) + d->CWRAM [i] = d->RAM [i]; + } + else + BIT_CLEAR (d->WRAM_BITS, i); + } + + for (i = 0; i < 0x10000 - l; i++) + { + if (TEST_BIT (d->SRAM_BITS, i) && + _C(cmp, _DS(size, d->SRAM, i), (int32) value)) + { + if (update) + d->CSRAM [i] = d->SRAM [i]; + } + else + BIT_CLEAR (d->SRAM_BITS, i); + } + + for (i = 0; i < 0x2000 - l; i++) + { + if (TEST_BIT (d->IRAM_BITS, i) && + _C(cmp, _DS(size, d->FillRAM + 0x3000, i), (int32) value)) + { + if (update) + d->CIRAM [i] = d->FillRAM [i + 0x3000]; + } + else + BIT_CLEAR (d->IRAM_BITS, i); + } + } + else + { + for (i = 0; i < 0x20000 - l; i++) + { + if (TEST_BIT (d->WRAM_BITS, i) && + _C(cmp, _D(size, d->RAM, i), value)) + { + if (update) + d->CWRAM [i] = d->RAM [i]; + } + else + BIT_CLEAR (d->WRAM_BITS, i); + } + + for (i = 0; i < 0x10000 - l; i++) + { + if (TEST_BIT (d->SRAM_BITS, i) && + _C(cmp, _D(size, d->SRAM, i), value)) + { + if (update) + d->CSRAM [i] = d->SRAM [i]; + } + else + BIT_CLEAR (d->SRAM_BITS, i); + } + + for (i = 0; i < 0x2000 - l; i++) + { + if (TEST_BIT (d->IRAM_BITS, i) && + _C(cmp, _D(size, d->FillRAM + 0x3000, i), value)) + { + if (update) + d->CIRAM [i] = d->FillRAM [i + 0x3000]; + } + else + BIT_CLEAR (d->IRAM_BITS, i); + } + } +} + +void S9xOutputCheatSearchResults (SCheatData *d) +{ + int i; + for (i = 0; i < 0x20000; i++) + { + if (TEST_BIT (d->WRAM_BITS, i)) + printf ("WRAM: %05x: %02x\n", i, d->RAM [i]); + } + + for (i = 0; i < 0x10000; i++) + { + if (TEST_BIT (d->SRAM_BITS, i)) + printf ("SRAM: %04x: %02x\n", i, d->SRAM [i]); + } + + for (i = 0; i < 0x2000; i++) + { + if (TEST_BIT (d->IRAM_BITS, i)) + printf ("IRAM: %05x: %02x\n", i, d->FillRAM [i + 0x3000]); + } +} + diff --git a/source/snes9x/unused/cheats.h b/source/snes9x/unused/cheats.h new file mode 100644 index 0000000..3786602 --- /dev/null +++ b/source/snes9x/unused/cheats.h @@ -0,0 +1,213 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _CHEATS_H_ +#define _CHEATS_H_ + +struct SCheat +{ + uint32 address; + uint8 byte; + uint8 saved_byte; + bool8 enabled; + bool8 saved; + char name [22]; +}; + +#define MAX_CHEATS 75 + +struct SCheatData +{ + struct SCheat c [MAX_CHEATS]; + uint32 num_cheats; + uint8 CWRAM [0x20000]; + uint8 CSRAM [0x10000]; + uint8 CIRAM [0x2000]; + uint8 *RAM; + uint8 *FillRAM; + uint8 *SRAM; + uint32 WRAM_BITS [0x20000 >> 3]; + uint32 SRAM_BITS [0x10000 >> 3]; + uint32 IRAM_BITS [0x2000 >> 3]; +}; + +typedef enum +{ + S9X_LESS_THAN, S9X_GREATER_THAN, S9X_LESS_THAN_OR_EQUAL, + S9X_GREATER_THAN_OR_EQUAL, S9X_EQUAL, S9X_NOT_EQUAL +} S9xCheatComparisonType; + +typedef enum +{ + S9X_8_BITS, S9X_16_BITS, S9X_24_BITS, S9X_32_BITS +} S9xCheatDataSize; + +void S9xInitCheatData (); + +const char *S9xGameGenieToRaw (const char *code, uint32 &address, uint8 &byte); +const char *S9xProActionReplayToRaw (const char *code, uint32 &address, uint8 &byte); +const char *S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram, + uint8 &num_bytes, uint8 bytes[3]); +void S9xApplyCheats (); +void S9xApplyCheat (uint32 which1); +void S9xRemoveCheats (); +void S9xRemoveCheat (uint32 which1); +void S9xEnableCheat (uint32 which1); +void S9xDisableCheat (uint32 which1); +void S9xAddCheat (bool8 enable, bool8 save_current_value, uint32 address, + uint8 byte); +void S9xDeleteCheats (); +void S9xDeleteCheat (uint32 which1); +bool8 S9xLoadCheatFile (const char *filename); +bool8 S9xSaveCheatFile (const char *filename); + +void S9xStartCheatSearch (SCheatData *); +void S9xSearchForChange (SCheatData *, S9xCheatComparisonType cmp, + S9xCheatDataSize size, bool8 is_signed, bool8 update); +void S9xSearchForValue (SCheatData *, S9xCheatComparisonType cmp, + S9xCheatDataSize size, uint32 value, + bool8 is_signed, bool8 update); +void S9xOutputCheatSearchResults (SCheatData *); + +#endif + diff --git a/source/snes9x/unused/cheats2.cpp b/source/snes9x/unused/cheats2.cpp new file mode 100644 index 0000000..372a140 --- /dev/null +++ b/source/snes9x/unused/cheats2.cpp @@ -0,0 +1,338 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include +#include +#include "snes9x.h" +#include "cheats.h" +#include "memmap.h" + +extern SCheatData Cheat; + +void S9xInitCheatData () +{ + Cheat.RAM = Memory.RAM; + Cheat.SRAM = ::SRAM; + Cheat.FillRAM = Memory.FillRAM; +} + +void S9xAddCheat (bool8 enable, bool8 save_current_value, + uint32 address, uint8 byte) +{ + if (Cheat.num_cheats < sizeof (Cheat.c) / sizeof (Cheat. c [0])) + { + Cheat.c [Cheat.num_cheats].address = address; + Cheat.c [Cheat.num_cheats].byte = byte; +#ifdef __MACOSX__ + Cheat.c [Cheat.num_cheats].enabled = enable; +#else + Cheat.c [Cheat.num_cheats].enabled = TRUE; +#endif + if (save_current_value) + { + Cheat.c [Cheat.num_cheats].saved_byte = S9xGetByte (address); + Cheat.c [Cheat.num_cheats].saved = TRUE; + } + Cheat.num_cheats++; + } +} + +void S9xDeleteCheat (uint32 which1) +{ + if (which1 < Cheat.num_cheats) + { + if (Cheat.c [which1].enabled) + S9xRemoveCheat (which1); + + memmove (&Cheat.c [which1], &Cheat.c [which1 + 1], + sizeof (Cheat.c [0]) * (Cheat.num_cheats - which1 - 1)); + Cheat.num_cheats--; //MK: This used to set it to 0?? + } +} + +void S9xDeleteCheats () +{ + S9xRemoveCheats (); + Cheat.num_cheats = 0; +} + +void S9xEnableCheat (uint32 which1) +{ + if (which1 < Cheat.num_cheats && !Cheat.c [which1].enabled) + { + Cheat.c [which1].enabled = TRUE; + S9xApplyCheat (which1); + } +} + +void S9xDisableCheat (uint32 which1) +{ + if (which1 < Cheat.num_cheats && Cheat.c [which1].enabled) + { + S9xRemoveCheat (which1); + Cheat.c [which1].enabled = FALSE; + } +} + +void S9xRemoveCheat (uint32 which1) +{ + if (Cheat.c [which1].saved) + { + uint32 address = Cheat.c [which1].address; + + int block = ((address&0xffffff) >> MEMMAP_SHIFT); + uint8 *ptr = Memory.Map [block]; + + if (ptr >= (uint8 *) CMemory::MAP_LAST) + *(ptr + (address & 0xffff)) = Cheat.c [which1].saved_byte; + else + S9xSetByte (Cheat.c [which1].saved_byte, address); + } +} + +void S9xApplyCheat (uint32 which1) +{ + uint32 address = Cheat.c [which1].address; + + if (!Cheat.c [which1].saved) + Cheat.c [which1].saved_byte = S9xGetByte (address); + + int block = ((address&0xffffff) >> MEMMAP_SHIFT); + uint8 *ptr = Memory.Map [block]; + + if (ptr >= (uint8 *) CMemory::MAP_LAST) + *(ptr + (address & 0xffff)) = Cheat.c [which1].byte; + else + S9xSetByte (Cheat.c [which1].byte, address); + Cheat.c [which1].saved = TRUE; +} + +void S9xApplyCheats () +{ + if (Settings.ApplyCheats) + { + for (uint32 i = 0; i < Cheat.num_cheats; i++) + if (Cheat.c [i].enabled) + S9xApplyCheat (i); + } +} + +void S9xRemoveCheats () +{ + for (uint32 i = 0; i < Cheat.num_cheats; i++) + if (Cheat.c [i].enabled) + S9xRemoveCheat (i); +} + +bool8 S9xLoadCheatFile (const char *filename) +{ + Cheat.num_cheats = 0; + + FILE *fs = fopen (filename, "rb"); + uint8 data [28]; + + if (!fs) + return (FALSE); + + while (fread ((void *) data, 1, 28, fs) == 28) + { + Cheat.c [Cheat.num_cheats].enabled = (data [0] & 4) == 0; + Cheat.c [Cheat.num_cheats].byte = data [1]; + Cheat.c [Cheat.num_cheats].address = data [2] | (data [3] << 8) | (data [4] << 16); + Cheat.c [Cheat.num_cheats].saved_byte = data [5]; + Cheat.c [Cheat.num_cheats].saved = (data [0] & 8) != 0; + memmove (Cheat.c [Cheat.num_cheats].name, &data [8], 20); + Cheat.c [Cheat.num_cheats++].name [20] = 0; + } + fclose (fs); + + return (TRUE); +} + +bool8 S9xSaveCheatFile (const char *filename) +{ + if (Cheat.num_cheats == 0) + { + (void) remove (filename); + return (TRUE); + } + + FILE *fs = fopen (filename, "wb"); + uint8 data [28]; + + if (!fs) + return (FALSE); + + uint32 i; + for (i = 0; i < Cheat.num_cheats; i++) + { + memset (data, 0, 28); + if (i == 0) + { + data [6] = 254; + data [7] = 252; + } + if (!Cheat.c [i].enabled) + data [0] |= 4; + + if (Cheat.c [i].saved) + data [0] |= 8; + + data [1] = Cheat.c [i].byte; + data [2] = (uint8) Cheat.c [i].address; + data [3] = (uint8) (Cheat.c [i].address >> 8); + data [4] = (uint8) (Cheat.c [i].address >> 16); + data [5] = Cheat.c [i].saved_byte; + + memmove (&data [8], Cheat.c [i].name, 19); + if (fwrite (data, 28, 1, fs) != 1) + { + fclose (fs); + return (FALSE); + } + } + return (fclose (fs) == 0); +} + + diff --git a/source/snes9x/unused/conffile.cpp b/source/snes9x/unused/conffile.cpp new file mode 100644 index 0000000..48a3e33 --- /dev/null +++ b/source/snes9x/unused/conffile.cpp @@ -0,0 +1,429 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#include +#include +#include + +#include "conffile.h" + +using namespace std; + +ConfigFile::ConfigFile(void) { + data.clear(); +} + +void ConfigFile::Clear(void){ + data.clear(); +} + +bool ConfigFile::LoadFile(const char *filename){ + STREAM s; + bool ret=false; + const char *n, *n2; + + if((s=OPEN_STREAM(filename, "r"))){ + n=filename; + n2=strrchr(n, '/'); if(n2!=NULL) n=n2+1; + n2=strrchr(n, '\\'); if(n2!=NULL) n=n2+1; + LoadFile(new fReader(s), n); + CLOSE_STREAM(s); + ret = true; + } else { + fprintf(stderr, "Couldn't open conffile "); + perror(filename); + } + return ret; +} + + +void ConfigFile::LoadFile(Reader *r, const char *name){ + string l, key, val; + string section; + int i, line, line2; + bool eof; + + line=line2=0; + section.clear(); + do { + line=line2++; + l=r->getline(eof); + ConfigEntry::trim(l); + if(l.size()==0) continue; + + if(l[0]=='#' || l[0]==';'){ + // comment + continue; + } + + if(l[0]=='['){ + if(*l.rbegin()!=']'){ + if(name) fprintf(stderr, "%s:", name); + fprintf(stderr, "[%d]: Ignoring invalid section header\n", line); + continue; + } + section.assign(l, 1, l.size()-2); + continue; + } + + while(*l.rbegin()=='\\'){ + l.erase(l.size()-1); + line2++; + val=r->getline(eof); + if(eof){ + fprintf(stderr, "Unexpected EOF reading config file"); + if(name) fprintf(stderr, " '%s'", name); + fprintf(stderr, "\n"); + return; + } + ConfigEntry::trim(val); + l+=val; + } + i=l.find('='); + if(i<0){ + if(name) fprintf(stderr, "%s:", name); + fprintf(stderr, "[%d]: Ignoring invalid entry\n", line); + continue; + } + key=l.substr(0,i); ConfigEntry::trim(key); + val=l.substr(i+1); ConfigEntry::trim(val); + if(val[0]=='"' && *val.rbegin()=='"') val=val.substr(1, val.size()-2); + + ConfigEntry e(line, section, key, val); + data.erase(e); + data.insert(e); + } while(!eof); +} + +bool ConfigFile::SaveTo(const char *filename){ + string section; + FILE *fp; + + if((fp=fopen(filename, "w"))==NULL){ + fprintf(stderr, "Couldn't write conffile "); + perror(filename); + return false; + } + + section.clear(); + set tmp; + fprintf(fp, "# Config file output by snes9x\n"); + time_t t=time(NULL); + fprintf(fp, "# %s", ctime(&t)); + for(set::iterator j=data.begin(); ; j++){ + if(j==data.end() || j->section!=section){ + if(!tmp.empty()){ + fprintf(fp, "\n[%s]\n", section.c_str()); + for(set::iterator i=tmp.begin(); i!=tmp.end(); i++){ + string o=i->val; ConfigEntry::trim(o); + if(o!=i->val) o="\""+i->val+"\""; + fprintf(fp, "%s = %s\n", i->key.c_str(), o.c_str()); + } + } + if(j==data.end()) break; + section=j->section; + tmp.clear(); + } + tmp.insert(*j); + } + + fclose(fp); + return true; +} + + +/***********************************************/ + +string ConfigFile::Get(const char *key){ + set::iterator i; + i=data.find(ConfigEntry(key)); + return i->val; +} + +bool ConfigFile::Exists(const char *key){ + return data.find(ConfigEntry(key))!=data.end(); +} + + +string ConfigFile::GetString(const char *key, string def){ + if(!Exists(key)) return def; + return Get(key); +} + +char *ConfigFile::GetString(const char *key, char *out, uint32 outlen){ + if(!Exists(key)) return NULL; + ZeroMemory(out, outlen); + string o=Get(key); + if(outlen>0){ + outlen--; + if(o.size()::iterator i; + i=data.find(ConfigEntry(key)); + if(i==data.end()) return def; + // This should be OK, until this key gets removed + return i->val.c_str(); +} + +char *ConfigFile::GetStringDup(const char *key, const char *def){ + const char *c=GetString(key, def); + if(c==NULL) return NULL; + return strdup(c); +} + +bool ConfigFile::SetString(const char *key, string val){ + set::iterator i; + bool ret=false; + + ConfigEntry e(key, val); + + i=data.find(e); + if(i!=data.end()){ + e.line=i->line; + data.erase(e); + ret=true; + } + data.insert(e); + return ret; +} + +int32 ConfigFile::GetInt(const char *key, int32 def, bool *bad){ + if(bad) *bad=false; + if(!Exists(key)) return def; + char *c; + int32 i; + string o=Get(key); + i=strtol(o.c_str(), &c, 10); + if(c!=NULL && *c!='\0'){ + i=def; + if(bad) *bad=true; + } + return i; +} + +bool ConfigFile::SetInt(const char *key, int32 val){ + char buf[20]; + snprintf(buf, sizeof(buf), "%d", val); + return SetString(key, buf); +} + +uint32 ConfigFile::GetUInt(const char *key, uint32 def, int base, bool *bad){ + if(bad) *bad=false; + if(!Exists(key)) return def; + if(base!=8 && base!=10 && base!=16) base=0; + char *c; + uint32 i; + string o=Get(key); + i=strtol(o.c_str(), &c, base); + if(c!=NULL && *c!='\0'){ + i=def; + if(bad) *bad=true; + } + return i; +} + +bool ConfigFile::SetUInt(const char *key, uint32 val, int base){ + char buf[20]; + switch(base){ + case 10: + default: + snprintf(buf, sizeof(buf), "%u", val); + break; + case 8: + snprintf(buf, sizeof(buf), "%#o", val); + break; + case 16: + snprintf(buf, sizeof(buf), "%#x", val); + break; + } + return SetString(key, buf); +} + +bool ConfigFile::GetBool(const char *key, bool def, bool *bad){ + if(bad) *bad=false; + if(!Exists(key)) return def; + string o=Get(key); + const char *c=o.c_str(); + if(!strcasecmp(c, "true") || !strcasecmp(c, "1") || !strcasecmp(c, "yes") || !strcasecmp(c, "on")) return true; + if(!strcasecmp(c, "false") || !strcasecmp(c, "0") || !strcasecmp(c, "no") || !strcasecmp(c, "off")) return false; + if(bad) *bad=true; + return def; +} + +bool ConfigFile::SetBool(const char *key, bool val, char *true_val, char *false_val){ + return SetString(key, val?true_val:false_val); +} + +bool ConfigFile::DeleteKey(const char *key){ + return (data.erase(ConfigEntry(key))>0); +} + +/***********************************************/ + +bool ConfigFile::DeleteSection(const char *section){ + set::iterator s, e; + + for(s=data.begin(); s!=data.end() && s->section!=section; s++); + if(s==data.end()) return false; + for(e=s; e!=data.end() && e->section==section; e++); + data.erase(s, e); + return true; +} + +ConfigFile::secvec_t ConfigFile::GetSection(const char *section){ + secvec_t v; + set::iterator i; + + v.clear(); + for(i=data.begin(); i!=data.end(); i++){ + if(i->section!=section) continue; + v.push_back(std::pair(i->key, i->val)); + } + return v; +} diff --git a/source/snes9x/unused/conffile.h b/source/snes9x/unused/conffile.h new file mode 100644 index 0000000..fc21a19 --- /dev/null +++ b/source/snes9x/unused/conffile.h @@ -0,0 +1,303 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include + +#include "port.h" +#include "reader.h" + +class ConfigFile { + public: + ConfigFile(void); + + void Clear(void); + + // return false on failure + bool LoadFile(const char *filename); + void LoadFile(Reader *r, const char *name=NULL); + + // return false if key does not exist + bool Exists(const char *key); + + // return the value / default + std::string GetString(const char *key, std::string def); + char *GetString(const char *key, char *out, uint32 outlen); // return NULL if it doesn't exist, out not affected + const char *GetString(const char *key, const char *def=NULL); // NOTE: returned pointer becomes invalid when key is deleted/modified, or the ConfigFile is Clear()ed or deleted. + char *GetStringDup(const char *key, const char *def=NULL); // Much like "strdup(GetString(key, def))" + int32 GetInt(const char *key, int32 def=-1, bool *bad=NULL); + uint32 GetUInt(const char *key, uint32 def=0, int base=0, bool *bad=NULL); // base = 0, 8, 10, or 16 + bool GetBool(const char *key, bool def=false, bool *bad=NULL); + + // return true if the key existed prior to setting + bool SetString(const char *key, std::string val); + bool SetInt(const char *key, int32 val); + bool SetUInt(const char *key, uint32 val, int base=10); // base = 8, 10, or 16 + bool SetBool(const char *key, bool val, char *true_val="TRUE", char *false_val="FALSE"); + bool DeleteKey(const char *key); + + // Operation on entire sections + bool DeleteSection(const char *section); + typedef std::vector > secvec_t; + secvec_t GetSection(const char *section); + + bool SaveTo(const char *filename); + + private: + std::string Get(const char *key); + + class ConfigEntry { + protected: + int line; + std::string section; + std::string key; + std::string val; + + struct key_less { + bool operator()(const ConfigEntry &a, const ConfigEntry &b) const{ + if(a.section!=b.section) return a.section0) s.erase(0, i); + i=s.find_last_not_of(" \f\n\r\t\v"); + if(i!=-1) s.erase(i+1); + } + + public: + ConfigEntry(int l, std::string &s, std::string &k, std::string &v) : + line(l), section(s), key(k), val(v) { + trim(section); + trim(key); + } + + void parse_key(std::string &k){ + int i=k.find("::"); + if(i==-1){ + section=""; key=k; + } else { + section=k.substr(0,i); key=k.substr(i+2); + } + trim(section); + trim(key); + } + + ConfigEntry(std::string k){ + parse_key(k); + } + + ConfigEntry(std::string k, std::string &v) : line(-1), val(v) { + parse_key(k); + } + + friend class ConfigFile; + friend struct key_less; + friend struct line_less; + }; + std::set data; +}; + +/* Config file format: + * + * Comments are any lines whose first non-whitespace character is ';' or '#'. + * Note that comments must be on lines by themselves, they cannot "end" a + * normal line. + * + * All parameters fall into sections. To name a section, the first + * non-whitespace character on the line will be '[', and the last will be ']'. + * + * Parameters are simple key=value pairs. Whitespace around the '=', and at the + * beginning or end of the line is ignored. Key names may not contain '=' nor + * begin with '[', however values can. If the last character of the value is + * '\', the next line (sans leading/trailing whitespace) is considered part of + * the value as well. Programmatically, the key "K" in section "S" is referred + * to as "S::K", much like C++ namespaces. For example: + * [Section1] + * # this is a comment + * foo = bar \ + * baz\ + * quux \ + * # this is not a comment! + * means the value of "Section1::foo" is "bar bazquux # this is not a comment!" + * + * Parameters may be of several types: + * String - Bare characters. If the first and last characters are both '"', + * they are removed (so just double them if you really want quotes + * there) + * Int - A decimal number from -2147483648 to 2147483647 + * UInt - A number in decimal, hex, or octal from 0 to 4294967295 (or + * 0xffffffff, or 037777777777) + * Bool - true/false, 0/1, on/off, yes/no + * + * Of course, the actual accepted values for a parameter may be further + * restricted ;) + */ + + +/* You must write this for your port */ +void S9xParsePortConfig(ConfigFile &, int pass); + +/* This may or may not be useful to you */ +char *S9xParseDisplayConfig(ConfigFile &, int pass); + +#endif diff --git a/source/snes9x/unused/loadzip.cpp b/source/snes9x/unused/loadzip.cpp new file mode 100644 index 0000000..1d0a7f1 --- /dev/null +++ b/source/snes9x/unused/loadzip.cpp @@ -0,0 +1,331 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifdef UNZIP_SUPPORT +/**********************************************************************************************/ +/* Loadzip.CPP */ +/* This file contains a function for loading a SNES ROM image from a zip file */ +/**********************************************************************************************/ + +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include + +#ifndef NO_INLINE_SET_GET +#define NO_INLINE_SET_GET +#endif + +#include "snes9x.h" +#include "memmap.h" + +#include "unzip.h" +#include +#include +#include + +bool8 LoadZip(const char* zipname, + int32 *TotalFileSize, + int32 *headers, uint8* buffer) +{ + *TotalFileSize = 0; + *headers = 0; + + unzFile file = unzOpen(zipname); + if(file == NULL) + return (FALSE); + + // find largest file in zip file (under MAX_ROM_SIZE) + // or a file with extension .1 + char filename[132]; + int filesize = 0; + int port = unzGoToFirstFile(file); + unz_file_info info; + while(port == UNZ_OK) + { + char name[132]; + unzGetCurrentFileInfo(file, &info, name,128, NULL,0, NULL,0); + +#if 0 + int calc_size = info.uncompressed_size / 0x2000; + calc_size *= 0x2000; + if(!(info.uncompressed_size - calc_size == 512 || info.uncompressed_size == calc_size)) + { + port = unzGoToNextFile(file); + continue; + } +#endif + + if(info.uncompressed_size > (CMemory::MAX_ROM_SIZE + 512)) + { + port = unzGoToNextFile(file); + continue; + } + + if ((int) info.uncompressed_size > filesize) + { + strcpy(filename,name); + filesize = info.uncompressed_size; + } + int len = strlen(name); + if(name[len-2] == '.' && name[len-1] == '1') + { + strcpy(filename,name); + filesize = info.uncompressed_size; + break; + } + port = unzGoToNextFile(file); + } + if( !(port == UNZ_END_OF_LIST_OF_FILE || port == UNZ_OK) || filesize == 0) + { + assert( unzClose(file) == UNZ_OK ); + return (FALSE); + } + + // Find extension + char tmp[2]; + tmp[0] = tmp[1] = 0; + char *ext = strrchr(filename,'.'); + if(ext) ext++; + else ext = tmp; + + uint8 *ptr = buffer; + bool8 more = FALSE; + + printf("Using ROM %s in %s\n", filename, zipname); + unzLocateFile(file,filename,1); + unzGetCurrentFileInfo(file, &info, filename,128, NULL,0, NULL,0); + + if( unzOpenCurrentFile(file) != UNZ_OK ) + { + unzClose(file); + return (FALSE); + } + + do + { + assert(info.uncompressed_size <= CMemory::MAX_ROM_SIZE + 512); + int FileSize = info.uncompressed_size; + + int calc_size = FileSize / 0x2000; + calc_size *= 0x2000; + + int l = unzReadCurrentFile(file,ptr,FileSize); + if(unzCloseCurrentFile(file) == UNZ_CRCERROR) + { + unzClose(file); + return (FALSE); + } + + if(l <= 0 || l != FileSize) + { + unzClose(file); + switch(l) + { + case UNZ_ERRNO: + break; + case UNZ_EOF: + break; + case UNZ_PARAMERROR: + break; + case UNZ_BADZIPFILE: + break; + case UNZ_INTERNALERROR: + break; + case UNZ_CRCERROR: + break; + } + return (FALSE); + } + + if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) || + Settings.ForceHeader) + { + memmove (ptr, ptr + 512, calc_size); + (*headers)++; + FileSize -= 512; + } + ptr += FileSize; + (*TotalFileSize) += FileSize; + + int len; + if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 0x200 && + (isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9')) + { + more = TRUE; + ext [0]++; + } + else if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 0x200) + { + if (ext == tmp) len = strlen (filename); + else len = ext - filename - 1; + if ((len == 7 || len == 8) && + strncasecmp (filename, "sf", 2) == 0 && + isdigit (filename [2]) && isdigit (filename [3]) && isdigit (filename [4]) && + isdigit (filename [5]) && isalpha (filename [len - 1])) + { + more = TRUE; + filename [len - 1]++; + } + } + else + more = FALSE; + + if(more) + { + if( unzLocateFile(file,filename,1) != UNZ_OK || + unzGetCurrentFileInfo(file, &info, filename,128, NULL,0, NULL,0) != UNZ_OK || + unzOpenCurrentFile(file) != UNZ_OK) + break; + printf(" ... and %s in %s\n", filename, zipname); + } + + } while(more); + + unzClose(file); + return (TRUE); +} +#endif + diff --git a/source/snes9x/unused/movie.cpp b/source/snes9x/unused/movie.cpp new file mode 100644 index 0000000..74d0ddc --- /dev/null +++ b/source/snes9x/unused/movie.cpp @@ -0,0 +1,835 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +// Input recording/playback code +// (c) Copyright 2004 blip + +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include + +#if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP) || defined(__MACOSX__) +#include +#include +#include +#endif +#include + +#ifdef __WIN32__ +#include +#ifndef W_OK +#define W_OK 2 +#endif +#endif + +#include "movie.h" +#include "snes9x.h" +#include "memmap.h" +#include "cpuexec.h" +#include "snapshot.h" + +#define SMV_MAGIC 0x1a564d53 // SMV0x1a +#define SMV_VERSION 2 +#define SMV_HEADER_SIZE 32 +#define CONTROLLER_DATA_SIZE 2 +#define BUFFER_GROWTH_SIZE 4096 + +enum MovieState +{ + MOVIE_STATE_NONE=0, + MOVIE_STATE_PLAY, + MOVIE_STATE_RECORD +}; + +static struct SMovie +{ + enum MovieState State; + char Filename [_MAX_PATH]; + FILE* File; + uint32 SaveStateOffset; + uint32 ControllerDataOffset; + uint32 MovieId; + uint32 CurrentFrame; + uint32 MaxFrame; + uint32 RerecordCount; + uint8 ControllersMask; + uint8 Opts; + bool8 ReadOnly; + uint32 BytesPerFrame; + uint8* InputBuffer; + uint32 InputBufferSize; + uint8* InputBufferPtr; + bool8 FrameDisplay; + char FrameDisplayString[256]; +} Movie; + +/* + For illustration: +struct MovieFileHeader +{ + uint32 magic; // SMV0x1a + uint32 version; + uint32 uid; // used to match savestates to a particular movie + uint32 rerecord_count; + uint32 length_frames; + uint8 flags[4]; + uint32 offset_to_savestate; // smvs have an embedded savestate + uint32 offset_to_controller_data; + // after the header comes extra metadata + // sizeof(metadata) = offset_to_savestate - sizeof(MovieFileHeader) +}; +*/ + +static int bytes_per_frame() +{ + int i; + int num_controllers; + + num_controllers=0; + for(i=0; i<8; ++i) + { + if(Movie.ControllersMask & (1<>8)&0xff); + ptr[2]=(uint8)((v>>16)&0xff); + ptr[3]=(uint8)((v>>24)&0xff); + ptr += 4; +} + +static void Write16(uint16 v, uint8*& ptr) +{ + ptr[0]=(uint8)(v&0xff); + ptr[1]=(uint8)((v>>8)&0xff); + ptr += 2; +} + +static int read_movie_header(FILE* fd, SMovie* movie) +{ + uint8 header[SMV_HEADER_SIZE]; + if(fread(header, 1, SMV_HEADER_SIZE, fd) != SMV_HEADER_SIZE) + return WRONG_FORMAT; + + const uint8* ptr=header; + uint32 magic=Read32(ptr); + if(magic!=SMV_MAGIC) + return WRONG_FORMAT; + + uint32 version=Read32(ptr); + if(version!=SMV_VERSION) + return WRONG_VERSION; + + movie->MovieId=Read32(ptr); + movie->RerecordCount=Read32(ptr); + movie->MaxFrame=Read32(ptr); + + movie->ControllersMask=*ptr++; + movie->Opts=*ptr++; + ptr += 2; + + movie->SaveStateOffset=Read32(ptr); + movie->ControllerDataOffset=Read32(ptr); + + return SUCCESS; +} + +static void write_movie_header(FILE* fd, const SMovie* movie) +{ + uint8 header[SMV_HEADER_SIZE]; + uint8* ptr=header; + + Write32(SMV_MAGIC, ptr); + Write32(SMV_VERSION, ptr); + Write32(movie->MovieId, ptr); + Write32(movie->RerecordCount, ptr); + Write32(movie->MaxFrame, ptr); + + *ptr++=movie->ControllersMask; + *ptr++=movie->Opts; + *ptr++=0; + *ptr++=0; + + Write32(movie->SaveStateOffset, ptr); + Write32(movie->ControllerDataOffset, ptr); + + fwrite(header, 1, SMV_HEADER_SIZE, fd); +} + +static void flush_movie() +{ + fseek(Movie.File, 0, SEEK_SET); + write_movie_header(Movie.File, &Movie); + fseek(Movie.File, Movie.ControllerDataOffset, SEEK_SET); + fwrite(Movie.InputBuffer, 1, Movie.BytesPerFrame*(Movie.MaxFrame+1), Movie.File); +} + +static void change_state(MovieState new_state) +{ + if(new_state==Movie.State) + return; + + if(Movie.State==MOVIE_STATE_RECORD) + { + flush_movie(); + } + + Movie.State=new_state; + + if(new_state==MOVIE_STATE_NONE) + { + fclose(Movie.File); + Movie.File=NULL; + // FIXME: truncate movie to MaxFrame length + /* truncate() could be used, if it's certain + * that the savestate block is never after + * the controller data block. It is not guaranteed + * by the format. + */ + } +} + +static void reserve_buffer_space(uint32 space_needed) +{ + if(space_needed > Movie.InputBufferSize) + { + uint32 ptr_offset = Movie.InputBufferPtr - Movie.InputBuffer; + uint32 alloc_chunks = space_needed / BUFFER_GROWTH_SIZE; + Movie.InputBufferSize = BUFFER_GROWTH_SIZE * (alloc_chunks+1); + Movie.InputBuffer = (uint8*)realloc(Movie.InputBuffer, Movie.InputBufferSize); + Movie.InputBufferPtr = Movie.InputBuffer + ptr_offset; + } +} + + +/* accessors into controls.cpp static variables */ +uint16 MovieGetJoypad(int i); +void MovieSetJoypad(int i, uint16 buttons); + +static void read_frame_controller_data() +{ + int i; + for(i=0; i<8; ++i) + { + if(Movie.ControllersMask & (1<MOVIE_MAX_METADATA) + { + metadata_length=MOVIE_MAX_METADATA; + } + + Movie.MovieId=(uint32)time(NULL); + Movie.RerecordCount=0; + Movie.MaxFrame=0; + Movie.SaveStateOffset=SMV_HEADER_SIZE+(sizeof(uint16)*metadata_length); + Movie.ControllerDataOffset=0; + Movie.ControllersMask=controllers_mask; + Movie.Opts=opts; + if(Settings.PAL) + { + Movie.Opts |= MOVIE_OPT_PAL; + } + else + { + Movie.Opts &= ~MOVIE_OPT_PAL; + } + + write_movie_header(fd, &Movie); + + // convert wchar_t metadata string/array to a uint16 array + if(metadata_length>0) + { + uint8 meta_buf[MOVIE_MAX_METADATA * sizeof(uint16)]; + int i; + + for(i=0; i>8)&0xff); + } + + fwrite(meta_buf, sizeof(uint16), metadata_length, fd); + } + + // write snapshot + fn=dup(fileno(fd)); + fclose(fd); + + // lseek(fn, Movie.SaveStateOffset, SEEK_SET); + if(!(stream=REOPEN_STREAM(fn, "ab"))) + return FILE_NOT_FOUND; + + if(opts & MOVIE_OPT_FROM_RESET) + { + S9xReset(); + // save only SRAM for a from-reset snapshot + WRITE_STREAM(SRAM, 0x20000, stream); + } + else + { + S9xFreezeToStream(stream); + } + CLOSE_STREAM(stream); + + if(!(fd=fopen(filename, "rb+"))) + return FILE_NOT_FOUND; + + fseek(fd, 0, SEEK_END); + Movie.ControllerDataOffset=(uint32)ftell(fd); + + // write "baseline" controller data + Movie.File=fd; + Movie.BytesPerFrame=bytes_per_frame(); + Movie.InputBufferPtr=Movie.InputBuffer; + write_frame_controller_data(); + + strncpy(Movie.Filename, filename, _MAX_PATH); + Movie.Filename[_MAX_PATH-1]='\0'; + Movie.CurrentFrame=0; + Movie.ReadOnly=false; + change_state(MOVIE_STATE_RECORD); + + S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_RECORD); + return SUCCESS; +} + +void S9xMovieUpdate () +{ + switch(Movie.State) + { + case MOVIE_STATE_PLAY: + if(Movie.CurrentFrame>=Movie.MaxFrame) + { + change_state(MOVIE_STATE_NONE); + S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_END); + return; + } + else + { + if(Movie.FrameDisplay) + { + sprintf(Movie.FrameDisplayString, "Playing frame: %d", Movie.CurrentFrame); + S9xMessage (S9X_INFO, S9X_MOVIE_INFO, Movie.FrameDisplayString); + } + read_frame_controller_data(); + ++Movie.CurrentFrame; + } + break; + + case MOVIE_STATE_RECORD: + { + if(Movie.FrameDisplay) + { + sprintf(Movie.FrameDisplayString, "Recording frame: %d", Movie.CurrentFrame); + S9xMessage (S9X_INFO, S9X_MOVIE_INFO, Movie.FrameDisplayString); + } + write_frame_controller_data(); + ++Movie.CurrentFrame; + Movie.MaxFrame=Movie.CurrentFrame; + fwrite((Movie.InputBufferPtr - Movie.BytesPerFrame), 1, Movie.BytesPerFrame, Movie.File); + } + break; + + default: + break; + } +} + +void S9xMovieStop (bool8 suppress_message) +{ + if(Movie.State!=MOVIE_STATE_NONE) + { + change_state(MOVIE_STATE_NONE); + + if(!suppress_message) + S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_STOP); + } +} + +int S9xMovieGetInfo (const char* filename, struct MovieInfo* info) +{ + FILE* fd; + int result; + SMovie local_movie; + int metadata_length; + + memset(info, 0, sizeof(*info)); + if(!(fd=fopen(filename, "rb"))) + return FILE_NOT_FOUND; + + if((result=(read_movie_header(fd, &local_movie)))!=SUCCESS) + return result; + + info->TimeCreated=(time_t)local_movie.MovieId; + info->LengthFrames=local_movie.MaxFrame; + info->RerecordCount=local_movie.RerecordCount; + info->Opts=local_movie.Opts; + info->ControllersMask=local_movie.ControllersMask; + + if(local_movie.SaveStateOffset > SMV_HEADER_SIZE) + { + uint8 meta_buf[MOVIE_MAX_METADATA * sizeof(uint16)]; + int i; + + metadata_length=((int)local_movie.SaveStateOffset-SMV_HEADER_SIZE)/sizeof(uint16); + metadata_length=(metadata_length>=MOVIE_MAX_METADATA) ? MOVIE_MAX_METADATA-1 : metadata_length; + metadata_length=(int)fread(meta_buf, sizeof(uint16), metadata_length, fd); + + for(i=0; iMetadata[i]=(wchar_t)c; + } + info->Metadata[i]='\0'; + } + else + { + info->Metadata[0]='\0'; + } + + fclose(fd); + + if(access(filename, W_OK)) + info->ReadOnly=true; + + return SUCCESS; +} + +bool8 S9xMovieActive () +{ + return (Movie.State!=MOVIE_STATE_NONE); +} + +bool8 S9xMovieReadOnly () +{ + if(!S9xMovieActive()) + return false; + + return Movie.ReadOnly; +} + +uint32 S9xMovieGetId () +{ + if(!S9xMovieActive()) + return 0; + + return Movie.MovieId; +} + +uint32 S9xMovieGetLength () +{ + if(!S9xMovieActive()) + return 0; + + return Movie.MaxFrame; +} + +uint32 S9xMovieGetFrameCounter () +{ + if(!S9xMovieActive()) + return 0; + + return Movie.CurrentFrame; +} + +void S9xMovieToggleFrameDisplay () +{ + Movie.FrameDisplay = !Movie.FrameDisplay; + if(!Movie.FrameDisplay) + { + GFX.InfoStringTimeout = 1; + } +} + +void S9xMovieFreeze (uint8** buf, uint32* size) +{ + // sanity check + if(!S9xMovieActive()) + { + return; + } + + *buf = NULL; + *size = 0; + + // compute size needed for the buffer + uint32 size_needed = 4*3; // room for MovieId, CurrentFrame, and MaxFrame + size_needed += (uint32)(Movie.BytesPerFrame * (Movie.MaxFrame+1)); + *buf=new uint8[size_needed]; + *size=size_needed; + + uint8* ptr = *buf; + if(!ptr) + { + return; + } + + Write32(Movie.MovieId, ptr); + Write32(Movie.CurrentFrame, ptr); + Write32(Movie.MaxFrame, ptr); + + memcpy(ptr, Movie.InputBuffer, Movie.BytesPerFrame * (Movie.MaxFrame+1)); +} + +bool8 S9xMovieUnfreeze (const uint8* buf, uint32 size) +{ + // sanity check + if(!S9xMovieActive()) + { + return false; + } + + const uint8* ptr = buf; + if(size < 4*3) + { + return false; + } + + uint32 movie_id = Read32(ptr); + uint32 current_frame = Read32(ptr); + uint32 max_frame = Read32(ptr); + uint32 space_needed = (Movie.BytesPerFrame * (max_frame+1)); + + if(movie_id != Movie.MovieId || + current_frame > max_frame || + space_needed > size) + { + return false; + } + + if(!Movie.ReadOnly) + { + // here, we are going to take the input data from the savestate + // and make it the input data for the current movie, then continue + // writing new input data at the currentframe pointer + change_state(MOVIE_STATE_RECORD); + S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_RERECORD); + + Movie.CurrentFrame = current_frame; + Movie.MaxFrame = max_frame; + ++Movie.RerecordCount; + + reserve_buffer_space(space_needed); + memcpy(Movie.InputBuffer, ptr, space_needed); + flush_movie(); + fseek(Movie.File, Movie.ControllerDataOffset+(Movie.BytesPerFrame * (Movie.CurrentFrame+1)), SEEK_SET); + } + else + { + // here, we are going to keep the input data from the movie file + // and simply rewind to the currentframe pointer + // this will cause a desync if the savestate is not in sync + // with the on-disk recording data, but it's easily solved + // by loading another savestate or playing the movie from the beginning + + // and older savestate might have a currentframe pointer past + // the end of the input data, so check for that here + if(current_frame > Movie.MaxFrame) + { + return false; + } + + change_state(MOVIE_STATE_PLAY); + S9xMessage(S9X_INFO, S9X_MOVIE_INFO, MOVIE_INFO_REWIND); + + Movie.CurrentFrame = current_frame; + } + + Movie.InputBufferPtr = Movie.InputBuffer + (Movie.BytesPerFrame * Movie.CurrentFrame); + read_frame_controller_data(); + + return true; +} diff --git a/source/snes9x/unused/netplay.cpp b/source/snes9x/unused/netplay.cpp new file mode 100644 index 0000000..a015f5b --- /dev/null +++ b/source/snes9x/unused/netplay.cpp @@ -0,0 +1,1103 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifdef NETPLAY_SUPPORT + +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +#include +#include +#include +#include +#endif + +#if defined (__WIN32__) +#include +#include + +#define ioctl ioctlsocket +#define close closesocket +#define read(a,b,c) recv(a, b, c, 0) +#define write(a,b,c) send(a, b, c, 0) +#else + +#include +#include +#include +#include +#include +#include + +#ifdef __SVR4 +#include +#endif +#endif + +#ifdef USE_THREADS +#include +#include +#include +#endif + +#include "snes9x.h" +#include "cpuexec.h" +#include "netplay.h" +#include "memmap.h" +#include "snapshot.h" +#include "display.h" + +void S9xNPClientLoop (void *); +bool8 S9xNPLoadROM (uint32 len); +bool8 S9xNPLoadROMDialog (const char *); +bool8 S9xNPGetROMImage (uint32 len); +void S9xNPGetSRAMData (uint32 len); +void S9xNPGetFreezeFile (uint32 len); + +unsigned long START = 0; + +bool8 S9xNPConnectToServer (const char *hostname, int port, + const char *rom_name) +{ + if (!S9xNPInitialise ()) + return (FALSE); + + S9xNPDisconnect (); + + NetPlay.MySequenceNum = 0; + NetPlay.ServerSequenceNum = 0; + NetPlay.Connected = FALSE; + NetPlay.Abort = FALSE; + NetPlay.Player = 0; + NetPlay.Paused = FALSE; + NetPlay.PercentageComplete = 0; + NetPlay.Socket = 0; + if (NetPlay.ServerHostName) + free ((char *) NetPlay.ServerHostName); + NetPlay.ServerHostName = strdup (hostname); + if (NetPlay.ROMName) + free ((char *) NetPlay.ROMName); + NetPlay.ROMName = strdup (rom_name); + NetPlay.Port = port; + NetPlay.PendingWait4Sync = FALSE; + +#ifdef __WIN32__ + if (GUI.ClientSemaphore == NULL) + GUI.ClientSemaphore = CreateSemaphore (NULL, 0, NP_JOYPAD_HIST_SIZE, NULL); + + if (NetPlay.ReplyEvent == NULL) + NetPlay.ReplyEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + + _beginthread (S9xNPClientLoop, 0, NULL); +#endif + + return (TRUE); +} + +bool8 S9xNPConnect () +{ + struct sockaddr_in address; + struct hostent *hostinfo; + unsigned int addr; + + address.sin_family = AF_INET; + address.sin_port = htons (NetPlay.Port); +#ifdef NP_DEBUG + printf ("CLIENT: Looking up server's hostname (%s) @%ld\n", NetPlay.ServerHostName, S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Looking up server's hostname..."); + if ((int) (addr = inet_addr (NetPlay.ServerHostName)) == -1) + { + if ((hostinfo = gethostbyname (NetPlay.ServerHostName))) + { + memcpy ((char *)&address.sin_addr, hostinfo->h_addr, + hostinfo->h_length); + } + else + { + S9xNPSetError ("\ +Unable to look up server's IP address from hostname.\n\n\ +Unknown hostname or may be your nameserver isn't set\n\ +up correctly?"); + return (FALSE); + } + } + else + { + memcpy ((char *)&address.sin_addr, &addr, sizeof (addr)); + } + +#ifdef NP_DEBUG + printf ("CLIENT: Creating socket @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Creating network socket..."); + if ((NetPlay.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) + { + S9xNPSetError ("Creating network socket failed."); + return (FALSE); + } + +#ifdef NP_DEBUG + printf ("CLIENT: Trying to connect to server @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Trying to connect to Snes9X server..."); + + if (connect (NetPlay.Socket, (struct sockaddr *) &address, sizeof (address)) < 0) + { + char buf [100]; +#ifdef __WIN32__ + if (WSAGetLastError () == WSAECONNREFUSED) +#else + if (errno == ECONNREFUSED) +#endif + { + S9xNPSetError ("\ +Connection to remote server socket refused:\n\n\ +Is there actually a Snes9X NetPlay server running\n\ +on the remote machine on this port?"); + } + else + { + sprintf (buf, "Connection to server failed with error number %d", +#ifdef __WIN32__ + WSAGetLastError () +#else + errno +#endif + ); + S9xNPDisconnect (); + } + return (FALSE); + } + NetPlay.Connected = TRUE; + +#ifdef NP_DEBUG + printf ("CLIENT: Sending 'HELLO' message @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Sending 'HELLO' message..."); + /* Send the server a HELLO packet*/ + int len = 7 + 4 + strlen (NetPlay.ROMName) + 1; + uint8 *tmp = new uint8 [len]; + uint8 *ptr = tmp; + + *ptr++ = NP_CLNT_MAGIC; + *ptr++ = NetPlay.MySequenceNum++; + *ptr++ = NP_CLNT_HELLO; + WRITE_LONG (ptr, len); + ptr += 4; +#ifdef __WIN32__ + uint32 ft = Settings.FrameTime * 1000; + + WRITE_LONG (ptr, ft); +#else + WRITE_LONG (ptr, Settings.FrameTime); +#endif + ptr += 4; + strcpy ((char *) ptr, NetPlay.ROMName); + + if (!S9xNPSendData (NetPlay.Socket, tmp, len)) + { + S9xNPSetError ("Sending 'HELLO' message failed."); + S9xNPDisconnect (); + delete tmp; + return (FALSE); + } + delete tmp; + +#ifdef NP_DEBUG + printf ("CLIENT: Waiting for 'WELCOME' reply from server @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Waiting for 'HELLO' reply from server..."); + + uint8 header [7]; + + if (!S9xNPGetData (NetPlay.Socket, header, 7) || + header [0] != NP_SERV_MAGIC || header [1] != 0 || + (header [2] & 0x1f) != NP_SERV_HELLO) + { + S9xNPSetError ("Error in 'HELLO' reply packet received from server."); + S9xNPDisconnect (); + return (FALSE); + } +#ifdef NP_DEBUG + printf ("CLIENT: Got 'WELCOME' reply @%ld\n", S9xGetMilliTime () - START); +#endif + len = READ_LONG (&header [3]); + if (len > 256) + { + S9xNPSetError ("Error in 'HELLO' reply packet received from server."); + S9xNPDisconnect (); + return (FALSE); + } + uint8 *data = new uint8 [len]; + if (!S9xNPGetData (NetPlay.Socket, data, len - 7)) + { + S9xNPSetError ("Error in 'HELLO' reply packet received from server."); + delete data; + S9xNPDisconnect (); + return (FALSE); + } + + if (data [0] != NP_VERSION) + { + S9xNPSetError ("\ +The Snes9X NetPlay server implements a different\n\ +version of the protocol. Disconnecting."); + delete data; + S9xNPDisconnect (); + return (FALSE); + } + + NetPlay.FrameCount = READ_LONG (&data [2]); + + if (!(header [2] & 0x80) && + strcmp ((char *) data + 4 + 2, NetPlay.ROMName) != 0) + { + if (!S9xNPLoadROMDialog ((char *) data + 4 + 2)) + { + delete data; + S9xNPDisconnect (); + return (FALSE); + } + } + NetPlay.Player = data [1]; + delete data; + + NetPlay.PendingWait4Sync = TRUE; + Settings.NetPlay = TRUE; + S9xNPResetJoypadReadPos (); + NetPlay.ServerSequenceNum = 1; + +#ifdef NP_DEBUG + printf ("CLIENT: Sending 'READY' to server @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Sending 'READY' to the server..."); + + return (S9xNPSendReady ((header [2] & 0x80) ? + NP_CLNT_WAITING_FOR_ROM_IMAGE : + NP_CLNT_READY)); +} + +bool8 S9xNPSendReady (uint8 op) +{ + uint8 ready [7]; + uint8 *ptr = ready; + *ptr++ = NP_CLNT_MAGIC; + *ptr++ = NetPlay.MySequenceNum++; + *ptr++ = op; + WRITE_LONG (ptr, 7); + ptr += 4; + + if (!S9xNPSendData (NetPlay.Socket, ready, 7)) + { + S9xNPDisconnect (); + S9xNPSetError ("Sending 'READY' message failed."); + return (FALSE); + } + + return (TRUE); +} + +bool8 S9xNPSendPause (bool8 paused) +{ +#ifdef NP_DEBUG + printf ("CLIENT: Pause - %s @%ld\n", paused ? "YES" : "NO", S9xGetMilliTime () - START); +#endif + uint8 pause [7]; + uint8 *ptr = pause; + *ptr++ = NP_CLNT_MAGIC; + *ptr++ = NetPlay.MySequenceNum++; + *ptr++ = NP_CLNT_PAUSE | (paused ? 0x80 : 0); + WRITE_LONG (ptr, 7); + ptr += 4; + + if (!S9xNPSendData (NetPlay.Socket, pause, 7)) + { + S9xNPSetError ("Sending 'PAUSE' message failed."); + S9xNPDisconnect (); + return (FALSE); + } + + return (TRUE); +} + +#ifdef __WIN32__ +void S9xNPClientLoop (void *) +{ + NetPlay.Waiting4EmulationThread = FALSE; + + if (S9xNPConnect ()) + { + S9xClearPause (PAUSE_NETPLAY_CONNECT); + while (NetPlay.Connected) + { + if (S9xNPWaitForHeartBeat ()) + { + LONG prev; + if (!ReleaseSemaphore (GUI.ClientSemaphore, 1, &prev)) + { +#ifdef NP_DEBUG + printf ("CLIENT: ReleaseSemaphore failed - already hit max count (%d) %ld\n", NP_JOYPAD_HIST_SIZE, S9xGetMilliTime () - START); +#endif + S9xNPSetWarning ("NetPlay: Client may be out of sync with server."); + } + else + { + if (!NetPlay.Waiting4EmulationThread && + prev == (int) NetPlay.MaxBehindFrameCount) + { + NetPlay.Waiting4EmulationThread = TRUE; + S9xNPSendPause (TRUE); + } + } + } + else + S9xNPDisconnect (); + } + } + else + { + S9xClearPause (PAUSE_NETPLAY_CONNECT); + } +#ifdef NP_DEBUG + printf ("CLIENT: Client thread exiting @%ld\n", S9xGetMilliTime () - START); +#endif +} +#endif + +bool8 S9xNPWaitForHeartBeat () +{ + uint8 header [3 + 4 + 4 * 5]; + + while (S9xNPGetData (NetPlay.Socket, header, 3 + 4)) + { + if (header [0] != NP_SERV_MAGIC) + { + S9xNPSetError ("Bad magic value from server while waiting for heart-beat message\n"); + S9xNPDisconnect (); + return (FALSE); + } + if (header [1] != NetPlay.ServerSequenceNum) + { + char buf [200]; + sprintf (buf, "Unexpected message sequence number from server, expected %d, got %d\n", NetPlay.ServerSequenceNum, header [1]); + S9xNPSetWarning (buf); + NetPlay.ServerSequenceNum = header [1] + 1; + } + else + NetPlay.ServerSequenceNum++; + + if ((header [2] & 0x1f) == NP_SERV_JOYPAD) + { + // Top 2 bits + 1 of opcode is joypad data count. + int num = (header [2] >> 6) + 1; + + if (num) + { + if (!S9xNPGetData (NetPlay.Socket, header + 3 + 4, num * 4)) + { + S9xNPSetError ("Error while receiving 'JOYPAD' message."); + S9xNPDisconnect (); + return (FALSE); + } + } + NetPlay.Frame [NetPlay.JoypadWriteInd] = READ_LONG (&header [3]); + + for (int i = 0; i < num; i++) + { + NetPlay.Joypads [NetPlay.JoypadWriteInd][i] = + READ_LONG (&header [3 + 4 + i * sizeof (uint32)]); + } + NetPlay.Paused = (header [2] & 0x20) != 0; + + NetPlay.JoypadWriteInd = (NetPlay.JoypadWriteInd + 1) % NP_JOYPAD_HIST_SIZE; + + if (NetPlay.JoypadWriteInd != (NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE) + { + //printf ("(%d)", (NetPlay.JoypadWriteInd - NetPlay.JoypadReadInd) % NP_JOYPAD_HIST_SIZE); fflush (stdout); + } +//printf ("CLIENT: HB: @%d\n", S9xGetMilliTime () - START); + return (TRUE); + } + else + { + uint32 len = READ_LONG (&header [3]); + switch (header [2] & 0x1f) + { + case NP_SERV_RESET: +#ifdef NP_DEBUG + printf ("CLIENT: RESET received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDiscardHeartbeats (); + S9xReset (); + NetPlay.FrameCount = READ_LONG (&header [3]); + S9xNPResetJoypadReadPos (); + S9xNPSendReady (); + break; + case NP_SERV_PAUSE: + NetPlay.Paused = (header [2] & 0x20) != 0; + break; + case NP_SERV_LOAD_ROM: +#ifdef NP_DEBUG + printf ("CLIENT: LOAD_ROM received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDiscardHeartbeats (); + if (S9xNPLoadROM (len - 7)) + S9xNPSendReady (NP_CLNT_LOADED_ROM); + break; + case NP_SERV_ROM_IMAGE: +#ifdef NP_DEBUG + printf ("CLIENT: ROM_IMAGE received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDiscardHeartbeats (); + if (S9xNPGetROMImage (len - 7)) + S9xNPSendReady (NP_CLNT_RECEIVED_ROM_IMAGE); + break; + case NP_SERV_SRAM_DATA: +#ifdef NP_DEBUG + printf ("CLIENT: SRAM_DATA received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDiscardHeartbeats (); + S9xNPGetSRAMData (len - 7); + break; + case NP_SERV_FREEZE_FILE: +#ifdef NP_DEBUG + printf ("CLIENT: FREEZE_FILE received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDiscardHeartbeats (); + S9xNPGetFreezeFile (len - 7); + S9xNPResetJoypadReadPos (); + S9xNPSendReady (); + break; + default: +#ifdef NP_DEBUG + printf ("CLIENT: UNKNOWN received @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPDisconnect (); + return (FALSE); + } + } + } + + S9xNPDisconnect (); + return (FALSE); +} + +bool8 S9xNPLoadROMDialog (const char *rom_name) +{ + NetPlay.Answer = FALSE; + +#ifdef __WIN32__ + ResetEvent (NetPlay.ReplyEvent); + +#ifdef NP_DEBUG + printf ("CLIENT: Asking GUI thread to open ROM load dialog...\n"); +#endif + + PostMessage (GUI.hWnd, WM_USER + 3, (uint32) rom_name, (uint32) rom_name); + +#ifdef NP_DEBUG + printf ("CLIENT: Waiting for reply from GUI thread...\n"); +#endif + + WaitForSingleObject (NetPlay.ReplyEvent, INFINITE); + +#ifdef NP_DEBUG + printf ("CLIENT: Got reply from GUI thread (%d)\n", NetPlay.Answer); +#endif +#endif + + return (NetPlay.Answer); +} + +bool8 S9xNPLoadROM (uint32 len) +{ + uint8 *data = new uint8 [len]; + + S9xNPSetAction ("Receiving ROM name..."); + if (!S9xNPGetData (NetPlay.Socket, data, len)) + { + S9xNPSetError ("Error while receiving ROM name."); + delete data; + S9xNPDisconnect (); + return (FALSE); + } + + S9xNPSetAction ("Opening LoadROM dialog..."); + if (!S9xNPLoadROMDialog ((char *) data)) + { + S9xNPSetError ("Disconnected from NetPlay server because you are playing a different game!"); + delete data; + S9xNPDisconnect (); + return (FALSE); + } + delete data; + return (TRUE); +} + +bool8 S9xNPGetROMImage (uint32 len) +{ + uint8 rom_info [5]; + + S9xNPSetAction ("Receiving ROM information..."); + if (!S9xNPGetData (NetPlay.Socket, rom_info, 5)) + { + S9xNPSetError ("Error while receiving ROM information."); + S9xNPDisconnect (); + return (FALSE); + } + uint32 CalculatedSize = READ_LONG (&rom_info [1]); +#ifdef NP_DEBUG + printf ("CLIENT: Hi-ROM: %s, Size: %04x\n", rom_info [0] ? "Y" : "N", CalculatedSize); +#endif + if (CalculatedSize + 5 >= len || + CalculatedSize >= CMemory::MAX_ROM_SIZE) + { + S9xNPSetError ("Size error in ROM image data received from server."); + S9xNPDisconnect (); + return (FALSE); + } + + Memory.HiROM = rom_info [0]; + Memory.LoROM = !Memory.HiROM; + Memory.HeaderCount = 0; + Memory.CalculatedSize = CalculatedSize; + + // Load up ROM image +#ifdef NP_DEBUG + printf ("CLIENT: Receiving ROM image @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Receiving ROM image..."); + if (!S9xNPGetData (NetPlay.Socket, Memory.ROM, Memory.CalculatedSize)) + { + S9xNPSetError ("Error while receiving ROM image from server."); + Settings.StopEmulation = TRUE; + S9xNPDisconnect (); + return (FALSE); + } +#ifdef NP_DEBUG + printf ("CLIENT: Receiving ROM filename @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Receiving ROM filename..."); + uint32 filename_len = len - Memory.CalculatedSize - 5; + if (filename_len > _MAX_PATH || + !S9xNPGetData (NetPlay.Socket, (uint8 *) Memory.ROMFilename, filename_len)) + { + S9xNPSetError ("Error while receiving ROM filename from server."); + S9xNPDisconnect (); + Settings.StopEmulation = TRUE; + return (FALSE); + } + Memory.InitROM (FALSE); + S9xReset (); + S9xNPResetJoypadReadPos (); + Settings.StopEmulation = FALSE; + +#ifdef __WIN32__ + PostMessage (GUI.hWnd, WM_NULL, 0, 0); +#endif + + return (TRUE); +} + +void S9xNPGetSRAMData (uint32 len) +{ + if (len > 0x10000) + { + S9xNPSetError ("Length error in S-RAM data received from server."); + S9xNPDisconnect (); + return; + } + S9xNPSetAction ("Receiving S-RAM data..."); + if (len > 0 && !S9xNPGetData (NetPlay.Socket, ::SRAM, len)) + { + S9xNPSetError ("Error while receiving S-RAM data from server."); + S9xNPDisconnect (); + } +} + +void S9xNPGetFreezeFile (uint32 len) +{ + uint8 frame_count [4]; + +#ifdef NP_DEBUG + printf ("CLIENT: Receiving freeze file information @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Receiving freeze file information..."); + if (!S9xNPGetData (NetPlay.Socket, frame_count, 4)) + { + S9xNPSetError ("Error while receiving freeze file information from server."); + S9xNPDisconnect (); + return; + } + NetPlay.FrameCount = READ_LONG (frame_count); + +#ifdef NP_DEBUG + printf ("CLIENT: Receiving freeze file @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Receiving freeze file..."); + uint8 *data = new uint8 [len]; + if (!S9xNPGetData (NetPlay.Socket, data, len - 4)) + { + S9xNPSetError ("Error while receiving freeze file from server."); + S9xNPDisconnect (); + delete data; + return; + } + + //FIXME: Setting umask here wouldn't hurt. + FILE *file; +#ifdef HAVE_MKSTEMP + int fd; + char fname[] = "/tmp/snes9x_fztmpXXXXXX"; + if ((fd = mkstemp(fname)) < 0) + { + if ((file = fdopen (fd, "wb"))) +#else + char fname [L_tmpnam]; + if (tmpnam (fname)) + { + if ((file = fopen (fname, "wb"))) +#endif + { + if (fwrite (data, 1, len, file) == len) + { + fclose(file); + if (!S9xUnfreezeGame (fname)) + S9xNPSetError ("Unable to load freeze file just received."); + } else { + S9xNPSetError ("Failed to write to temporary freeze file."); + fclose (file); + } + } else + S9xNPSetError ("Failed to create temporary freeze file."); + remove (fname); + } else + S9xNPSetError ("Unable to get name for temporary freeze file."); + delete data; +} + +uint32 S9xNPGetJoypad (int which1) +{ + if (Settings.NetPlay && which1 < 5) + return (NetPlay.Joypads [NetPlay.JoypadReadInd][which1]); + + return (0); +} + +void S9xNPStepJoypadHistory () +{ + if ((NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE != NetPlay.JoypadWriteInd) + { + NetPlay.JoypadReadInd = (NetPlay.JoypadReadInd + 1) % NP_JOYPAD_HIST_SIZE; + if (NetPlay.FrameCount != NetPlay.Frame [NetPlay.JoypadReadInd]) + { + S9xNPSetWarning ("This Snes9X session may be out of sync with the server."); +#ifdef NP_DEBUG + printf ("*** CLIENT: client out of sync with server (%d, %d) @%ld\n", NetPlay.FrameCount, NetPlay.Frame [NetPlay.JoypadReadInd], S9xGetMilliTime () - START); +#endif + } + } + else + { +#ifdef NP_DEBUG + printf ("*** CLIENT: S9xNPStepJoypadHistory NOT OK@%ld\n", S9xGetMilliTime () - START); +#endif + } +} + + +void S9xNPResetJoypadReadPos () +{ +#ifdef NP_DEBUG + printf ("CLIENT: ResetJoyReadPos @%ld\n", S9xGetMilliTime () - START); fflush (stdout); +#endif + NetPlay.JoypadWriteInd = 0; + NetPlay.JoypadReadInd = NP_JOYPAD_HIST_SIZE - 1; + for (int h = 0; h < NP_JOYPAD_HIST_SIZE; h++) + memset ((void *) &NetPlay.Joypads [h], 0, sizeof (NetPlay.Joypads [0])); +} + +bool8 S9xNPSendJoypadUpdate (uint32 joypad) +{ + uint8 data [7]; + uint8 *ptr = data; + + *ptr++ = NP_CLNT_MAGIC; + *ptr++ = NetPlay.MySequenceNum++; + *ptr++ = NP_CLNT_JOYPAD; + + joypad |= 0x80000000; + + WRITE_LONG (ptr, joypad); + if (!S9xNPSendData (NetPlay.Socket, data, 7)) + { + S9xNPSetError ("Error while sending joypad data server."); + S9xNPDisconnect (); + return (FALSE); + } + return (TRUE); +} + +void S9xNPDisconnect () +{ + close (NetPlay.Socket); + NetPlay.Socket = -1; + NetPlay.Connected = FALSE; + Settings.NetPlay = FALSE; +} + +bool8 S9xNPSendData (int socket, const uint8 *data, int length) +{ + int len = length; + const uint8 *ptr = data; + + NetPlay.PercentageComplete = 0; + + do + { + if (NetPlay.Abort) + return (FALSE); + + int num_bytes = len; + + // Write the data in small chunks, allowing this thread to spot an + // abort request from another thread. + if (num_bytes > 512) + num_bytes = 512; + + int sent = write (socket, (char *) ptr, num_bytes); + if (sent < 0) + { + if (errno == EINTR +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ) + { +#ifdef NP_DEBUG + printf ("CLIENT: EINTR, EAGAIN or EWOULDBLOCK while sending data @%ld\n", S9xGetMilliTime () - START); +#endif + continue; + } + return (FALSE); + } + else + if (sent == 0) + return (FALSE); + len -= sent; + ptr += sent; + + NetPlay.PercentageComplete = (uint8) (((length - len) * 100) / length); + } while (len > 0); + + return (TRUE); +} + +bool8 S9xNPGetData (int socket, uint8 *data, int length) +{ + int len = length; + uint8 *ptr = data; + int chunk = length / 50; + + if (chunk < 1024) + chunk = 1024; + + NetPlay.PercentageComplete = 0; + do + { + if (NetPlay.Abort) + return (FALSE); + + int num_bytes = len; + + // Read the data in small chunks, allowing this thread to spot an + // abort request from another thread. + if (num_bytes > chunk) + num_bytes = chunk; + + int got = read (socket, (char *) ptr, num_bytes); + if (got < 0) + { + if (errno == EINTR +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif +#ifdef WSAEWOULDBLOCK + || errno == WSAEWOULDBLOCK +#endif + ) + { +#ifdef NP_DEBUG + printf ("CLIENT: EINTR, EAGAIN or EWOULDBLOCK while receiving data @%ld\n", S9xGetMilliTime () - START); +#endif + continue; + } +#ifdef WSAEMSGSIZE + if (errno != WSAEMSGSIZE) + return (FALSE); + else + { + got = num_bytes; +#ifdef NP_DEBUG + printf ("CLIENT: WSAEMSGSIZE, actual bytes %d while receiving data @%ld\n", got, S9xGetMilliTime () - START); +#endif + } +#else + return (FALSE); +#endif + } + else + if (got == 0) + return (FALSE); + + len -= got; + ptr += got; + + if (!Settings.NetPlayServer && length > 1024) + { + NetPlay.PercentageComplete = (uint8) (((length - len) * 100) / length); +#ifdef __WIN32__ + PostMessage (GUI.hWnd, WM_USER, NetPlay.PercentageComplete, + NetPlay.PercentageComplete); + Sleep (0); +#endif + } + + } while (len > 0); + + return (TRUE); +} + +bool8 S9xNPInitialise () +{ +#ifdef __WIN32__ + static bool8 initialised = FALSE; + + if (!initialised) + { + initialised = TRUE; + WSADATA data; + +#ifdef NP_DEBUG + START = S9xGetMilliTime (); + + printf ("CLIENT/SERVER: Initialising WinSock @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Initialising Windows sockets interface..."); + if (WSAStartup (MAKEWORD (1, 0), &data) != 0) + { + S9xNPSetError ("Call to init Windows sockets failed. Do you have WinSock2 installed?"); + return (FALSE); + } + } +#endif + return (TRUE); +} + +void S9xNPDiscardHeartbeats () +{ + // Discard any pending heartbeats and wait for any frame that is currently + // being emulated to complete. +#ifdef NP_DEBUG + printf ("CLIENT: DiscardHeartbeats @%ld, finished @", S9xGetMilliTime () - START); + fflush (stdout); +#endif + +#ifdef __WIN32__ + while (WaitForSingleObject (GUI.ClientSemaphore, 200) == WAIT_OBJECT_0) + ; +#endif + +#ifdef NP_DEBUG + printf ("%ld\n", S9xGetMilliTime () - START); +#endif + NetPlay.Waiting4EmulationThread = FALSE; +} + +void S9xNPSetAction (const char *action, bool8 force) +{ + if (force || !Settings.NetPlayServer) + { + strncpy (NetPlay.ActionMsg, action, NP_MAX_ACTION_LEN - 1); + NetPlay.ActionMsg [NP_MAX_ACTION_LEN - 1] = 0; +#ifdef __WIN32__ + PostMessage (GUI.hWnd, WM_USER, 0, 0); + Sleep (0); +#endif + } +} + +void S9xNPSetError (const char *error) +{ + strncpy (NetPlay.ErrorMsg, error, NP_MAX_ACTION_LEN - 1); + NetPlay.ErrorMsg [NP_MAX_ACTION_LEN - 1] = 0; +#ifdef __WIN32 + PostMessage (GUI.hWnd, WM_USER + 1, 0, 0); + Sleep (0); +#endif +} + +void S9xNPSetWarning (const char *warning) +{ + strncpy (NetPlay.WarningMsg, warning, NP_MAX_ACTION_LEN - 1); + NetPlay.WarningMsg [NP_MAX_ACTION_LEN - 1] = 0; +#ifdef __WIN32__ + PostMessage (GUI.hWnd, WM_USER + 2, 0, 0); + Sleep (0); +#endif +} +#endif + + diff --git a/source/snes9x/unused/netplay.h b/source/snes9x/unused/netplay.h new file mode 100644 index 0000000..bfede8b --- /dev/null +++ b/source/snes9x/unused/netplay.h @@ -0,0 +1,340 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + +#ifndef _NETPLAY_H_ +#define _NETPLAY_H_ + +/* + * Client to server joypad update + * + * magic 1 + * sequence_no 1 + * opcode 1 + * joypad data 4 + * + * Server to client joypad update + * magic 1 + * sequence_no 1 + * opcode 1 + num joypads (top 3 bits) + * joypad data 4 * n + */ + +//#define NP_DEBUG 1 + +#define NP_VERSION 10 +#define NP_JOYPAD_HIST_SIZE 120 +#define NP_DEFAULT_PORT 6096 + +#define NP_MAX_CLIENTS 5 + +#define NP_SERV_MAGIC 'S' +#define NP_CLNT_MAGIC 'C' + +#define NP_CLNT_HELLO 0 +#define NP_CLNT_JOYPAD 1 +#define NP_CLNT_RESET 2 +#define NP_CLNT_PAUSE 3 +#define NP_CLNT_LOAD_ROM 4 +#define NP_CLNT_ROM_IMAGE 5 +#define NP_CLNT_FREEZE_FILE 6 +#define NP_CLNT_SRAM_DATA 7 +#define NP_CLNT_READY 8 +#define NP_CLNT_LOADED_ROM 9 +#define NP_CLNT_RECEIVED_ROM_IMAGE 10 +#define NP_CLNT_WAITING_FOR_ROM_IMAGE 11 + +#define NP_SERV_HELLO 0 +#define NP_SERV_JOYPAD 1 +#define NP_SERV_RESET 2 +#define NP_SERV_PAUSE 3 +#define NP_SERV_LOAD_ROM 4 +#define NP_SERV_ROM_IMAGE 5 +#define NP_SERV_FREEZE_FILE 6 +#define NP_SERV_SRAM_DATA 7 +#define NP_SERV_READY 8 + +struct SNPClient +{ + volatile uint8 SendSequenceNum; + volatile uint8 ReceiveSequenceNum; + volatile bool8 Connected; + volatile bool8 SaidHello; + volatile bool8 Paused; + volatile bool8 Ready; + int Socket; + char *ROMName; + char *HostName; + char *Who; +}; + +enum { + NP_SERVER_SEND_ROM_IMAGE, + NP_SERVER_SYNC_ALL, + NP_SERVER_SYNC_CLIENT, + NP_SERVER_SEND_FREEZE_FILE_ALL, + NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL, + NP_SERVER_RESET_ALL, + NP_SERVER_SEND_SRAM_ALL, + NP_SERVER_SEND_SRAM +}; + +#define NP_MAX_TASKS 20 + +struct NPServerTask +{ + uint32 Task; + void *Data; +}; + +struct SNPServer +{ + struct SNPClient Clients [NP_MAX_CLIENTS]; + int NumClients; + volatile struct NPServerTask TaskQueue [NP_MAX_TASKS]; + volatile uint32 TaskHead; + volatile uint32 TaskTail; + int Socket; + uint32 FrameTime; + uint32 FrameCount; + char ROMName [30]; + uint32 Joypads [5]; + bool8 ClientPaused; + uint32 Paused; + bool8 SendROMImageOnConnect; + bool8 SyncByReset; +}; + +#define NP_MAX_ACTION_LEN 200 + +struct SNetPlay +{ + volatile uint8 MySequenceNum; + volatile uint8 ServerSequenceNum; + volatile bool8 Connected; + volatile bool8 Abort; + volatile uint8 Player; + volatile bool8 ClientsReady [NP_MAX_CLIENTS]; + volatile bool8 ClientsPaused [NP_MAX_CLIENTS]; + volatile bool8 Paused; + volatile bool8 PendingWait4Sync; + volatile uint8 PercentageComplete; + volatile bool8 Waiting4EmulationThread; + volatile bool8 Answer; +#ifdef __WIN32__ + HANDLE ReplyEvent; +#endif + volatile int Socket; + char *ServerHostName; + char *ROMName; + int Port; + volatile uint32 JoypadWriteInd; + volatile uint32 JoypadReadInd; + uint32 Joypads [NP_JOYPAD_HIST_SIZE][NP_MAX_CLIENTS]; + uint32 Frame [NP_JOYPAD_HIST_SIZE]; + uint32 FrameCount; + uint32 MaxFrameSkip; + uint32 MaxBehindFrameCount; + char ActionMsg [NP_MAX_ACTION_LEN]; + char ErrorMsg [NP_MAX_ACTION_LEN]; + char WarningMsg [NP_MAX_ACTION_LEN]; +}; + +extern "C" struct SNetPlay NetPlay; + +// +// NETPLAY_CLIENT_HELLO message format: +// header +// frame_time (4) +// ROMName (variable) + +#define WRITE_LONG(p, v) { \ +*((p) + 0) = (uint8) ((v) >> 24); \ +*((p) + 1) = (uint8) ((v) >> 16); \ +*((p) + 2) = (uint8) ((v) >> 8); \ +*((p) + 3) = (uint8) ((v) >> 0); \ +} + +#define READ_LONG(p) \ +((((uint8) *((p) + 0)) << 24) | \ + (((uint8) *((p) + 1)) << 16) | \ + (((uint8) *((p) + 2)) << 8) | \ + (((uint8) *((p) + 3)) << 0)) + +bool8 S9xNPConnectToServer (const char *server_name, int port, + const char *rom_name); +bool8 S9xNPWaitForHeartBeat (); +uint32 S9xNPGetJoypad (int which1); +bool8 S9xNPSendJoypadUpdate (uint32 joypad); +void S9xNPDisconnect (); +bool8 S9xNPInitialise (); +bool8 S9xNPSendData (int fd, const uint8 *data, int len); +bool8 S9xNPGetData (int fd, uint8 *data, int len); + +void S9xNPSyncClients (); +void S9xNPStepJoypadHistory (); + +void S9xNPResetJoypadReadPos (); +bool8 S9xNPSendReady (uint8 op = NP_CLNT_READY); +bool8 S9xNPSendPause (bool8 pause); +void S9xNPReset (); +void S9xNPSetAction (const char *action, bool8 force = FALSE); +void S9xNPSetError (const char *error); +void S9xNPSetWarning (const char *warning); +void S9xNPDiscardHeartbeats (); +void S9xNPServerQueueSendingFreezeFile (const char *filename); +void S9xNPServerQueueSyncAll (); +void S9xNPServerQueueSendingROMImage (); +void S9xNPServerQueueSendingLoadROMRequest (const char *filename); + +void S9xNPServerAddTask (uint32 task, void *data); + +bool8 S9xNPStartServer (int port); +void S9xNPStopServer (); +#ifdef __WIN32__ +#define S9xGetMilliTime timeGetTime +#else +uint32 S9xGetMilliTime (); +#endif +#endif + diff --git a/source/snes9x/unused/reader.cpp b/source/snes9x/unused/reader.cpp new file mode 100644 index 0000000..3712fa4 --- /dev/null +++ b/source/snes9x/unused/reader.cpp @@ -0,0 +1,270 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +// Abstract the details of reading from zip files versus FILE *'s. + +#include "reader.h" +#include + + +// Generic constructor/destructor + +Reader::Reader(void){} + +Reader::~Reader(){} + + +// Generic getline function, based on gets. Reimlpement if you can do better. + +char *Reader::getline(void){ + bool eof; + std::string ret; + ret=getline(eof); + if(ret.size()==0 && eof) return NULL; + return strdup(ret.c_str()); +} + +std::string Reader::getline(bool &eof){ + char buf[100]; + std::string ret; + + eof=false; + ret.clear(); + do { + if(gets(buf, sizeof(buf))==NULL){ + eof=true; + break; + } + ret.append(buf); + } while(*ret.rbegin()!='\n'); + return ret; +} + + +// snes9x.h STREAM reader + +fReader::fReader(STREAM f){ + fp=f; +} + +fReader::~fReader(void){} + +int fReader::get_char(){ + return GETC_STREAM(fp); +} + +char *fReader::gets(char *buf, size_t len){ + return GETS_STREAM(buf, len, fp); +} + +size_t fReader::read(char *buf, size_t len){ + return READ_STREAM(buf, len, fp); +} + + +// unzip reader +#ifdef UNZIP_SUPPORT + +unzReader::unzReader(unzFile &v){ + file=v; + head=NULL; + numbytes=0; +} + +unzReader::~unzReader(void){} + +int unzReader::get_char(){ + unsigned char c; + + if(numbytes<=0){ + numbytes=unzReadCurrentFile(file, buffer, unz_BUFFSIZ); + if(numbytes<=0) return (EOF); + head=buffer; + } + + c=*head; + head++; + numbytes--; + return (int) c; +} + +char *unzReader::gets(char *buf, size_t len){ + size_t i; + int c; + + for(i=0; i0){ + memcpy(buf, head, numbytes); + numread+=numbytes; + head=NULL; + numbytes=0; + } + int l=unzReadCurrentFile(file, buf+numread, len-numread); + if(l>0) numread+=l; + return numread; +} +#endif diff --git a/source/snes9x/unused/reader.h b/source/snes9x/unused/reader.h new file mode 100644 index 0000000..4e26009 --- /dev/null +++ b/source/snes9x/unused/reader.h @@ -0,0 +1,196 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +// Abstract the details of reading from zip files versus FILE *'s. + +#ifndef _READER_H_ +#define _READER_H_ + +#include +#include + +#include "snes9x.h" + +class Reader { + public: + Reader(void); + virtual ~Reader(); + virtual int get_char() = 0; + virtual char *gets(char *buf, size_t len) = 0; + virtual char *getline(void); // free() when done + virtual std::string getline(bool &eof); + virtual size_t read(char *buf, size_t len) = 0; +}; + +class fReader : public Reader { + public: + fReader(STREAM fp); + virtual ~fReader(void); + virtual int get_char(); + virtual char *gets(char *buf, size_t len); + virtual size_t read(char *buf, size_t len); + private: + STREAM fp; +}; + +#ifdef UNZIP_SUPPORT +#include "unzip.h" + +#define unz_BUFFSIZ 1024 + +class unzReader : public Reader { + public: + unzReader(unzFile &v); + virtual ~unzReader(void); + virtual int get_char(); + virtual char *gets(char *buf, size_t len); + virtual size_t read(char *buf, size_t len); + private: + unzFile file; + char buffer[unz_BUFFSIZ]; + char *head; + size_t numbytes; +}; +#endif + +#endif /* ndef _READER_H_ */ diff --git a/source/snes9x/unused/screenshot.cpp b/source/snes9x/unused/screenshot.cpp new file mode 100644 index 0000000..e285bf2 --- /dev/null +++ b/source/snes9x/unused/screenshot.cpp @@ -0,0 +1,270 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + + + +#ifdef HAVE_CONFIG_H + #include +#endif +#include + +#ifndef __WIN32__ +#include +#else +#include +#endif +#include +#include + +#ifdef HAVE_LIBPNG +#include +#endif + +#include "snes9x.h" +#include "memmap.h" +#include "display.h" +#include "gfx.h" +#include "ppu.h" +#include "screenshot.h" + +bool8 S9xDoScreenshot(int width, int height){ +#ifdef HAVE_LIBPNG + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_color_8 sig_bit; + int imgwidth; + int imgheight; + const char *fname=S9xGetFilenameInc(".png", SCREENSHOT_DIR); + + Settings.TakeScreenshot=FALSE; + + if((fp=fopen(fname, "wb"))==NULL){ + perror("Screenshot failed"); + return FALSE; + } + + png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!png_ptr){ + fclose(fp); + unlink(fname); + return FALSE; + } + info_ptr=png_create_info_struct(png_ptr); + if(!info_ptr){ + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + fclose(fp); + unlink(fname); + return FALSE; + } + + if(setjmp(png_jmpbuf(png_ptr))){ + perror("Screenshot: setjmp"); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + unlink(fname); + return FALSE; + } + + imgwidth=width; + imgheight=height; + if(Settings.StretchScreenshots==1){ + if(width<=256 && height>SNES_HEIGHT_EXTENDED) imgwidth=width<<1; + if(width>256 && height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1; + } else if(Settings.StretchScreenshots==2){ + if(width<=256) imgwidth=width<<1; + if(height<=SNES_HEIGHT_EXTENDED) imgheight=height<<1; + } + + png_init_io(png_ptr, fp); + png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + /* 5 bits per color */ + sig_bit.red=5; + sig_bit.green=5; + sig_bit.blue=5; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, &sig_bit); + + png_write_info(png_ptr, info_ptr); + + png_set_packing(png_ptr); + + png_byte *row_pointer=new png_byte [png_get_rowbytes(png_ptr, info_ptr)]; + uint16 *screen=GFX.Screen; + for(int y=0; y +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifndef __WIN32__ +#include +#include +#endif + +#ifdef __WIN32__ + +#include +#include +#define ioctl ioctlsocket +#define close closesocket +#define read(a,b,c) recv(a, b, c, 0) +#define write(a,b,c) send(a, b, c, 0) +#define gettimeofday(a,b) S9xGetTimeOfDay (a) +#define exit(a) _endthread() +void S9xGetTimeOfDay (struct timeval *n); +#else + +#include +#include +#include +#include +#include +#include + +#ifdef __SVR4 +#include +#endif + +#endif // !__WIN32__ + +#include "snes9x.h" +#include "netplay.h" +#include "memmap.h" +#include "snapshot.h" + +#define NP_ONE_CLIENT 1 + +struct SNPServer NPServer; + +extern unsigned long START; + +void S9xNPSendToAllClients (uint8 *data, int len); +bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len); +void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len); +void S9xNPNoClientReady (int start_index = NP_ONE_CLIENT); +void S9xNPRecomputePause (); +void S9xNPWaitForEmulationToComplete (); +void S9xNPSendROMImageToAllClients (); +bool8 S9xNPSendROMImageToClient (int client); +void S9xNPSendSRAMToClient (int c); +void S9xNPSendSRAMToAllClients (); +void S9xNPSyncClient (int); +void S9xNPSendROMLoadRequest (const char *filename); +void S9xNPSendFreezeFileToAllClients (const char *filename); +void S9xNPStopServer (); + +void S9xNPShutdownClient (int c, bool8 report_error = FALSE) +{ + if (NPServer.Clients [c].Connected) + { + NPServer.Clients [c].Connected = FALSE; + NPServer.Clients [c].SaidHello = FALSE; + + close (NPServer.Clients [c].Socket); +#ifdef NP_DEBUG + printf ("SERVER: Player %d disconnecting @%ld\n", c + 1, S9xGetMilliTime () - START); +#endif + if (report_error) + { + sprintf (NetPlay.ErrorMsg, + "Player %d on '%s' has disconnected.", c + 1, + NPServer.Clients [c].HostName); + S9xNPSetError (NetPlay.ErrorMsg); + } + + if (NPServer.Clients [c].HostName) + { + free ((char *) NPServer.Clients [c].HostName); + NPServer.Clients [c].HostName = NULL; + } + if (NPServer.Clients [c].ROMName) + { + free ((char *) NPServer.Clients [c].ROMName); + NPServer.Clients [c].ROMName = NULL; + } + if (NPServer.Clients [c].Who) + { + free ((char *) NPServer.Clients [c].Who); + NPServer.Clients [c].Who = NULL; + } + NPServer.Joypads [c] = 0; + NPServer.NumClients--; + S9xNPRecomputePause (); + } +} + +static bool8 S9xNPSGetData (int socket, uint8 *data, int length) +{ + int len = length; + uint8 *ptr = data; + + do + { + int num_bytes = len; + + // Read the data in small chunks, allowing this thread to spot an + // abort request from another thread. + if (num_bytes > 512) + num_bytes = 512; + + int got = read (socket, (char *) ptr, num_bytes); + if (got < 0) + { + if (errno == EINTR +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif +#ifdef WSAEWOULDBLOCK + || errno == WSAEWOULDBLOCK +#endif + ) + continue; +#ifdef WSAEMSGSIZE + if (errno != WSAEMSGSIZE) + return (FALSE); + else + { + got = num_bytes; +#ifdef NP_DEBUG + printf ("SERVER: WSAEMSGSIZE, actual bytes %d while receiving data @%d\n", got, S9xGetMilliTime () - START); +#endif + } +#else + return (FALSE); +#endif + } + else + if (got == 0) + return (FALSE); + + len -= got; + ptr += got; + } while (len > 0); + + return (TRUE); +} + +static bool8 S9xNPSSendData (int fd, const uint8 *data, int length) +{ + int Percent = 0; + int len = length; + int chunk = length / 50; + + if (chunk < 1024) + chunk = 1024; + + do + { + int num_bytes = len; + + // Write the data in small chunks, allowing this thread to spot an + // abort request from another thread. + if (num_bytes > chunk) + num_bytes = chunk; + + int sent; + sent = write (fd, (char *) data, len); + + if (sent < 0) + { + if (errno == EINTR +#ifdef EAGAIN + || errno == EAGAIN +#endif +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ) + { +#ifdef NP_DEBUG + printf ("SERVER: EINTR, EAGAIN or EWOULDBLOCK while sending data @%ld\n", S9xGetMilliTime () - START); +#endif + continue; + } + return (FALSE); + } + else + if (sent == 0) + return (FALSE); + len -= sent; + data += sent; + if (length > 1024) + { + Percent = (uint8) (((length - len) * 100) / length); +#ifdef __WIN32__ + PostMessage (GUI.hWnd, WM_USER, Percent, Percent); + Sleep (0); +#endif + } + } while (len > 0); + + return (TRUE); +} + +void S9xNPSendHeartBeat () +{ + int len = 3; + uint8 data [3 + 4 * 5]; + uint8 *ptr = data; + int n; + + for (n = NP_MAX_CLIENTS - 1; n >= 0; n--) + { + if (NPServer.Clients [n].SaidHello) + break; + } + + if (n >= 0) + { + bool8 Paused = NPServer.Paused != 0; + + NPServer.FrameCount++; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = 0; // Individual client sequence number will get placed here + *ptr++ = NP_SERV_JOYPAD | (n << 6) | ((Paused != 0) << 5); + + WRITE_LONG (ptr, NPServer.FrameCount); + len += 4; + ptr += 4; + + int i; + + for (i = 0; i <= n; i++) + { + WRITE_LONG (ptr, NPServer.Joypads [i]); + len += 4; + ptr += 4; + } + + S9xNPSendToAllClients (data, len); + } +} + +void S9xNPSendToAllClients (uint8 *data, int len) +{ + int i; + + for (i = 0; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].SaidHello) + { + data [1] = NPServer.Clients [i].SendSequenceNum++; + if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) + S9xNPShutdownClient (i, TRUE); + } + } +} + +void S9xNPProcessClient (int c) +{ + uint8 header [7]; + uint8 *data; + uint32 len; + uint8 *ptr; + + if (!S9xNPSGetData (NPServer.Clients [c].Socket, header, 7)) + { + S9xNPSetWarning ("SERVER: Failed to get message header from client.\n"); + S9xNPShutdownClient (c, TRUE); + return; + } + if (header [0] != NP_CLNT_MAGIC) + { + S9xNPSetWarning ("SERVER: Bad header magic value received from client.\n"); + S9xNPShutdownClient (c, TRUE); + return; + } + + if (header [1] != NPServer.Clients [c].ReceiveSequenceNum) + { +#ifdef NP_DEBUG + printf ("SERVER: Messages lost from '%s', expected %d, got %d\n", + NPServer.Clients [c].HostName ? + NPServer.Clients [c].HostName : "Unknown", + NPServer.Clients [c].ReceiveSequenceNum, + header [1]); +#endif + sprintf (NetPlay.WarningMsg, + "SERVER: Messages lost from '%s', expected %d, got %d\n", + NPServer.Clients [c].HostName ? + NPServer.Clients [c].HostName : "Unknown", + NPServer.Clients [c].ReceiveSequenceNum, + header [1]); + NPServer.Clients [c].ReceiveSequenceNum = header [1] + 1; + S9xNPSetWarning (NetPlay.WarningMsg); + } + else + NPServer.Clients [c].ReceiveSequenceNum++; + + len = READ_LONG (&header [3]); + + switch (header [2] & 0x3f) + { + case NP_CLNT_HELLO: +#ifdef NP_DEBUG + printf ("SERVER: Got HELLO from client @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("Got HELLO from client...", TRUE); + if (len > 0x10000) + { + S9xNPSetWarning ("SERVER: Client HELLO message length error."); + S9xNPShutdownClient (c, TRUE); + return; + } + data = new uint8 [len - 7]; + if (!S9xNPSGetData (NPServer.Clients [c].Socket, data, len - 7)) + { + S9xNPSetWarning ("SERVER: Failed to get HELLO message content from client."); + S9xNPShutdownClient (c, TRUE); + return; + } + + if (NPServer.NumClients <= NP_ONE_CLIENT) + { + NPServer.FrameTime = READ_LONG (data); + strncpy (NPServer.ROMName, (char *) &data [4], 29); + NPServer.ROMName [29] = 0; + } + + NPServer.Clients [c].ROMName = strdup ((char *) &data [4]); +#ifdef NP_DEBUG + printf ("SERVER: Client is playing: %s, Frame Time: %d @%ld\n", data + 4, READ_LONG (data), S9xGetMilliTime () - START); +#endif + + NPServer.Clients [c].SendSequenceNum = 0; + + len = 7 + 1 + 1 + 4 + strlen (NPServer.ROMName) + 1; + + delete data; + ptr = data = new uint8 [len]; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = NPServer.Clients [c].SendSequenceNum++; + + if (NPServer.SendROMImageOnConnect && + NPServer.NumClients > NP_ONE_CLIENT) + *ptr++ = NP_SERV_HELLO | 0x80; + else + *ptr++ = NP_SERV_HELLO; + WRITE_LONG (ptr, len); + ptr += 4; + *ptr++ = NP_VERSION; + *ptr++ = c + 1; + WRITE_LONG (ptr, NPServer.FrameCount); + ptr += 4; + strcpy ((char *) ptr, NPServer.ROMName); + +#ifdef NP_DEBUG + printf ("SERVER: Sending welcome information to client @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("SERVER: Sending welcome information to new client...", TRUE); + if (!S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) + { + S9xNPSetWarning ("SERVER: Failed to send welcome message to client."); + S9xNPShutdownClient (c, TRUE); + return; + } + delete data; +#ifdef NP_DEBUG + printf ("SERVER: Waiting for a response from the client @%ld...\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("SERVER: Waiting for a response from the client...", TRUE); + break; + + case NP_CLNT_LOADED_ROM: +#ifdef NP_DEBUG + printf ("SERVER: Client %d loaded requested ROM @%ld...\n", c, S9xGetMilliTime () - START); +#endif + NPServer.Clients [c].SaidHello = TRUE; + NPServer.Clients [c].Ready = FALSE; + NPServer.Clients [c].Paused = FALSE; + S9xNPRecomputePause (); + S9xNPWaitForEmulationToComplete (); + + if (NPServer.SyncByReset) + { + S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); + break; + + case NP_CLNT_RECEIVED_ROM_IMAGE: +#ifdef NP_DEBUG + printf ("SERVER: Client %d received ROM image @%ld...\n", c, S9xGetMilliTime () - START); +#endif + NPServer.Clients [c].SaidHello = TRUE; + NPServer.Clients [c].Ready = FALSE; + NPServer.Clients [c].Paused = FALSE; + S9xNPRecomputePause (); + S9xNPWaitForEmulationToComplete (); + + if (NPServer.SyncByReset) + { + S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); + + break; + + case NP_CLNT_WAITING_FOR_ROM_IMAGE: +#ifdef NP_DEBUG + printf ("SERVER: Client %d waiting for ROM image @%ld...\n", c, S9xGetMilliTime () - START); +#endif + NPServer.Clients [c].SaidHello = TRUE; + NPServer.Clients [c].Ready = FALSE; + NPServer.Clients [c].Paused = FALSE; + S9xNPRecomputePause (); + S9xNPSendROMImageToClient (c); + break; + + case NP_CLNT_READY: +#ifdef NP_DEBUG + printf ("SERVER: Client %d ready @%ld...\n", c, S9xGetMilliTime () - START); +#endif + if (NPServer.Clients [c].SaidHello) + { + NPServer.Clients [c].Paused = FALSE; + NPServer.Clients [c].Ready = TRUE; + + S9xNPRecomputePause (); + break; + } + NPServer.Clients [c].SaidHello = TRUE; + NPServer.Clients [c].Ready = TRUE; + NPServer.Clients [c].Paused = FALSE; + S9xNPRecomputePause (); + +//printf ("SERVER: SaidHello = TRUE, SeqNum = %d @%d\n", NPServer.Clients [c].SendSequenceNum, S9xGetMilliTime () - START); + if (NPServer.NumClients > NP_ONE_CLIENT) + { + if (!NPServer.SendROMImageOnConnect) + { + S9xNPWaitForEmulationToComplete (); + + if (NPServer.SyncByReset) + { + S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); + } + } + else + { + NPServer.Clients [c].Ready = TRUE; + S9xNPRecomputePause (); + } + break; + case NP_CLNT_JOYPAD: + NPServer.Joypads [c] = len; + break; + case NP_CLNT_PAUSE: +#ifdef NP_DEBUG + printf ("SERVER: Client %d Paused: %s @%ld\n", c, (header [2] & 0x80) ? "YES" : "NO", S9xGetMilliTime () - START); +#endif + NPServer.Clients [c].Paused = (header [2] & 0x80) != 0; + if (NPServer.Clients [c].Paused) + sprintf (NetPlay.WarningMsg, "SERVER: Client %d has paused.", c + 1); + else + sprintf (NetPlay.WarningMsg, "SERVER: Client %d has resumed.", c + 1); + S9xNPSetWarning (NetPlay.WarningMsg); + S9xNPRecomputePause (); + break; + } +} + +void S9xNPAcceptClient (int Listen, bool8 block) +{ + struct sockaddr_in remote_address; + struct linger val2; + struct hostent *host; + int new_fd; + int i; + +#ifdef NP_DEBUG + printf ("SERVER: attempting to accept new client connection @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("SERVER: Attempting to accept client connection...", TRUE); + memset (&remote_address, 0, sizeof (remote_address)); + ACCEPT_SIZE_T len = sizeof (remote_address); + + new_fd = accept (Listen, (struct sockaddr *)&remote_address, &len); + + S9xNPSetAction ("Setting socket options...", TRUE); + val2.l_onoff = 1; + val2.l_linger = 0; + if (setsockopt (new_fd, SOL_SOCKET, SO_LINGER, + (char *) &val2, sizeof (val2)) < 0) + { + S9xNPSetError ("Setting socket options failed."); + close (new_fd); + return; + } + + for (i = 0; i < NP_MAX_CLIENTS; i++) + { + if (!NPServer.Clients [i].Connected) + { + NPServer.NumClients++; + NPServer.Clients [i].Socket = new_fd; + NPServer.Clients [i].SendSequenceNum = 0; + NPServer.Clients [i].ReceiveSequenceNum = 0; + NPServer.Clients [i].Connected = TRUE; + NPServer.Clients [i].SaidHello = FALSE; + NPServer.Clients [i].Paused = FALSE; + NPServer.Clients [i].Ready = FALSE; + NPServer.Clients [i].ROMName = NULL; + NPServer.Clients [i].HostName = NULL; + NPServer.Clients [i].Who = NULL; + break; + } + } + + if (i >= NP_MAX_CLIENTS) + { + S9xNPSetError ("SERVER: Maximum number of NetPlay Clients have already connected."); + close (new_fd); + return; + } + + if (remote_address.sin_family == AF_INET) + { +#ifdef NP_DEBUG + printf ("SERVER: Looking up new client's hostname @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("SERVER: Looking up new client's hostname...", TRUE); + host = gethostbyaddr ((char *) &remote_address.sin_addr, + sizeof (remote_address.sin_addr), AF_INET); + + if (host) + { +#ifdef NP_DEBUG + printf ("SERVER: resolved new client's hostname (%s) @%ld\n", host->h_name, S9xGetMilliTime () - START); +#endif + sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, host->h_name); + NPServer.Clients [i].HostName = strdup (host->h_name); + } + else + { + char *ip = inet_ntoa (remote_address.sin_addr); + if (ip) + NPServer.Clients [i].HostName = strdup (ip); +#ifdef NP_DEBUG + printf ("SERVER: couldn't resolve new client's hostname (%s) @%ld\n", ip ? ip : "Unknown", S9xGetMilliTime () - START); +#endif + sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, ip ? ip : "Unknown"); + } + S9xNPSetWarning (NetPlay.WarningMsg); + } +#ifdef NP_DEBUG + printf ("SERVER: waiting for HELLO message from new client @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPSetAction ("SERVER: Waiting for HELLO message from new client..."); +} + +static bool8 server_continue = TRUE; + +static bool8 S9xNPServerInit (int port) +{ + struct sockaddr_in address; + int i; + int val; + + if (!S9xNPInitialise ()) + return (FALSE); + + for (i = 0; i < NP_MAX_CLIENTS; i++) + { + NPServer.Clients [i].SendSequenceNum = 0; + NPServer.Clients [i].ReceiveSequenceNum = 0; + NPServer.Clients [i].Connected = FALSE; + NPServer.Clients [i].SaidHello = FALSE; + NPServer.Clients [i].Paused = FALSE; + NPServer.Clients [i].Ready = FALSE; + NPServer.Clients [i].Socket = 0; + NPServer.Clients [i].ROMName = NULL; + NPServer.Clients [i].HostName = NULL; + NPServer.Clients [i].Who = NULL; + NPServer.Joypads [i] = 0; + } + + NPServer.NumClients = 0; + NPServer.FrameCount = 0; + +#ifdef NP_DEBUG + printf ("SERVER: Creating socket @%ld\n", S9xGetMilliTime () - START); +#endif + if ((NPServer.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) + { + S9xNPSetError ("NetPlay Server: Can't create listening socket."); + return (FALSE); + } + + val = 1; + setsockopt (NPServer.Socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&val, sizeof (val)); + + memset (&address, 0, sizeof (address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl (INADDR_ANY); + address.sin_port = htons (port); + +#ifdef NP_DEBUG + printf ("SERVER: Binding socket to address and port @%ld\n", S9xGetMilliTime () - START); +#endif + if (bind (NPServer.Socket, (struct sockaddr *) &address, sizeof (address)) < 0) + { + S9xNPSetError ("NetPlay Server: Can't bind socket to port number.\nPort already in use?"); + return (FALSE); + } + +#ifdef NP_DEBUG + printf ("SERVER: Getting socket to listen @%ld\n", S9xGetMilliTime () - START); +#endif + if (listen (NPServer.Socket, NP_MAX_CLIENTS) < 0) + { + S9xNPSetError ("NetPlay Server: Can't get new socket to listen."); + return (FALSE); + } + +#ifdef NP_DEBUG + printf ("SERVER: Init complete @%ld\n", S9xGetMilliTime () - START); +#endif + return (TRUE); +} + +void S9xNPServerLoop (void *) +{ +#ifdef __WIN32__ + BOOL success = FALSE; +#else + bool8 success = FALSE; +#endif + + while (server_continue) + { + fd_set read_fds; + struct timeval timeout; + int res; + int i; + + int max_fd = NPServer.Socket; + +#ifdef __WIN32__ + Sleep (0); +#endif + + if (success && !Settings.Paused && !Settings.StopEmulation && + !Settings.ForcedPause && !NPServer.Paused) + { + S9xNPSendHeartBeat (); + } + + do + { + FD_ZERO (&read_fds); + FD_SET (NPServer.Socket, &read_fds); + for (i = 0; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].Connected) + { + FD_SET (NPServer.Clients [i].Socket, &read_fds); + if (NPServer.Clients [i].Socket > max_fd) + max_fd = NPServer.Clients [i].Socket; + } + } + + timeout.tv_sec = 0; + timeout.tv_usec = 1000; + res = select (max_fd + 1, &read_fds, NULL, NULL, &timeout); + + if (res > 0) + { + if (FD_ISSET (NPServer.Socket, &read_fds)) + S9xNPAcceptClient (NPServer.Socket, FALSE); + + for (i = 0; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].Connected && + FD_ISSET (NPServer.Clients [i].Socket, &read_fds)) + { + S9xNPProcessClient (i); + } + } + } + } while (res > 0); + +#ifdef __WIN32__ + success = WaitForSingleObject (GUI.ServerTimerSemaphore, 200) == WAIT_OBJECT_0; +#endif + + while (NPServer.TaskHead != NPServer.TaskTail) + { + void *task_data = NPServer.TaskQueue [NPServer.TaskHead].Data; + +#if defined(NP_DEBUG) && NP_DEBUG == 2 + printf ("SERVER: task %d @%ld\n", NPServer.TaskQueue [NPServer.TaskHead].Task, S9xGetMilliTime () - START); +#endif + + switch (NPServer.TaskQueue [NPServer.TaskHead].Task) + { + case NP_SERVER_SEND_ROM_IMAGE: + S9xNPSendROMImageToAllClients (); + break; + case NP_SERVER_SYNC_CLIENT: + NPServer.Clients [(pint) task_data].Ready = FALSE; + S9xNPRecomputePause (); + S9xNPSyncClient ((pint) task_data); + break; + case NP_SERVER_SYNC_ALL: + S9xNPSyncClients (); + break; + case NP_SERVER_SEND_FREEZE_FILE_ALL: + S9xNPSendFreezeFileToAllClients ((char *) task_data); + free ((char *) task_data); + break; + case NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL: + S9xNPSendROMLoadRequest ((char *) task_data); + free ((char *) task_data); + break; + case NP_SERVER_RESET_ALL: + S9xNPNoClientReady (0); + S9xNPWaitForEmulationToComplete (); + S9xNPSetAction ("SERVER: Sending RESET to all clients...", TRUE); +#ifdef NP_DEBUG + printf ("SERVER: Sending RESET to all clients @%ld\n", S9xGetMilliTime () - START); +#endif + { + uint8 reset [7]; + uint8 *ptr; + + ptr = reset; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = 0; + *ptr++ = NP_SERV_RESET; + WRITE_LONG (ptr, NPServer.FrameCount); + S9xNPSendToAllClients (reset, 7); + } + break; + case NP_SERVER_SEND_SRAM: + NPServer.Clients [(pint) task_data].Ready = FALSE; + S9xNPRecomputePause (); + S9xNPWaitForEmulationToComplete (); + S9xNPSendSRAMToClient ((pint) task_data); + break; + + case NP_SERVER_SEND_SRAM_ALL: + S9xNPNoClientReady (); + S9xNPWaitForEmulationToComplete (); + S9xNPSendSRAMToAllClients (); + break; + + default: + S9xNPSetError ("SERVER: *** Unknown task ***\n"); + break; + } + NPServer.TaskHead = (NPServer.TaskHead + 1) % NP_MAX_TASKS; + } + } +#ifdef NP_DEBUG + printf ("SERVER: Server thread exiting @%ld\n", S9xGetMilliTime () - START); +#endif + S9xNPStopServer (); +} + +bool8 S9xNPStartServer (int port) +{ + static int p; + +#ifdef NP_DEBUG + printf ("SERVER: Starting server on port %d @%ld\n", port, S9xGetMilliTime () - START); +#endif + p = port; + server_continue = TRUE; + if (S9xNPServerInit (port)) +#ifdef __WIN32__ + return (_beginthread (S9xNPServerLoop, 0, &p) != ~0); +#else + return (TRUE); +#endif + + return (FALSE); +} + +void S9xNPStopServer () +{ +#ifdef NP_DEBUG + printf ("SERVER: Stopping server @%ld\n", S9xGetMilliTime () - START); +#endif + server_continue = FALSE; + close (NPServer.Socket); + + for (int i = 0; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].Connected) + { + close (NPServer.Clients [i].Socket); + NPServer.Clients [i].Connected = FALSE; + NPServer.Clients [i].SaidHello = FALSE; + } + } +} + +#ifdef __WIN32__ +void S9xGetTimeOfDay (struct timeval *n) +{ + unsigned long t = S9xGetMilliTime (); + + n->tv_sec = t / 1000; + n->tv_usec = (t % 1000) * 1000; +} +#endif + +void S9xNPSendROMImageToAllClients () +{ + S9xNPNoClientReady (); + S9xNPWaitForEmulationToComplete (); + + int c; + + for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) + { + if (NPServer.Clients [c].SaidHello) + S9xNPSendROMImageToClient (c); + } + + if (NPServer.SyncByReset) + { + S9xNPServerAddTask (NP_SERVER_SEND_SRAM_ALL, 0); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); + } + else + S9xNPSyncClient (-1); +} + +bool8 S9xNPSendROMImageToClient (int c) +{ +#ifdef NP_DEBUG + printf ("SERVER: Sending ROM image to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); +#endif + sprintf (NetPlay.ActionMsg, "Sending ROM image to player %d...", c + 1); + S9xNPSetAction (NetPlay.ActionMsg, TRUE); + + uint8 header [7 + 1 + 4]; + uint8 *ptr = header; + int len = sizeof (header) + Memory.CalculatedSize + + strlen (Memory.ROMFilename) + 1; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = NPServer.Clients [c].SendSequenceNum++; + *ptr++ = NP_SERV_ROM_IMAGE; + WRITE_LONG (ptr, len); + ptr += 4; + *ptr++ = Memory.HiROM; + WRITE_LONG (ptr, Memory.CalculatedSize); + + if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, sizeof (header)) || + !S9xNPSSendData (NPServer.Clients [c].Socket, Memory.ROM, + Memory.CalculatedSize) || + !S9xNPSSendData (NPServer.Clients [c].Socket, (uint8 *) Memory.ROMFilename, + strlen (Memory.ROMFilename) + 1)) + { + S9xNPShutdownClient (c, TRUE); + return (FALSE); + } + return (TRUE); +} + +void S9xNPSyncClients () +{ + S9xNPNoClientReady (); + S9xNPSyncClient (-1); +} + +void S9xNPSyncClient (int client) +{ +#ifdef HAVE_MKSTEMP + char fname[] = "/tmp/snes9x_fztmpXXXXXX"; +#else + char fname [L_tmpnam]; +#endif + + S9xNPWaitForEmulationToComplete (); + + S9xNPSetAction ("SERVER: Freezing game...", TRUE); +#ifdef HAVE_MKSTEMP + if ( (mkstemp(fname) < 0) && S9xFreezeGame(fname) ) +#else + if ( tmpnam(fname) && S9xFreezeGame(fname) ) +#endif + { + uint8 *data; + uint32 len; + + S9xNPSetAction ("SERVER: Loading freeze file...", TRUE); + if (S9xNPLoadFreezeFile (fname, data, len)) + { + int c; + + if (client < 0) + { + for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) + { + if (NPServer.Clients [c].SaidHello) + { + NPServer.Clients [client].Ready = FALSE; + S9xNPRecomputePause (); + S9xNPSendFreezeFile (c, data, len); + } + } + } + else + { + NPServer.Clients [client].Ready = FALSE; + S9xNPRecomputePause (); + S9xNPSendFreezeFile (client, data, len); + } + delete data; + } + remove (fname); + } +} + +bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len) +{ + FILE *ff; + + if ((ff = fopen (fname, "rb"))) + { + fseek (ff, 0, SEEK_END); + len = ftell (ff); + fseek (ff, 0, SEEK_SET); + + data = new uint8 [len]; + bool8 ok = (fread (data, 1, len, ff) == len); + fclose (ff); + + return (ok); + } + return (FALSE); +} + +void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len) +{ +#ifdef NP_DEBUG + printf ("SERVER: Sending freeze file to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); +#endif + + sprintf (NetPlay.ActionMsg, "SERVER: Sending freeze-file to player %d...", c + 1); + S9xNPSetAction (NetPlay.ActionMsg, TRUE); + uint8 header [7 + 4]; + uint8 *ptr = header; + + *ptr++ = NP_SERV_MAGIC; + *ptr++ = NPServer.Clients [c].SendSequenceNum++; + *ptr++ = NP_SERV_FREEZE_FILE; + WRITE_LONG (ptr, len + 7 + 4); + ptr += 4; + WRITE_LONG (ptr, NPServer.FrameCount); + + if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, 7 + 4) || + !S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) + { + S9xNPShutdownClient (c, TRUE); + } +} + +void S9xNPRecomputePause () +{ + int c; + + for (c = 0; c < NP_MAX_CLIENTS; c++) + { + if (NPServer.Clients [c].SaidHello && + (!NPServer.Clients [c].Ready || NPServer.Clients [c].Paused)) + { +#if defined(NP_DEBUG) && NP_DEBUG == 2 + printf ("SERVER: Paused because of client %d (%d,%d) @%ld\n", c, NPServer.Clients [c].Ready, NPServer.Clients [c].Paused, S9xGetMilliTime () - START); +#endif + NPServer.Paused = TRUE; + return; + } + } +#if defined(NP_DEBUG) && NP_DEBUG == 2 + printf ("SERVER: not paused @%ld\n", S9xGetMilliTime () - START); +#endif + NPServer.Paused = FALSE; +} + +void S9xNPNoClientReady (int start_index) +{ + int c; + + for (c = start_index; c < NP_MAX_CLIENTS; c++) + NPServer.Clients [c].Ready = FALSE; + S9xNPRecomputePause (); +} + +void S9xNPSendROMLoadRequest (const char *filename) +{ + S9xNPNoClientReady (); + + int len = 7 + strlen (filename) + 1; + uint8 *data = new uint8 [len]; + uint8 *ptr = data; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = 0; + *ptr++ = NP_SERV_LOAD_ROM; + WRITE_LONG (ptr, len); + ptr += 4; + strcpy ((char *) ptr, filename); + + for (int i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].SaidHello) + { +#ifdef NP_DEBUG + printf ("SERVER: Sending load ROM requesting to player %d @%ld\n", i + 1, S9xGetMilliTime () - START); +#endif + sprintf (NetPlay.WarningMsg, "SERVER: sending ROM load request to player %d...", i + 1); + S9xNPSetAction (NetPlay.WarningMsg, TRUE); + data [1] = NPServer.Clients [i].SendSequenceNum++; + if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) + { + S9xNPShutdownClient (i, TRUE); + } + } + } + delete data; +} + +void S9xNPSendSRAMToAllClients () +{ + int i; + + for (i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) + { + if (NPServer.Clients [i].SaidHello) + S9xNPSendSRAMToClient (i); + } +} + +void S9xNPSendSRAMToClient (int c) +{ +#ifdef NP_DEBUG + printf ("SERVER: Sending S-RAM data to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); +#endif + uint8 sram [7]; + int SRAMSize = Memory.SRAMSize ? + (1 << (Memory.SRAMSize + 3)) * 128 : 0; + if (SRAMSize > 0x10000) + SRAMSize = 0x10000; + int len = 7 + SRAMSize; + + sprintf (NetPlay.ActionMsg, "SERVER: Sending S-RAM to player %d...", c + 1); + S9xNPSetAction (NetPlay.ActionMsg, TRUE); + + uint8 *ptr = sram; + *ptr++ = NP_SERV_MAGIC; + *ptr++ = NPServer.Clients [c].SendSequenceNum++; + *ptr++ = NP_SERV_SRAM_DATA; + WRITE_LONG (ptr, len); + if (!S9xNPSSendData (NPServer.Clients [c].Socket, + sram, sizeof (sram)) || + (len > 7 && + !S9xNPSSendData (NPServer.Clients [c].Socket, + ::SRAM, len - 7))) + { + S9xNPShutdownClient (c, TRUE); + } +} + +void S9xNPSendFreezeFileToAllClients (const char *filename) +{ + uint8 *data; + uint32 len; + + if (NPServer.NumClients > NP_ONE_CLIENT && S9xNPLoadFreezeFile (filename, data, len)) + { + S9xNPNoClientReady (); + + for (int c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) + { + if (NPServer.Clients [c].SaidHello) + S9xNPSendFreezeFile (c, data, len); + } + delete data; + } +} + +void S9xNPServerAddTask (uint32 task, void *data) +{ + NPServer.TaskQueue [NPServer.TaskTail].Task = task; + NPServer.TaskQueue [NPServer.TaskTail].Data = data; + + NPServer.TaskTail = (NPServer.TaskTail + 1) % NP_MAX_TASKS; +} + +void S9xNPReset () +{ + S9xNPNoClientReady (0); + S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); +} + +void S9xNPWaitForEmulationToComplete () +{ +#ifdef NP_DEBUG + printf ("SERVER: WaitForEmulationToComplete start @%ld\n", S9xGetMilliTime () - START); +#endif + + while (!NetPlay.PendingWait4Sync && NetPlay.Connected && + !Settings.ForcedPause && !Settings.StopEmulation && + !Settings.Paused) + { +#ifdef __WIN32__ + Sleep (40); +#endif + } +#ifdef NP_DEBUG + printf ("SERVER: WaitForEmulationToComplete end @%ld\n", S9xGetMilliTime () - START); +#endif +} + +void S9xNPServerQueueSyncAll () +{ + if (Settings.NetPlay && Settings.NetPlayServer && + NPServer.NumClients > NP_ONE_CLIENT) + { + S9xNPNoClientReady (); + S9xNPDiscardHeartbeats (); + S9xNPServerAddTask (NP_SERVER_SYNC_ALL, 0); + } +} + +void S9xNPServerQueueSendingROMImage () +{ + if (Settings.NetPlay && Settings.NetPlayServer && + NPServer.NumClients > NP_ONE_CLIENT) + { + S9xNPNoClientReady (); + S9xNPDiscardHeartbeats (); + S9xNPServerAddTask (NP_SERVER_SEND_ROM_IMAGE, 0); + } +} + +void S9xNPServerQueueSendingFreezeFile (const char *filename) +{ + if (Settings.NetPlay && Settings.NetPlayServer && + NPServer.NumClients > NP_ONE_CLIENT) + { + S9xNPNoClientReady (); + S9xNPDiscardHeartbeats (); + S9xNPServerAddTask (NP_SERVER_SEND_FREEZE_FILE_ALL, + (void *) strdup (filename)); + } +} + +void S9xNPServerQueueSendingLoadROMRequest (const char *filename) +{ + if (Settings.NetPlay && Settings.NetPlayServer && + NPServer.NumClients > NP_ONE_CLIENT) + { + S9xNPNoClientReady (); + S9xNPDiscardHeartbeats (); + S9xNPServerAddTask (NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL, + (void *) strdup (filename)); + } +} + +#ifndef __WIN32__ +uint32 S9xGetMilliTime () +{ + static bool8 first = TRUE; + static long start_sec; + struct timeval tv; + + gettimeofday (&tv, NULL); + if (first) + { + start_sec = tv.tv_sec; + first = FALSE; + } + return ((uint32) ((tv.tv_sec - start_sec) * 1000 + tv.tv_usec / 1000)); +} +#endif +#endif + diff --git a/source/snes9x/unused/snaporig.cpp b/source/snes9x/unused/snaporig.cpp new file mode 100644 index 0000000..fd6c126 --- /dev/null +++ b/source/snes9x/unused/snaporig.cpp @@ -0,0 +1,517 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include + +#if defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP) +#include +#include +#include +#endif + +#include "snapshot.h" +#include "snaporig.h" +#include "memmap.h" +#include "snes9x.h" +#include "65c816.h" +#include "ppu.h" +#include "cpuexec.h" +#include "display.h" +#include "apu.h" +#include "soundux.h" + +#undef TransferBytes +#undef IndirectAddress + +struct SOrigPPU OrigPPU; +struct SOrigDMA OrigDMA [8]; +struct SOrigRegisters OrigRegisters; +struct SOrigCPUState OrigCPU; +struct SOrigAPU OrigAPU; +SOrigSoundData OrigSoundData; +struct SOrigAPURegisters OrigAPURegisters; +char ROMFilename [1025]; + +static int ReadOrigSnapshot (STREAM); + +bool8 S9xLoadOrigSnapshot (const char *filename) +{ + STREAM snapshot = NULL; + if (S9xOpenSnapshotFile (filename, TRUE, &snapshot)) + { + int result; + if ((result = ReadOrigSnapshot (snapshot)) != SUCCESS) + { + S9xCloseSnapshotFile (snapshot); + return (FALSE); + } + S9xCloseSnapshotFile (snapshot); + return (TRUE); + } + return (FALSE); +} + +static int ReadBlock (const char *key, void *block, int max_len, STREAM snap) +{ + char buffer [20]; + int len = 0; + int rem = 0; + + if (READ_STREAM (buffer, 11, snap) != 11 || + strncmp (buffer, key, 4) != 0 || + (len = atoi (&buffer [4])) == 0) + return (WRONG_FORMAT); + + if (len > max_len) + { + rem = len - max_len; + len = max_len; + } + if (READ_STREAM (block, len, snap) != len) + return (WRONG_FORMAT); + + if (rem) + { + char *junk = new char [rem]; + READ_STREAM (junk, rem, snap); + delete[] junk; + } + + return (SUCCESS); +} + +static int ReadOrigSnapshot (STREAM snap) +{ + char buffer [_MAX_PATH]; + char rom_filename [_MAX_PATH]; + int result; + int i; + int j; + + int version; + int len = strlen (ORIG_SNAPSHOT_MAGIC) + 1 + 4 + 1; + if (READ_STREAM (buffer, len, snap) != len) + return (WRONG_FORMAT); + if (strncmp (buffer, ORIG_SNAPSHOT_MAGIC, strlen (ORIG_SNAPSHOT_MAGIC)) != 0) + return (WRONG_FORMAT); + if ((version = atoi (&buffer [strlen (SNAPSHOT_MAGIC) + 1])) > ORIG_SNAPSHOT_VERSION) + return (WRONG_VERSION); + + if ((result = ReadBlock ("NAM:", rom_filename, _MAX_PATH, snap)) != SUCCESS) + return (result); + + if ((result = ReadBlock ("HiR:", buffer, 0x41, snap)) != SUCCESS) + return (result); + + if (strcasecmp (rom_filename, Memory.ROMFilename) != 0 && + strcasecmp (S9xBasename (rom_filename), S9xBasename (Memory.ROMFilename)) != 0) + { + S9xMessage (S9X_WARNING, S9X_FREEZE_ROM_NAME, + "Current loaded ROM image doesn't match that required by freeze-game file."); + } + + S9xReset (); + S9xSetSoundMute (TRUE); + if ((result = ReadBlock ("CPU:", &OrigCPU, sizeof (OrigCPU), snap)) != SUCCESS) + return (result); + OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; + Memory.FixROMSpeed (); + if (version == 3) + { + OrigCPU.Cycles = OrigCPU.Cycles_old; + OrigCPU.NextEvent = OrigCPU.NextEvent_old; + OrigCPU.V_Counter = OrigCPU.V_Counter_old; + OrigCPU.MemSpeed = OrigCPU.MemSpeed_old; + OrigCPU.MemSpeedx2 = OrigCPU.MemSpeedx2_old; + OrigCPU.FastROMSpeed = OrigCPU.FastROMSpeed_old; + } + CPU.Flags = OrigCPU.Flags; + CPU.BranchSkip = OrigCPU.BranchSkip; + CPU.NMIActive = OrigCPU.NMIActive; + CPU.IRQActive = OrigCPU.IRQActive; + CPU.WaitingForInterrupt = OrigCPU.WaitingForInterrupt; + CPU.WhichEvent = OrigCPU.WhichEvent; + CPU.Cycles = OrigCPU.Cycles; + CPU.NextEvent = OrigCPU.NextEvent; + CPU.V_Counter = OrigCPU.V_Counter; + CPU.MemSpeed = OrigCPU.MemSpeed; + CPU.MemSpeedx2 = OrigCPU.MemSpeedx2; + CPU.FastROMSpeed = OrigCPU.FastROMSpeed; + + if ((result = ReadBlock ("REG:", &OrigRegisters, sizeof (OrigRegisters), snap)) != SUCCESS) + return (result); + + Registers = *(struct SRegisters *) &OrigRegisters; + + if ((result = ReadBlock ("PPU:", &OrigPPU, sizeof (OrigPPU), snap)) != SUCCESS) + return (result); + + if (version == 2) + { + OrigPPU.OBJNameSelect = OrigPPU.OBJNameSelect_old << 13; + OrigPPU.OBJNameBase <<= 1; + OrigPPU.OBJNameSelect <<= 13; + } + PPU.BGMode = OrigPPU.BGMode; + PPU.BG3Priority = OrigPPU.BG3Priority; + PPU.Brightness = OrigPPU.Brightness; + + PPU.VMA.High = OrigPPU.VMA.High; + PPU.VMA.Increment = OrigPPU.VMA.Increment; + PPU.VMA.Address = OrigPPU.VMA.Address; + PPU.VMA.Mask1 = OrigPPU.VMA.Mask1; + PPU.VMA.FullGraphicCount = OrigPPU.VMA.FullGraphicCount; + PPU.VMA.Shift = OrigPPU.VMA.Shift; + + for (i = 0; i < 4; i++) + { + PPU.BG[i].SCBase = OrigPPU.BG[i].SCBase; + PPU.BG[i].VOffset = OrigPPU.BG[i].VOffset; + PPU.BG[i].HOffset = OrigPPU.BG[i].HOffset; + PPU.BG[i].BGSize = OrigPPU.BG[i].BGSize; + PPU.BG[i].NameBase = OrigPPU.BG[i].NameBase; + PPU.BG[i].SCSize = OrigPPU.BG[i].SCSize; + } + + PPU.CGFLIP = OrigPPU.CGFLIP; + for (i = 0; i < 256; i++) + PPU.CGDATA [i] = OrigPPU.CGDATA [i]; + PPU.FirstSprite = OrigPPU.FirstSprite; + for (i = 0; i < 128; i++) + { + PPU.OBJ[i].HPos = OrigPPU.OBJ [i].HPos; + PPU.OBJ[i].VPos = OrigPPU.OBJ [i].VPos; + PPU.OBJ[i].Name = OrigPPU.OBJ [i].Name; + PPU.OBJ[i].VFlip = OrigPPU.OBJ [i].VFlip; + PPU.OBJ[i].HFlip = OrigPPU.OBJ [i].HFlip; + PPU.OBJ[i].Priority = OrigPPU.OBJ [i].Priority; + PPU.OBJ[i].Palette = OrigPPU.OBJ [i].Palette; + PPU.OBJ[i].Size = OrigPPU.OBJ [i].Size; + } + PPU.OAMPriorityRotation = OrigPPU.OAMPriorityRotation; + PPU.OAMAddr = OrigPPU.OAMAddr; + + PPU.OAMFlip = OrigPPU.OAMFlip; + PPU.OAMTileAddress = OrigPPU.OAMTileAddress; + PPU.IRQVBeamPos = OrigPPU.IRQVBeamPos; + PPU.IRQHBeamPos = OrigPPU.IRQHBeamPos; + PPU.VBeamPosLatched = OrigPPU.VBeamPosLatched; + PPU.HBeamPosLatched = OrigPPU.HBeamPosLatched; + + PPU.HBeamFlip = OrigPPU.HBeamFlip; + PPU.VBeamFlip = OrigPPU.VBeamFlip; + PPU.HVBeamCounterLatched = OrigPPU.HVBeamCounterLatched; + + PPU.MatrixA = OrigPPU.MatrixA; + PPU.MatrixB = OrigPPU.MatrixB; + PPU.MatrixC = OrigPPU.MatrixC; + PPU.MatrixD = OrigPPU.MatrixD; + PPU.CentreX = OrigPPU.CentreX; + PPU.CentreY = OrigPPU.CentreY; + + PPU.CGADD = OrigPPU.CGADD; + PPU.FixedColourRed = OrigPPU.FixedColourRed; + PPU.FixedColourGreen = OrigPPU.FixedColourGreen; + PPU.FixedColourBlue = OrigPPU.FixedColourBlue; + PPU.SavedOAMAddr = OrigPPU.SavedOAMAddr; + PPU.ScreenHeight = OrigPPU.ScreenHeight; + PPU.WRAM = OrigPPU.WRAM; + PPU.ForcedBlanking = OrigPPU.ForcedBlanking; + PPU.OBJNameSelect = OrigPPU.OBJNameSelect; + PPU.OBJSizeSelect = OrigPPU.OBJSizeSelect; + PPU.OBJNameBase = OrigPPU.OBJNameBase; + PPU.OAMReadFlip = OrigPPU.OAMReadFlip; + memmove (PPU.OAMData, OrigPPU.OAMData, sizeof (PPU.OAMData)); + PPU.VTimerEnabled = OrigPPU.VTimerEnabled; + PPU.HTimerEnabled = OrigPPU.HTimerEnabled; + PPU.HTimerPosition = OrigPPU.HTimerPosition; + PPU.Mosaic = OrigPPU.Mosaic; + memmove (PPU.BGMosaic, OrigPPU.BGMosaic, sizeof (PPU.BGMosaic)); + PPU.Mode7HFlip = OrigPPU.Mode7HFlip; + PPU.Mode7VFlip = OrigPPU.Mode7VFlip; + PPU.Mode7Repeat = OrigPPU.Mode7Repeat; + PPU.Window1Left = OrigPPU.Window1Left; + PPU.Window1Right = OrigPPU.Window1Right; + PPU.Window2Left = OrigPPU.Window2Left; + PPU.Window2Right = OrigPPU.Window2Right; + for (i = 0; i < 6; i++) + { + PPU.ClipWindowOverlapLogic [i] = OrigPPU.ClipWindowOverlapLogic [i]; + PPU.ClipWindow1Enable [i] = OrigPPU.ClipWindow1Enable [i]; + PPU.ClipWindow2Enable [i] = OrigPPU.ClipWindow2Enable [i]; + PPU.ClipWindow1Inside [i] = OrigPPU.ClipWindow1Inside [i]; + PPU.ClipWindow2Inside [i] = OrigPPU.ClipWindow2Inside [i]; + } + PPU.CGFLIPRead = OrigPPU.CGFLIPRead; + PPU.Need16x8Mulitply = OrigPPU.Need16x8Mulitply; + + IPPU.ColorsChanged = TRUE; + IPPU.OBJChanged = TRUE; + S9xFixColourBrightness (); + IPPU.RenderThisFrame = FALSE; + + if ((result = ReadBlock ("DMA:", OrigDMA, sizeof (OrigDMA), snap)) != SUCCESS) + return (result); + + for (i = 0; i < 8; i++) + { + DMA[i].TransferDirection = OrigDMA[i].TransferDirection; + DMA[i].AAddressFixed = OrigDMA[i].AAddressFixed; + DMA[i].AAddressDecrement = OrigDMA[i].AAddressDecrement; + DMA[i].TransferMode = OrigDMA[i].TransferMode; + DMA[i].ABank = OrigDMA[i].ABank; + DMA[i].AAddress = OrigDMA[i].AAddress; + DMA[i].Address = OrigDMA[i].Address; + DMA[i].BAddress = OrigDMA[i].BAddress; + DMA[i].HDMAIndirectAddressing = OrigDMA[i].HDMAIndirectAddressing; + DMA[i].DMACount_Or_HDMAIndirectAddress = OrigDMA[i].IndirectAddress; + DMA[i].IndirectBank = OrigDMA[i].IndirectBank; + DMA[i].Repeat = OrigDMA[i].Repeat; + DMA[i].LineCount = OrigDMA[i].LineCount; + DMA[i].DoTransfer = OrigDMA[i].FirstLine; + } + + if ((result = ReadBlock ("VRA:", Memory.VRAM, 0x10000, snap)) != SUCCESS) + return (result); + if ((result = ReadBlock ("RAM:", Memory.RAM, 0x20000, snap)) != SUCCESS) + return (result); + if ((result = ReadBlock ("SRA:", ::SRAM, 0x10000, snap)) != SUCCESS) + return (result); + if ((result = ReadBlock ("FIL:", Memory.FillRAM, 0x8000, snap)) != SUCCESS) + return (result); + if (ReadBlock ("APU:", &OrigAPU, sizeof (OrigAPU), snap) == SUCCESS) + { + APU = *(struct SAPU *) &OrigAPU; + + if ((result = ReadBlock ("ARE:", &OrigAPURegisters, + sizeof (OrigAPURegisters), snap)) != SUCCESS) + return (result); + APURegisters = *(struct SAPURegisters *) &OrigAPURegisters; + if ((result = ReadBlock ("ARA:", IAPU.RAM, 0x10000, snap)) != SUCCESS) + return (result); + if ((result = ReadBlock ("SOU:", &OrigSoundData, + sizeof (SOrigSoundData), snap)) != SUCCESS) + return (result); + + SoundData.master_volume_left = OrigSoundData.master_volume_left; + SoundData.master_volume_right = OrigSoundData.master_volume_right; + SoundData.echo_volume_left = OrigSoundData.echo_volume_left; + SoundData.echo_volume_right = OrigSoundData.echo_volume_right; + SoundData.echo_enable = OrigSoundData.echo_enable; + SoundData.echo_feedback = OrigSoundData.echo_feedback; + SoundData.echo_ptr = OrigSoundData.echo_ptr; + SoundData.echo_buffer_size = OrigSoundData.echo_buffer_size; + SoundData.echo_write_enabled = OrigSoundData.echo_write_enabled; + SoundData.echo_channel_enable = OrigSoundData.echo_channel_enable; + SoundData.pitch_mod = OrigSoundData.pitch_mod; + + for (i = 0; i < 3; i++) + SoundData.dummy [i] = OrigSoundData.dummy [i]; + for (i = 0; i < NUM_CHANNELS; i++) + { + SoundData.channels [i].state = OrigSoundData.channels [i].state; + SoundData.channels [i].type = OrigSoundData.channels [i].type; + SoundData.channels [i].volume_left = OrigSoundData.channels [i].volume_left; + SoundData.channels [i].volume_right = OrigSoundData.channels [i].volume_right; + SoundData.channels [i].hertz = OrigSoundData.channels [i].frequency; + SoundData.channels [i].count = OrigSoundData.channels [i].count; + SoundData.channels [i].loop = OrigSoundData.channels [i].loop; + SoundData.channels [i].envx = OrigSoundData.channels [i].envx; + SoundData.channels [i].left_vol_level = OrigSoundData.channels [i].left_vol_level; + SoundData.channels [i].right_vol_level = OrigSoundData.channels [i].right_vol_level; + SoundData.channels [i].envx_target = OrigSoundData.channels [i].envx_target; + SoundData.channels [i].env_error = OrigSoundData.channels [i].env_error; + SoundData.channels [i].erate = OrigSoundData.channels [i].erate; + SoundData.channels [i].direction = OrigSoundData.channels [i].direction; + SoundData.channels [i].attack_rate = OrigSoundData.channels [i].attack_rate; + SoundData.channels [i].decay_rate = OrigSoundData.channels [i].decay_rate; + SoundData.channels [i].sustain_rate = OrigSoundData.channels [i].sustain_rate; + SoundData.channels [i].release_rate = OrigSoundData.channels [i].release_rate; + SoundData.channels [i].sustain_level = OrigSoundData.channels [i].sustain_level; + SoundData.channels [i].sample = OrigSoundData.channels [i].sample; + for (j = 0; j < 16; j++) + SoundData.channels [i].decoded [j] = OrigSoundData.channels [i].decoded [j]; + + for (j = 0; j < 2; j++) + SoundData.channels [i].previous [j] = OrigSoundData.channels [i].previous [j]; + + SoundData.channels [i].sample_number = OrigSoundData.channels [i].sample_number; + SoundData.channels [i].last_block = OrigSoundData.channels [i].last_block; + SoundData.channels [i].needs_decode = OrigSoundData.channels [i].needs_decode; + SoundData.channels [i].block_pointer = OrigSoundData.channels [i].block_pointer; + SoundData.channels [i].sample_pointer = OrigSoundData.channels [i].sample_pointer; + SoundData.channels [i].mode = OrigSoundData.channels [i].mode; + } + + S9xSetSoundMute (FALSE); + IAPU.PC = IAPU.RAM + APURegisters.PC; + S9xAPUUnpackStatus (); + if (APUCheckDirectPage ()) + IAPU.DirectPage = IAPU.RAM + 0x100; + else + IAPU.DirectPage = IAPU.RAM; + Settings.APUEnabled = TRUE; + IAPU.APUExecuting = TRUE; + } + else + { + Settings.APUEnabled = FALSE; + IAPU.APUExecuting = FALSE; + S9xSetSoundMute (TRUE); + } + S9xFixSoundAfterSnapshotLoad (1); + ICPU.ShiftedPB = Registers.PB << 16; + ICPU.ShiftedDB = Registers.DB << 16; + S9xSetPCBase (Registers.PBPC); + S9xUnpackStatus (); + S9xFixCycles (); + S9xReschedule (); + + return (SUCCESS); +} + diff --git a/source/snes9x/unused/snaporig.h b/source/snes9x/unused/snaporig.h new file mode 100644 index 0000000..c75147b --- /dev/null +++ b/source/snes9x/unused/snaporig.h @@ -0,0 +1,433 @@ +/********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 Brad Jorsch (anomie@users.sourceforge.net), + funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com), + Nach (n-a-c-h@users.sourceforge.net), and + zones (kasumitokoduck@yahoo.com) + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001-2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight, + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x filter + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Specific ports contains the works of other authors. See headers in + individual files. + + Snes9x homepage: http://www.snes9x.com + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. +**********************************************************************************/ + +#ifndef _SNAPORIG_H_ +#define _SNAPORIG_H_ + +#define ORIG_SNAPSHOT_MAGIC "#!snes96" +#define ORIG_SNAPSHOT_VERSION 4 + +EXTERN_C bool8 S9xLoadOrigSnapshot (const char *filename); + +struct SOrigCPUState{ + uint32 Flags; + short Cycles_old; + short NextEvent_old; + uint8 CurrentFrame; + uint8 FastROMSpeed_old_old; + uint16 V_Counter_old; + bool8 BranchSkip; + bool8 NMIActive; + bool8 IRQActive; + bool8 WaitingForInterrupt; + bool8 InDMA; + uint8 WhichEvent; + uint8 *PC; + uint8 *PCBase; + uint16 MemSpeed_old; + uint16 MemSpeedx2_old; + uint16 FastROMSpeed_old; + bool8 FastDP; + uint8 *PCAtOpcodeStart; + uint8 *WaitAddress; + uint32 WaitCounter; + int32 Cycles; + int32 NextEvent; + int32 V_Counter; + int32 MemSpeed; + int32 MemSpeedx2; + int32 FastROMSpeed; +}; + +struct SOrigAPU +{ + uint32 Cycles; + bool8 ShowROM; + uint8 Flags; + uint8 KeyedChannels; + uint8 OutPorts [4]; + uint8 DSP [0x80]; + uint8 ExtraRAM [64]; + uint16 Timer [3]; + uint16 TimerTarget [3]; + bool8 TimerEnabled [3]; + bool8 TimerValueWritten [3]; +}; + +typedef union +{ +#ifdef LSB_FIRST + struct { uint8 A, Y; } B; +#else + struct { uint8 Y, A; } B; +#endif + uint16 W; +} OrigYAndA; + +struct SOrigAPURegisters{ + uint8 P; + OrigYAndA YA; + uint8 X; + uint8 S; + uint16 PC; +}; + +#define ORIG_MAX_BUFFER_SIZE (1024 * 4) +#define NUM_CHANNELS 8 + +typedef struct { + int32 state; + int32 type; + short volume_left; + short volume_right; + uint32 frequency; + uint32 count; + signed short wave [ORIG_MAX_BUFFER_SIZE]; + bool8 loop; + int32 envx; + short left_vol_level; + short right_vol_level; + short envx_target; + uint32 env_error; + uint32 erate; + int32 direction; + uint32 attack_rate; + uint32 decay_rate; + uint32 sustain_rate; + uint32 release_rate; + uint32 sustain_level; + signed short sample; + signed short decoded [16]; + signed short previous [2]; + uint16 sample_number; + bool8 last_block; + bool8 needs_decode; + uint32 block_pointer; + uint32 sample_pointer; + int32 *echo_buf_ptr; + int32 mode; + uint32 dummy [8]; +} OrigChannel; + +typedef struct +{ + short master_volume_left; + short master_volume_right; + short echo_volume_left; + short echo_volume_right; + int32 echo_enable; + int32 echo_feedback; + int32 echo_ptr; + int32 echo_buffer_size; + int32 echo_write_enabled; + int32 echo_channel_enable; + int32 pitch_mod; + // Just incase they are needed in the future, for snapshot compatibility. + uint32 dummy [3]; + OrigChannel channels [NUM_CHANNELS]; +} SOrigSoundData; + +struct SOrigOBJ +{ + short HPos; + uint16 VPos; + uint16 Name; + uint8 VFlip; + uint8 HFlip; + uint8 Priority; + uint8 Palette; + uint8 Size; + uint8 Prev; + uint8 Next; +}; + +struct SOrigPPU { + uint8 BGMode; + uint8 BG3Priority; + uint8 Brightness; + + struct { + bool8 High; + uint8 Increment; + uint16 Address; + uint16 Mask1; + uint16 FullGraphicCount; + uint16 Shift; + } VMA; + + struct { + uint8 TileSize; + uint16 TileAddress; + uint8 Width; + uint8 Height; + uint16 SCBase; + uint16 VOffset; + uint16 HOffset; + bool8 ThroughMain; + bool8 ThroughSub; + uint8 BGSize; + uint16 NameBase; + uint16 SCSize; + bool8 Addition; + } BG [4]; + + bool8 CGFLIP; + uint16 CGDATA [256]; + uint8 FirstSprite; + uint8 LastSprite; + struct SOrigOBJ OBJ [129]; + uint8 OAMPriorityRotation; + uint16 OAMAddr; + + uint8 OAMFlip; + uint16 OAMTileAddress; + uint16 IRQVBeamPos; + uint16 IRQHBeamPos; + uint16 VBeamPosLatched; + uint16 HBeamPosLatched; + + uint8 HBeamFlip; + uint8 VBeamFlip; + uint8 HVBeamCounterLatched; + + short MatrixA; + short MatrixB; + short MatrixC; + short MatrixD; + short CentreX; + short CentreY; + uint8 Joypad1ButtonReadPos; + uint8 Joypad2ButtonReadPos; + + uint8 CGADD; + uint8 FixedColourRed; + uint8 FixedColourGreen; + uint8 FixedColourBlue; + uint16 SavedOAMAddr; + uint16 ScreenHeight; + uint32 WRAM; + uint8 BG_Forced; + bool8 ForcedBlanking; + bool8 OBJThroughMain; + bool8 OBJThroughSub; + uint8 OBJSizeSelect; + uint8 OBJNameSelect_old; + uint16 OBJNameBase; + bool8 OBJAddition; + uint8 OAMReadFlip; + uint8 OAMData [512 + 32]; + bool8 VTimerEnabled; + bool8 HTimerEnabled; + short HTimerPosition; + uint8 Mosaic; + bool8 BGMosaic [4]; + bool8 Mode7HFlip; + bool8 Mode7VFlip; + uint8 Mode7Repeat; + uint8 Window1Left; + uint8 Window1Right; + uint8 Window2Left; + uint8 Window2Right; + uint8 ClipCounts [6]; + uint8 ClipLeftEdges [3][6]; + uint8 ClipRightEdges [3][6]; + uint8 ClipWindowOverlapLogic [6]; + uint8 ClipWindow1Enable [6]; + uint8 ClipWindow2Enable [6]; + bool8 ClipWindow1Inside [6]; + bool8 ClipWindow2Inside [6]; + bool8 RecomputeClipWindows; + uint8 CGFLIPRead; + uint16 OBJNameSelect; + bool8 Need16x8Mulitply; + uint8 Joypad3ButtonReadPos; + uint8 MouseSpeed[2]; +}; + +struct SOrigDMA { + bool8 TransferDirection; + bool8 AAddressFixed; + bool8 AAddressDecrement; + uint8 TransferMode; + + uint8 ABank; + uint16 AAddress; + uint16 Address; + uint8 BAddress; + + // General DMA only: + uint16 TransferBytes; + + // H-DMA only: + bool8 HDMAIndirectAddressing; + uint16 IndirectAddress; + uint8 IndirectBank; + uint8 Repeat; + uint8 LineCount; + uint8 FirstLine; + bool8 JustStarted; +}; + +typedef union +{ +#ifdef LSB_FIRST + struct { uint8 l,h; } B; +#else + struct { uint8 h,l; } B; +#endif + uint16 W; +} OrigPair; + +struct SOrigRegisters{ + uint8 DB; + OrigPair P; + OrigPair A; + OrigPair D; + OrigPair S; + OrigPair X; + OrigPair Y; + PC_t PC; +}; + +#endif +