Commit 8791d241 authored by Donald Haase's avatar Donald Haase
Browse files

Initial commit of Beta 2 source code

parent ace7aae2
USE_CPUASM=1
#USE_CPUASM_MIXTO=1
USE_GL=1
USE_MMU=1
TARGET = snes4all
BACK_KOS_AS=$(KOS_CC_BASE)/bin/$(KOS_CC_PREFIX)-as
KOS_AS = $(KOS_CCPLUS) -ml -m4-single-only -c
OPTFLAGS=-O3 -fomit-frame-pointer -DDREAMCAST -DDATA_PREFIX="/rd/" -ffast-math -g0
#OPTFLAGS=-Os -fomit-frame-pointer -DDREAMCAST -DDATA_PREFIX="/rd/" -ffast-math -g0
#OPTFLAGS+= -falign-functions=32 -falign-labels=32 -falign-loops=32 -falign-jumps=32
OPTFLAGS+= -falign-functions=32 -falign-labels=4 -falign-loops=4 -falign-jumps=4
#OPTFLAGS+= -falign-functions -falign-labels -falign-loops -falign-jumps
DEFS += -DSNES4ALL_MAX_ROM_SIZE=0x600000
#DEFS += -DNORES256
DEFS += -DUSE_RASTER_DIFF
DEFS += -DCPU_SHUTDOWN
DEFS += -DSPC700_SHUTDOWN
DEFS += -DEXECUTE_SUPERFX_PER_LINE
DEFS += -DSPC700_C
DEFS += -DVAR_CYCLES
DEFS += -DSDD1_DECOMP
DEFS += -DUSE_OLD_DSP1
DEFS += -DUSE_NO_WAIT_WHEN_IRQ
DEFS += -DNO_INLINE_SET_GET
#DEFS += -DUSE_MMU_BOUNDARY
#DEFS += -DUSE_MMU_MASK
DEFS += -DUSE_MMU_DIRECT_INDEX
#DEFS += -DUSE_MMU_BASEPOINTER
#DEFS += -DUSE_MEMORY_SPEED
#DEFS += -DUSE_BLOCK_RAM
DEFS += -DUSE_ASM_ALIGN_OPCODES
DEFS += -DUSE_ASM_SMALL
#DEFS += -DUSE_ASM_R5
DEFS += -DUSE_ASM_R12
#DEFS += -DENABLE_ECHO_SOUND
#DEFS += -DENABLE_MASTER_VOLUMEN
#DEFS += -DUSE_SOUND_DESYNC
#DEFS += -DUSE_REAL_SOUND_MUL
#DEFS += -DENABLE_INTERPOLATE_SOUND
DEFS += -DUSE_ALTDECODE=5
#DEFS += -DENABLE_FIX_FREQUENCY
#DEFS += -DUSE_MODE7_INTERPOLATE
DEFS += -DENABLE_GRAPHIC_WINDOWS
DEFS += -DENABLE_HDMA
#DEFS += -DUSE_HDMA_EVENT
#DEFS += -DNEW_COLOUR_BLENDING
#DEFS += -DOLD_COLOUR_BLENDING
#DEFS += -DSNES4ALL_NUM_CHANNELS=6
#DEFS += -DSNES4ALL_STEREO
#DEFS += -DUSE_VIDEOGL_DIRECT_SLOT
#DEFS += -DDIRECT_COLOR_MAP
DEFS += -DTEST_CACHETILE
DEFS += -DTILES_INLINE
DEFS += -DUSE_SETPPU_TABLE
#DEFS += -DUSE_SETPPU_SMALL_TABLE
DEFS += -DUSE_GETPPU_TABLE
DEFS += -DUSE_ASM_GET_SPC
DEFS += -DUSE_ASM_SET_MATRIX
DEFS += -DUSE_ASM_IRQ_INLINE
DEFS += -DUSE_ASM_PREFETCH
DEFS += -DUSE_VIDEOGL_SELECTIVE_CACHE_RESET=4
DEFS += -DVIDEO_GL_MAX_TEX=32768
DEFS += -DVIDEO_GL_RASTER=64
#DEFS += -DUSE_VIDEOGL_EXTEND_TILELIST
#DEFS += -DUSE_VGL_TABLE
#DEFS += -DUSE_VGL_LARGE_TABLE
#DEFS += -DNOSOUND
#DEFS += -DAUTOLOAD="/cd/Aladdin.zip"
#DEFS += -DAUTOLOAD="/cd/smario.zip"
#DEFS += -DAUTOLOAD="/cd/starwars.zip"
#DEFS += -DAUTOLOAD="/cd/turrican.zip"
#DEFS += -DAUTOLOAD="/cd/castlevania.zip"
#DEFS += -DAUTOLOAD="/cd/jamespond.zip"
#DEFS += -DAUTOLOAD="/cd/Parodius.zip"
#DEFS += -DAUTOLOAD="/sd/snes4all/EarthwormJim.zip"
#DEFS += -DAUTOLOAD="/sd/snes4all/KirbySuperstar.zip"
#DEFS += -DAUTOSAVESTATE
#DEFS += -DAUTO_LOADSAVESTATE="jamespond.ssn"
#DEFS += -DAUTO_LOADSAVESTATE="castlevania.ssn"
#DEFS += -DAUTO_LOADSAVESTATE="turrican.ssn"
#DEFS += -DAUTO_LOADSAVESTATE="aladdin.ssn"
#DEFS += -DAUTO_LOADSAVESTATE="smario.ssn"
#DEFS += -DAUTO_LOADSAVESTATE="starwars.ssn"
#DEFS += -DAUTO_EVENTS
#DEFS += -DMAX_AUTO_EVENTS=500
#DEFS += -DSHOW_DMA
#DEFS += -DPROFILER_SNES4ALL
#DEFS += -DDEBUG_FRAMESKIP
#DEFS += -DAUTO_DEBUG_FRAMESKIP=1000
#DEFS += -DDISPLAY_FRAMERATE
#DEFS += -DDEBUG_TILECACHE
#DEFS += -DAUTO_DEBUG_TILECACHE=2000
DEFS += -DREBOOT_DREAMCAST
ifdef USE_GL
DEFS += -DUSE_GL
endif
ifdef USE_CPUASM
DEFS += -DUSE_OPC_ASM
DEFS += -DASMSTRUC_NOP_PATCH
DEFS += -DSA1ADDR_NOP_PATCH
DEFS += -DASMADDR_NOP_PATCH
DEFS += -DUSE_OLD_APUTIMER
#DEFS += -DUSE_OLD_END_REFRESH
#DEFS += -DUSE_OLD_START_REFRESH
#DEFS += -DUSE_OLD_SYNC_SPEED
#DEFS += -DUSE_ALWAYS_APU_SYNC
endif
ifdef USE_CPUASM_MIXTO
DEFS += -DUSE_OPC_ASM_MIXTO
endif
ifdef USE_MMU
KOS_CFLAGS= -Isrc/mmu_handle/kos-patch/kernel/arch/dreamcast/include -O3 -fomit-frame-pointer -ml -m4-single-only -fno-optimize-sibling-calls -I$(KOS_BASE)/include -I$(KOS_BASE)/addons/include -I$(KOS_BASE)/kernel/arch/dreamcast/include -D_arch_dreamcast -D_arch_sub_pristine -Wall -g -fno-builtin -fno-strict-aliasing
KOS_LDFLAGS = -Lsrc/mmu_handle/kos-patch/lib/dreamcast -Lsrc/mmu_handle/kos-patch/addons/lib/dreamcast -ml -m4-single-only -Wl,-Ttext=0x8c010000 -nostartfiles -nostdlib -L$(KOS_BASE)/lib/dreamcast -L$(KOS_BASE)/addons/lib/dreamcast
MORE_CFLAGS = -DUSE_MMU -Isrc/mmu_handle -I$(KOS_BASE)/addons/include/SDL -I$(KOS_BASE)/addons/include $(OPTFLAGS)
else
MORE_CFLAGS = -I$(KOS_BASE)/addons/include/SDL -I$(KOS_BASE)/addons/include $(OPTFLAGS)
endif
MORE_CFLAGS += -Isrc/include -Isrc/unzip -Isrc/menu -Isrc/sh -DMITSHM \
$(DEFS) -DUNZIP_SUPPORT -DZLIB -DHAVE_MKSTEMP \
-DACCEPT_SIZE_T=int
#MORE_CFLAGS += -DNOSOUND
KOS_CFLAGS += $(MORE_CFLAGS)
KOS_CPPFLAGS += $(MORE_CFLAGS)
KOS_AFLAGS = $(MORE_CFLAGS)
all: $(TARGET).bin
include $(KOS_BASE)/Makefile.rules
KOS_CPPFLAGS=-fno-operator-names -fno-exceptions
ifdef USE_CPUASM
ifdef USE_CPUASM_MIXTO
OBJS += \
src/cpuexec.o
endif
OBJS += \
src/sh/cpuexec.o \
src/sh/cpuops.o \
src/sh/cpumem.o
ifdef USE_MMU
OBJS += src/sh/sa1ops.o
else
OBJS += src/sa1cpu.o
endif
else
OBJS += \
src/cpuops.o \
src/cpuexec.o \
src/sa1cpu.o
endif
ifdef USE_MMU
OBJS += src/mmu_handle/mmu_handle.o
endif
OBJS += \
src/globals.o \
src/fxinst.o \
src/c4emu.o \
src/fxemu.o \
src/2xsai.o \
src/apu.o \
src/c4.o \
src/cheats.o \
src/cheats2.o \
src/clip.o \
src/cpu.o \
src/data.o \
src/dma.o \
src/dsp1.o \
src/gfx.o \
src/loadzip.o \
src/memmap.o \
src/netplay.o \
src/obc1.o \
src/ppu.o \
src/sa1.o \
src/screenshot.o \
src/sdd1.o \
src/sdd1emu.o \
src/server.o \
src/seta.o \
src/seta010.o \
src/seta011.o \
src/seta018.o \
src/snaporig.o \
src/snapshot.o \
src/soundux.o \
src/spc700.o \
src/spc7110.o \
src/srtc.o \
src/tile.o \
src/sdl/config.o \
src/sdl/machine.o \
src/sdl/vmu.o \
src/sdl/sdl.o \
src/unzip/explode.o \
src/unzip/unreduce.o \
src/unzip/unshrink.o \
src/unzip/unzip.o \
src/menu/fade.o \
src/menu/menu.o \
src/menu/menu_main.o \
src/menu/menu_save.o \
src/menu/menu_load.o \
romdisk.o
ifdef USE_GL
OBJS += \
src/sdl/videogl.o \
src/tilegl.o
endif
ifdef USE_GL
LIBS= -lSDL_mixer_126 -lSDL_gl_1213 -lkglx -lz_123 -lm
else
LIBS= -lSDL_mixer_126 -lSDL_1213 -lz_123 -lm
endif
clean:
rm -f $(OBJS) $(TARGET).elf $(TARGET).bin romdisk.o romdisk.img example.iso offsets.bin offsets.elf src/offsets.o
$(TARGET).elf: $(OBJS)
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET).elf $(KOS_START) \
$(OBJS) $(OBJEXTRA) $(LIBS) $(KOS_LIBS)
offsets.elf: src/offsets.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o offsets.elf $(KOS_START) \
src/offsets.o $(OBJEXTRA) -lm $(KOS_LIBS)
$(TARGET).bin: $(TARGET).elf
$(KOS_OBJCOPY) -R .stack -O binary $(TARGET).elf $(TARGET).bin
offsets.bin: offsets.elf
$(KOS_OBJCOPY) -R .stack -O binary offsets.elf offsets.bin
romdisk.o: romdisk.img
KOS_AS=$(BACK_KOS_AS) KOS_AFLAGS=-little $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
# bin2odc romdisk.img romdisk.o
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d data -v
example.iso: example
mkisofs -joliet-long -l -o example.iso -graft-points /=example/
run: $(TARGET).bin example.iso
$(KOS_LOADER) $(TARGET).bin -i example.iso
# $(KOS_LOADER) $(TARGET).bin
offsets: offsets.bin
$(KOS_LOADER) offsets.bin > offsets.h
#USE_CPUASM=1
#USE_MMX=1
#USE_ZSNES_FX=1
USE_GL=1
NAME = snes4all
O = o
RM = rm -f
CC = gcc
CXX = g++
AS = c++
STRIP = strip
PROG = $(NAME)
DEFS += -DSNES4ALL_MAX_ROM_SIZE=0x600000
ifdef USE_GL
DEFS += -DUSE_GL
else
#DEFS += -DNORES256
endif
#DEFS += -DPLAYBACK_RATE=22050
DEFS += -DCPU_SHUTDOWN
DEFS += -DSPC700_SHUTDOWN
DEFS += -DEXECUTE_SUPERFX_PER_LINE
DEFS += -DSPC700_C
DEFS += -DVAR_CYCLES
DEFS += -DSDD1_DECOMP
DEFS += -DUSE_NO_WAIT_WHEN_IRQ
DEFS += -DNO_INLINE_SET_GET
#DEFS += -DUSE_MEMORY_SPEED
#DEFS += -DUSE_BLOCK_RAM
#DEFS += -DENABLE_ECHO_SOUND
#DEFS += -DENABLE_MASTER_VOLUMEN
#DEFS += -DUSE_SOUND_DESYNC
#DEFS += -DENABLE_INTERPOLATE_SOUND
#DEFS += -DUSE_ALTDECODE=1
#DEFS += -DENABLE_FIX_FREQUENCY
#DEFS += -DUSE_MODE7_INTERPOLATE
DEFS += -DENABLE_GRAPHIC_WINDOWS
DEFS += -DENABLE_HDMA
#DEFS += -DUSE_HDMA_EVENT
DEFS += -DUSE_OLD_DSP1
#DEFS += -DNEW_COLOUR_BLENDING
#DEFS += -DOLD_COLOUR_BLENDING
#DEFS += -DSNES4ALL_NUM_CHANNELS=6
#DEFS += -DSNES4ALL_STEREO
#DEFS += -DDIRECT_COLOR_MAP
#DEFS += -DTEST_CACHETILE
#DEFS += -DTILES_INLINE
DEFS += -DUSE_RASTER_DIFF
DEFS += -DUSE_SETPPU_TABLE
DEFS += -DUSE_GETPPU_TABLE
#DEFS += -DUSE_VIDEOGL_SELECTIVE_CACHE_RESET=1
DEFS += -DUSE_VIDEOGL_SELECTIVE_CACHE_RESET=4
#DEFS += -DUSE_VIDEOGL_EXTEND_TILELIST
#DEFS += -DUSE_VGL_TABLE
#DEFS += -DUSE_VGL_LARGE_TABLE
#DEFS += -DNOSOUND
#DEFS += -DAUTOLOAD=\"example/Super\ Metroid.zip\"
#DEFS += -DAUTOLOAD=\"example/Aladdin.zip\"
#DEFS += -DAUTOLOAD=\"example/castlevania.zip\"
#DEFS += -DAUTOLOAD=\"example/smario.zip\"
#DEFS += -DAUTOLOAD=\"example/fzero.zip\"
#DEFS += -DAUTOLOAD=\"example/rrunner.zip\"
#DEFS += -DAUTOLOAD=\"example/supergoal.zip\"
#DEFS += -DAUTOLOAD=\"example/dkcountry.zip\"
#DEFS += -DAUTOLOAD=\"example/pacintime.zip\"
#DEFS += -DAUTOLOAD=\"example/starwars.zip\"
#DEFS += -DAUTOLOAD=\"example/jurassic.zip\"
#DEFS += -DAUTOLOAD=\"example/jimpower.zip\"
#DEFS += -DAUTOLOAD=\"example/turrican.zip\"
#DEFS += -DAUTOLOAD=\"example/sfighter.zip\"
#DEFS += -DAUTOLOAD=\"example/rtype.zip\"
#DEFS += -DAUTO_LOADSAVESTATE=\"castlevania.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"rtype.1ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"sfighter.2ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"jimpower.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"turrican.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"pacintime.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"jurassic.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"supergoal.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"smario.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"fzero.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"smario.1ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"prueba.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"rrunner.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"Aladdin.ssn\"
#DEFS += -DAUTO_LOADSAVESTATE=\"Super\ Metroid.1ssn\"
#DEFS += -DAUTO_EVENTS
#DEFS += -DMAX_AUTO_EVENTS=50
#DEFS += -DMAX_AUTO_EVENTS=500
#DEFS += -DPROFILER_SNES4ALL
#DEFS += -DDEBUG_FRAMESKIP
#DEFS += -DAUTO_DEBUG_FRAMESKIP=1000
#DEFS += -DDISPLAY_FRAMERATE
#DEFS += -DDEBUG_TILECACHE
#DEFS += -DAUTO_DEBUG_TILECACHE=2000
DEFS += -DLINUX -DUNIX
ifdef USE_CPUASM
DEFS += -DUSE_X86_ASM
endif
ifdef USE_MMX
DEFS += -DMMX
endif
ifdef USE_ZSNES_FX
DEFS += -DZSNES_FX
endif
DEFAULT_CFLAGS = `sdl-config --cflags`
LDFLAGS = `sdl-config --libs` -lSDL_mixer -lz
ifdef USE_GL
LDFLAGS += -lGL
endif
MORE_CFLAGS = -O3 -DDATA_PREFIX=\"data/\"
MORE_CFLAGS += -Isrc/include -Isrc/unzip -Isrc/menu -Isrc/i386 -DMITSHM \
$(DEFS) -DUNZIP_SUPPORT -DZLIB -DHAVE_MKSTEMP -DHAVE_STRINGS_H \
-DHAVE_SYS_IOCTL_H '-DACCEPT_SIZE_T=int'
#MORE_CFLAGS += -DNOSOUND
CFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS)
CPPFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS)
OBJS = \
src/2xsai.o \
src/apu.o \
src/c4.o \
src/cheats.o \
src/cheats2.o \
src/clip.o \
src/cpu.o \
src/data.o \
src/dma.o \
src/dsp1.o \
src/gfx.o \
src/globals.o \
src/loadzip.o \
src/memmap.o \
src/netplay.o \
src/obc1.o \
src/ppu.o \
src/sa1.o \
src/screenshot.o \
src/sdd1.o \
src/sdd1emu.o \
src/server.o \
src/seta.o \
src/seta010.o \
src/seta011.o \
src/seta018.o \
src/snaporig.o \
src/snapshot.o \
src/soundux.o \
src/spc700.o \
src/spc7110.o \
src/srtc.o \
src/tile.o \
src/sdl/config.o \
src/sdl/machine.o \
src/sdl/sdl.o \
src/unzip/explode.o \
src/unzip/unreduce.o \
src/unzip/unshrink.o \
src/unzip/unzip.o \
src/menu/fade.o \
src/menu/menu.o \
src/menu/menu_main.o \
src/menu/menu_save.o \
src/menu/menu_load.o
ifdef USE_GL
OBJS += \
src/sdl/videogl.o \
src/tilegl.o
endif
ifdef USE_CPUASM
OBJS += \
src/i386/cpuexec.o \
src/i386/cpuops.o \
src/i386/sa1ops.o \
src/i386/spc.o
else
OBJS += \
src/cpuexec.o \
src/sa1cpu.o
endif
ifdef USE_MMX
OBJS += \
src/i386/2xsaimmx.o \
src/i386/bilinear.o
endif
ifdef USE_ZSNES_FX
OBJS += \
src/i386/fxemu2.o \
src/i386/fxemu2b.o \
src/i386/fxemu2c.o \
src/i386/fxtable.o \
src/i386/sfxproc.o \
src/i386/zsnes.o \
src/i386/zsnesc4.o \
src/i386/c4.o
else
OBJS += \
src/cpuops.o \
src/fxinst.o \
src/c4emu.o \
src/fxemu.o
endif
$(PROG): $(OBJS)
$(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LDFLAGS)
$(STRIP) $(PROG)
run: $(PROG)
./$(PROG)
clean:
$(RM) $(PROG) $(OBJS)
src/i386/2xsaimmx.o: src/i386/2xsaimmx.asm
nasm -f elf src/i386/2xsaimmx.asm $(DEFS)
src/i386/bilinear.o: src/i386/bilinear.asm
nasm -f elf src/i386/bilinear.asm $(DEFS)
src/i386/c4.o: src/i386/c4.asm
nasm -f elf src/i386/c4.asm $(DEFS)
src/i386/fxemu2.o: src/i386/fxemu2.asm
nasm -f elf src/i386/fxemu2.asm $(DEFS)
src/i386/fxemu2b.o: src/i386/fxemu2b.asm
nasm -f elf src/i386/fxemu2b.asm $(DEFS)
src/i386/fxemu2c.o: src/i386/fxemu2c.asm
nasm -f elf src/i386/fxemu2c.asm $(DEFS)
src/i386/fxtable.o: src/i386/fxtable.asm
nasm -f elf src/i386/fxtable.asm $(DEFS)
src/i386/sfxproc.o: src/i386/sfxproc.asm
nasm -f elf src/i386/sfxproc.asm $(DEFS)
src/i386/spc.o: src/i386/spc.asm
nasm -f elf src/i386/spc.asm $(DEFS)
src/i386/zsnes.o: src/i386/zsnes.asm
nasm -f elf src/i386/zsnes.asm $(DEFS)
src/i386/zsnesc4.o: src/i386/zsnesc4.asm
nasm -f elf src/i386/zsnesc4.asm $(DEFS)
#USE_CPUASM=1
#USE_MMX=1
#USE_ZSNES_FX=1
USE_GL=1
NAME = snes4all
O = o
RM = rm -f
CC = gcc-3
CXX = g++-3
AS = c++-3
STRIP = strip
PROG = $(NAME)
DEFS += -DSNES4ALL_MAX_ROM_SIZE=0x600000
ifdef USE_GL
DEFS += -DUSE_GL
else
#DEFS += -DNORES256
endif
DEFS += -DCPU_SHUTDOWN
DEFS += -DSPC700_SHUTDOWN
DEFS += -DEXECUTE_SUPERFX_PER_LINE
DEFS += -DSPC700_C
DEFS += -DVAR_CYCLES
DEFS += -DSDD1_DECOMP
DEFS += -DUSE_NO_WAIT_WHEN_IRQ
DEFS += -DUSE_OLD_DSP1
#DEFS += -DNO_INLINE_SET_GET
#DEFS += -DENABLE_ECHO_SOUND
#DEFS += -DENABLE_MASTER_VOLUMEN
#DEFS += -DUSE_SOUND_DESYNC
#DEFS += -DENABLE_INTERPOLATE_SOUND
#DEFS += -DUSE_ALTDECODE=1
#DEFS += -DENABLE_FIX_FREQUENCY
#DEFS += -DUSE_MODE7_INTERPOLATE
DEFS += -DENABLE_GRAPHIC_WINDOWS
DEFS += -DENABLE_HDMA
#DEFS += -DUSE_HDMA_EVENT
#DEFS += -DNEW_COLOUR_BLENDING
#DEFS += -DOLD_COLOUR_BLENDING
#DEFS += -DSNES4ALL_NUM_CHANNELS=6
#DEFS += -DSNES4ALL_STEREO
#DEFS += -DDIRECT_COLOR_MAP
#DEFS += -DTEST_CACHETILE
#DEFS += -DTILES_INLINE
DEFS += -DUSE_RASTER_DIFF
DEFS += -DUSE_GETPPU_TABLE
#DEFS += -DNOSOUND
#DEFS += -DAUTOLOAD=\"example/smario.smc\"
#DEFS += -DAUTO_EVENTS
#DEFS += -DMAX_AUTO_EVENTS=1000
#DEFS += -DPROFILER_SNES4ALL
#DEFS += -DDEBUG_FRAMESKIP
#DEFS += -DAUTO_DEBUG_FRAMESKIP=1000
#DEFS += -DDISPLAY_FRAMERATE
#DEFS += -DDEBUG_TILECACHE
#DEFS += -DAUTO_DEBUG_TILECACHE=2000
DEFS += -D__DJGPP__ -D__DJGCC -D_WINDOWS
ifdef USE_CPUASM
DEFS += -DUSE_X86_ASM -DUSE_OPC_ASM
endif
ifdef USE_MMX
DEFS += -DMMX
endif
ifdef USE_ZSNES_FX
DEFS += -DZSNES_FX
endif
DEFAULT_CFLAGS = `sdl-config --cflags`
LDFLAGS = `sdl-config --libs` -lSDL_mixer -lz
MORE_CFLAGS = -O3 -DDATA_PREFIX=\"data/\" -U__WIN32__
MORE_CFLAGS += -Isrc/include -Isrc/unzip -Isrc/menu -Isrc/i386 -DMITSHM \
$(DEFS) -DUNZIP_SUPPORT -DZLIB -DHAVE_MKSTEMP -DHAVE_STRINGS_H \
'-DACCEPT_SIZE_T=int'
CFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS)
CPPFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS)
OBJS = \
src/2xsai.o \
src/memmap.o \
src/apu.o \
src/c4.o \
src/cheats.o \
src/cheats2.o \
src/clip.o \
src/cpu.o \
src/data.o \
src/dma.o \
src/dsp1.o \
src/gfx.o \
src/globals.o \
src/loadzip.o \
src/netplay.o \
src/obc1.o \
src/ppu.o \
src/sa1.o \
src/screenshot.o \
src/sdd1.o \
src/sdd1emu.o \
src/server.o \
src/seta.o \
src/seta010.o \
src/seta011.o \
src/seta018.o \
src/snaporig.o \
src/snapshot.o \
src/soundux.o \
src/spc700.o \
src/spc7110.o \
src/srtc.o \
src/tile.o \
src/sdl/config.o \
src/sdl/machine.o \
src/sdl/sdl.o \
src/unzip/explode.o \
src/unzip/unreduce.o \
src/unzip/unshrink.o \
src/unzip/unzip.o \
src/menu/fade.o \
src/menu/menu.o \
src/menu/menu_main.o \
src/menu/menu_save.o \
src/menu/menu_load.o
ifdef USE_GL
OBJS += \
src/sdl/videogl.o \
src/tilegl.o
endif
ifdef USE_CPUASM
OBJS += \
src/i386/cpuexec.o \
src/i386/cpuops.o \
src/i386/sa1ops.o \
src/i386/spc.o
else
OBJS += \
src/cpuexec.o \
src/sa1cpu.o
endif
ifdef USE_MMX
OBJS += \
src/i386/2xsaimmx.o \
src/i386/bilinear.o
endif
ifdef USE_ZSNES_FX
OBJS += \
src/i386/fxemu2.o \
src/i386/fxemu2b.o \
src/i386/fxemu2c.o \
src/i386/fxtable.o \
src/i386/sfxproc.o \
src/i386/zsnes.o \
src/i386/zsnesc4.o \
src/i386/c4.o
else
OBJS += \
src/cpuops.o \
src/fxinst.o \
src/c4emu.o \
src/fxemu.o
endif
all: $(PROG)
run: $(PROG)
./$(PROG)
clean:
$(RM) $(PROG).exe $(OBJS) stdout.txt stderr.txt
src/i386/2xsaimmx.o: src/i386/2xsaimmx.asm
nasm -f gnuwin32 src/i386/2xsaimmx.asm $(DEFS)
src/i386/bilinear.o: src/i386/bilinear.asm
nasm -f gnuwin32 src/i386/bilinear.asm $(DEFS)
src/i386/c4.o: src/i386/c4.asm
nasm -f gnuwin32 src/i386/c4.asm $(DEFS)
src/i386/fxemu2.o: src/i386/fxemu2.asm
nasm -f gnuwin32 src/i386/fxemu2.asm $(DEFS)
src/i386/fxemu2b.o: src/i386/fxemu2b.asm
nasm -f gnuwin32 src/i386/fxemu2b.asm $(DEFS)
src/i386/fxemu2c.o: src/i386/fxemu2c.asm
nasm -f gnuwin32 src/i386/fxemu2c.asm $(DEFS)
src/i386/fxtable.o: src/i386/fxtable.asm
nasm -f gnuwin32 src/i386/fxtable.asm $(DEFS)
src/i386/sfxproc.o: src/i386/sfxproc.asm
nasm -f gnuwin32 src/i386/sfxproc.asm $(DEFS)
src/i386/spc.o: src/i386/spc.asm
nasm -f gnuwin32 src/i386/spc.asm $(DEFS)
src/i386/zsnes.o: src/i386/zsnes.asm
nasm -f gnuwin32 src/i386/zsnes.asm $(DEFS)
src/i386/zsnesc4.o: src/i386/zsnesc4.asm
nasm -f gnuwin32 src/i386/zsnesc4.asm $(DEFS)
$(PROG): $(OBJS)
ifdef USE_GL
$(CC) -L/usr/lib/mingw -L/usr/local/lib -L/usr/lib/w32api/ -L/usr/X11R6/lib -lglu32 -lopengl32 -o $(PROG) -lmingw32 $(OBJS) -lglu32 -lopengl32 -lSDL_static_1212 -lGL -lpthread -mwindows -mno-cygwin -luser32 -lgdi32 -lwinmm -ldxguid
else
$(CC) -L/usr/lib/mingw -L/usr/local/lib -o $(PROG) -lmingw32 $(OBJS) -lz -lSDL_static_129 -mwindows -mno-cygwin -luser32 -lgdi32 -lwinmm -ldxguid
endif
$(STRIP) $(PROG).exe
# snes4all
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.completext.com/Dreamcast/snes4all.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.completext.com/Dreamcast/snes4all/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
menu_inv_color=0x44,0x22,0x22
menu_win0_color=0x8F,0x5F,0x5F
menu_win1_color=0xCF,0x6F,0x6F
menu_barra0_color=0x45,0x45,0x45
menu_barra1_color=0xff,0xc4,0x5e
How to Port Snes9x to a New Platform
====================================
Version: 1.01
Date: 23-December-1998
(c) Copyright 1998 Gary Henderson (gary@daniver.demon.co.uk)
Introduction
============
This is brief description of the steps involved in porting Snes9x, the Super
Nintendo Entertainment System emulator, to new hardware which is at least
similar to Workstation or PC. It describes what code you have to write and
what functions exist that you can make use of. It also gives some insights as
to how Snes9x actually works, although that will be subject of another
document yet to be written.
Host System Requirements
========================
A C++ compiler, so you can compile the emulator! Snes9x really isn't written
in C++, it just uses the C++ compiler as a 'better C' compiler to get inline
functions and so on. With some modification, it could be converted to be
compiled with an ordinary C compiler. Snes9x isn't very C type safe and
will probably not work on a system who's integers are less than 32-bits wide
without lots of editing.
If the host system uses a CPU that implements the i386 instruction set then
you will also want to use the three assembler CPU cores, although I recently
scrapped the SPC700 assembler code (too many bugs) and replaced it with
compiler generated assembler code that I haven't got around to optimising
yet. The 65c816 and SPC700 code needs to be assembled using the GNU
assembler that comes with gcc and the Super FX code assembled with NASM
v0.97 or higher. gcc is available from lots of sites. NASM is available from
http://www.cryogen.com/Nasm
A fast CPU. SNES emulation is very compute intensive: two, or sometimes three
CPUs to emulate, an 8-channel 16-bit stereo sound digital signal processor
with real-time sample decompression, filter and echo effects, two custom
graphics processor chips that can produce transparency, scaling, rotation
and window effects in 32768 colors, and finally hardware DMA all take their
toll on the host CPU.
Lots of RAM. The SNES itself has 128k work RAM, 64k V-RAM and 64k sound CPU
RAM. If a Super FX game is being emulated, that usually comes with another
64k inside the game pack. Snes9x itself needs 4Mb to load SNES ROM images
into (or 6Mb if I ever figure out the SNES memory map of the 48Mbit ROM
images out there), 256k to cache decompressed sound samples in, 512k to
cache converted SNES tiles in, and another 64k for S-RAM emulation. And
that's not counting a few large lookup tables that the graphics code needs
for speeding up transparency effects plus few other tables used by the ZSNES
Super FX code. It all adds up to 7Mb (ish). Add to that RAM needed to
store the actual emulator code and RAM required by the host operating system
and any other process that is running; that's lots of RAM. Well, it is if
your host system only has a few mega-bytes of RAM available.
An 8-bit, 256 color (one byte per pixel) or deeper display, at least 256x239
pixels in resolution, or 512x478 if you're going to support the SNES'
hi-res. background screen modes. Ideally, a 16-bit, 65536 color screen mode
is required if you want to support transparency at speed, as that is what the
code renders internally. Any other format screen, with transparency enabled,
will require picture format conversion before you can place the rendered
SNES image on to the screen.
Sound output requires spooling 8-bit or 16-bit, mono or stereo digital sound
data to the host computer's sound hardware. The DOS port uses interrupts
from the sound card to know when more sound data is required, most other
ports have to periodically poll the host sound hardware to see if more data
is required; if it is then the SNES sound mixing code provided by Snes9x is
called to fill an area of system memory with ready mixed SNES sound data,
which then can be passed on to the host sound hardware. Sound data is
generated as an array of bytes (uint8) for 8-bit sound or shorts (int16) for
16-bit data. Stereo sound data generates twice as many samples, with each
channel's samples interleaved, first left's then right's.
For the user to be able to control and play SNES games, some form of input
device is required, a joystick or keyboard, for example. The real SNES can
have 2 eight-button digital joy-pads connected to it or 5 joy-pads when an
optional multi-player adaptor was purchased, although most games only require
a single joy-pad. Access to all eight buttons and the direction pad, of
course, are usually required by most games. Snes9x does emulate the
multi-player adaptor hardware, if you were wondering, but its still up to
you to provide the emulation of the individual joy-pads.
The SNES also had a mouse and light gun available as optional extras,
Snes9x can emulate both of these using some form of pointing device,
usually the host system's mouse.
If an accurate, constant SNES play rate is required, then a real-time timer
will be needed that can time intervals of 16.7ms (NTSC frame time) or 20ms
(PAL frame time).
Some SNES game packs contained a small amount of extra RAM and a battery so
ROMs could save a player's progress through a game for games that takes many
hours to play from start to finish. Snes9x simulates this S-RAM by saving
the contents of the area of memory normally occupied by the S-RAM into file
then automatically restoring it again the next time the user plays the same
game. If the hardware you're porting to doesn't have a hard disk available
then you could be in trouble.
Snes9x also implements freeze-game files which can record the state of the
SNES hardware and RAM at a particular point in time and can restore it to
that exact state at a later date - the result is that users can save a game
at any point, not just at save-game or password points provided by the
original game coders. Each freeze file is over 400k in size. To help save
disk space, Snes9x can be compiled with zlib, which is used to compress the
freeze files, reducing the size to typically below 100k. Download zlib from
its homepage at http://www.cdrom.com/pub/infozip/zlib/, compile Snes9x with
ZLIB defined and link with zlib. zlib is also used to load any compressed
ROM images Snes9x my encounter, compressed with gzip or compress.
Porting
=======
In theory you will only need to edit port.h, then in a separate file write
all the initialisation code and interface routines that Snes9x expects the
you to implement. You, no doubt, will discover otherwise....
There are several compile-time only options available:
DEBUGGER
--------
Enables extra code to assist me in debugging SNES ROMs. The debugger has only
ever been a quick-hack by me and user-interface to debugger facilities is
virtually non-existent. Most of the debugger information is output via
stdout and enabling the compile-time options slows the whole emulator down
slightly. However, the debugger options available are very powerful; you
could use it to help get your port working. You probably still want to ship
the finished version with the debugger disabled, it will only confuse
non-technical users.
VAR_CYCLES
----------
I recommend you define this. The main CPU in the SNES actually varies in
speed depending on what area of memory its accessing and the ROM access
speed of the game pack; defining VAR_CYCLES causes Snes9x to emulate this,
using a good approximation, rather than fixed cycle length as ZSNES does. The
resultant code is slightly slower. Leaving it undefined results in many more
emulation timing errors appearing while playing games.
CPU_SHUTDOWN and SPC700_SHUTDOWN
--------------------------------
Again I recommend defining both of these. They are both speed up hacks.
When defined, Snes9x starts watching for when either the main or sound CPUs
are in simply loops waiting for a known event to happen - like the end of
the current scan-line, and interrupt or a sound timer to reach a particular
value. If Snes9x spots either CPU in such a loop it uses its insider
knowledge to simply skip the emulation of that CPU's instructions until the
event happens. It can be a big win with lots of SNES games.
I'm constantly amazed at the ingenuity of some programmers who are able to
produce complex code to do simple things: some ROM's wait loops are so
complex Snes9x fails to spot the CPU is in such a loop and the shutdown
speed up hacks don't work.
You might be wondering why VAR_CYCLES, and the two SHUTDOWN options have to
be enabled with defines, well, in the past they sometimes introduced
problems with some ROMs, so I kept them as options. I think I've fixed all
the problems now, but you never know...
SPC700_C
--------
Define this if you are using the C/C++ version of the SPC700 CPU core. It
enables a ROM compatibility feature that executes SPC700 instructions during
SNES DMA, it allows several games to start that would otherwise lock up and
fixes music pauses when ROMs do lots of DMA, usually when switching between
game screens.
ZLIB
----
Define this if you have the zlib library available and you want it to
compress freeze-game files to save disk space. The library is also used to
support compressed ROM images.
NO_INLINE_SET_GET
-----------------
Define this to stop several of the memory access routines from being
defined in-line. Whether the C++ compiler actually in-lines when this symbol
is not defined is up to the compiler itself. In-lines functions can speed up
the C++ CPU emulations on some architectures at the cost of increased code
size. Try fiddling with this option once you've got port working to see if
it helps the speed of your port.
EXECUTE_SUPERFX_PER_LINE and ZSNES_FX
-------------------------------------
Define these if you're going to be using the ZSNES Super FX i386 assembler
code, otherwise leave them both undefined. In theory,
EXECUTE_SUPERFX_PER_LINE can also be defined when using the C++ Super FX
emulation code, but the code is still buggy and enabling the option
introduces more problems than it fixes. Any takers for fixing the C++ code?
JOYSTICK_SUPPORT, SIDEWINDER_SUPPORT and GRIP_SUPPORT
-----------------------------------------------------
These options enable support for various input devices in the UNIX and MS-DOS
port code. They're only of interest if you're able to use the existing UNIX
or MS-DOS port specific code.
port.h
======
If the byte ordering of the target system is least significant byte first,
make sure LSB_FIRST is defined in this header, otherwise, make sure its not
defined.
If you're going to support 16-bit screen rendering (required if you want
transparency effects) and your system doesn't use RGB 565 - 5 bits for red,
6 bits for green and 5 bits for blue - then you'll need make sure RGB555,
BGR565 or BGR555 is defined instead. You might want to take a look at the
*_LOW_BIT_MASKs, *_HI_BIT_MASKs and BUILD_PIXEL macros to make sure they're
correct, because I've only every tested the RGB565 version, though the Mac
port uses the RGB555 option. If your system is 24 or 32-bit only, then
don't define anything; instead write a conversion routine that will take a
complete rendered 16-bit SNES screen in RGB565 format and convert to the
format required to be displayed on your hardware.
port.h also typedefs some types, uint8 for an unsigned, 8-bit quantity,
uint16 for an unsigned, 16-bit quantity, uint32 for a 32-bit, unsigned
quantity and bool8 for a true/false type. Signed versions are also
typedef'ed.
The CHECK_SOUND macro can be defined to invoke some code that polls the
host system's sound hardware to see if it can accept any more sound data.
Snes9x makes calls to this macro several times when it is rendering the SNES
screen, during large SNES DMAs and after every emulated CPU instruction.
Since this CHECK_SOUND macro is invoked often, the code should only take a
very small amount of time to execute or it will slow down the emulator's
performance. The Linux and UNIX ports use a system timer and set a variable
when it has expired; the CHECK_SOUND only has to check to see if the
variable is set. On the MS-DOS and Mac ports, the sound hardware is not
polled at all, instead it is driven by interrupts or callbacks and the
CHECK_SOUND macro is defined to be empty.
Initialisation Code
-------------------
This is what the Linux, UNIX and MS-DOS ports do, I suspect your code
might be similar:
- The Settings structure is initialised to some sensible default values -
check the main function in unix.cpp for the values it uses.
- The command line is parsed, options specified override default values in
the Settings structure and specify a ROM image filename that the user
wants loaded. Your port could load user preferences from a file or some
other source at this point. Most values, with a little care, can be changed
via a GUI once the emulator is running.
- Some Settings structure value validation takes place, for example if
transparency effects are requested the code also makes sure 16-bit
screen rendering is turned on as well.
- Memory.Init() and S9xInitAPU() are called, checking neither failed. The
only reason they would fail is if memory allocation failed.
- Memory.LoadROM (filename) is called to load the specified ROM image into
memory. If that worked Memory.LoadSRAM (sram_filename) is called to load
the ROM's S-RAM file, if one exists. The all current ports base the
sram_filename on the filename of the ROM image, changing the file's
extension (the .smc or whatever bit) and changing the directory where its
located - you won't be able to save S-RAM files onto a CD if that's where
the ROM image is located!
If your port has a GUI, you can delay this step until the user picks an
image to load.
SNES roms images come in all shapes and sizes, some with headers, some
without, some have been mangled by the copier device in one of two ways, and
some split into several pieces; plus the SNES itself has several different
memory map models. The code tries to auto-detect all these various types,
but sometimes the SNES ROM header information has been manually edited by
someone at some stage and the code guesses wrong. To help it out it these
situations, the Settings structure contains several options to force a
particular ROM image format; these values must be initialised prior to each
call to Memory.LoadROM(filename).
- The Linux and UNIX ports now do some more operating system initialisation
ready for a system timer to be started.
- The host display hardware is now initialised. The actual screen depth and
resolution should be picked based on the user preferences if possible.
The X Window System port can't control the screen depth or resolution, if
the user requests transparency effects but the display hardware is only
set to 8-bit, it has to invoke an extra step of converting the 16-bit SNES
rendered screen to a fixed palette 8-bit display just before the SNES
screen is copied to the display hardware.
The GFX.Screen pointer needs to be initialised to point to an array of
uint8 for 8-bit screen rendering or uint16 for 16-bit rendering, cast to
an array of uint8. The array needs to be at least 256x239 bytes or shorts
in size for lo-res only support (Settings.SupportHiRes = FALSE) or
512x478 for lo-res and hi-res support. If transparency effects are
required, the GFX.SubScreen array also needs to be initialised to another
identically sized array of the same type, otherwise it can be just
initialised to NULL.
The GFX.Pitch variable needs to be set to the number of bytes on each line
of the arrays, e.g. 256 for lo-res only support, up to 1024 for 16-bit
hi-res support. If GFX.Screen is pointing into an existing array, one
created by the library function rather than just calling malloc or new,
then set GFX.Pitch to the number of bytes per line of that array,
including any padding the library function may have added.
If the target hardware supports fast access to video RAM, the screen is in
16-bit format supported by the SNES rendering code and you can double
buffer the display, you might want to point GFX.Screen directly at the
video buffer RAM. You will need to recompute the GFX.Delta value every
time you change the GFX.Screen value to double-buffer the rendering and
display.
- A call to S9xGraphicsInit() is made; make sure all your graphics rendering
options are setup correctly by now. If later, you want to change some
settings, for example 16-bit to 8-bit rendering, call S9xGraphicsDeinit()
first, change your settings, GFX.Screen and GFX.SubScreen arrays, etc.,
then call S9xGraphicsInit() again.
- S9xInitSound(int playbackrate, bool8 stereo, int sound_buffer_size)
is now called, which in turn will call your S9xOpenSoundDevice function -
see below.
- The display is switched to graphics mode using a call to S9xGraphicsMode().
- The system timer is started; its used for keeping the emulator speed
relatively constant on the MS-DOS port and noting when the sound hardware
sound should be able to accept more sound data on the Linux and UNIX ports.
- A main loop is entered which is just a loop constantly calling
S9xMainLoop() then polling the operating system for any pending events
such as key presses and releases, joystick updates, mouse position
updates, GUI user interaction, etc.
Pause functionality can be implemented by skipping the call to S9xMainLoop
and muting the sound output by calling S9xSetSoundMute (TRUE).
Don't enter the main loop until a SNES ROM image has been loaded, or at
least skip calling S9xMainLoop inside the loop until one is and make sure
S9xReset is called instead before entering the main loop. The Mac port
implements this technique by starting in pause mode and refusing to unpause
until a ROM image is loaded.
S9xMainLoop processes SNES CPU emulation, SNES screen rendering, DMA and
H-DMA emulation, until emulated scan-line 0 is reached, then it returns.
Now is your chance to process any system events pending, scan the
keyboard, read joystick values, etc.
If DEBUGGER compile-time support is enabled and the CPU emulation has hit
a break point or single-stepping is switched on, or the DEBUG_MODE_FLAG is
set in the CPU.Flags variable, then the S9xMainLoop routine returns early,
allowing you to act on the event in some way. The Linux, DOS and UNIX ports
respond to the DEBUG_MODE_FLAG being set by calling S9xDoDebug(), which in
turn outputs the current instruction and loops reading commands from stdin
and outputting debug information, currently via stdout. The debugger
desperately needs rewriting to support a GUI interface, more descriptive
commands and better error handling; maybe one day...
Existing Interface Routines
---------------------------
These are routines already written that you will either need to call or
might find useful.
-> bool8 Memory.Init ()
Allocates and initialises several major lumps of memory, for example
the SNES ROM and RAM arrays, tile cache arrays, etc. Returns FALSE if
memory allocation fails.
-> void Memory.Deinit ()
Undoes the memory allocations made by Memory.Init.
-> bool8 S9xGraphicsInit ()
Allocated and initialises several lookup tables used to speed up SNES
graphics rendering. Call after you have initialised the GFX.Screen,
GFX.SubScreen and GFX.Pitch values. If Settings.Transparency is false it
does not allocate tables used to speed up transparency effects. If you
want to provide the user with option to turn the effects on and off during
game play, make sure Settings.Transparency is true when this function is
called, it can later be set to FALSE.
Returns FALSE if memory allocation fails.
-> void S9xGraphicsDeinit ()
Undoes the memory allocations made by S9xGraphicsInit.
-> bool8 S9xInitAPU ()
Allocates and initialises several arrays used by the sound CPU and sound
generation code.
-> void S9xDeinitAPU ()
Undoes the allocations made by S9xInitAPU.
-> bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size)
Does more sound code initialisation and opens the host system's sound hardware
by calling the S9xOpenSoundDevice function provided by you.
-> void S9xReset ()
Resets the SNES emulated hardware back to the state it was in at 'switch-on'
except the S-RAM area is presevered. The effect is it resets the current game
back to the start. This function is automatically called by Memory.LoROM.
-> bool8 Memory.LoadROM (const char *filename)
Attempts to load the specified ROM image filename into the emulated ROM area.
There are many different SNES ROM image formats and the code attempts to
auto-detect as many different types as it can and in a vast majority of the
cases gets it right. However, some ROM images have been edited by someone at
some stage or have been mangled by the ROM copier that produced them and
LoadROM needs help. Inparticular, it can't auto-detect the odd way in which
some Super FX games have been mangled and needs to be told, via
Settings.Interleaved2, that the ROM image is in that format, or that
odd-sized ROM images have a 512 byte copier header.
There are several other ROM image options in the Settings structure;
allow the user to set them before calling LoadROM, or make sure they all
reset to default values before each call to LoadROM.
-> bool8 Memory.LoadSRAM (const char *filename)
Call this routine to load the associated S-RAM save file (if any). The
filename should be based on the ROM image name to allow easy linkage.
The current ports change the directory and the filename extension of the ROM
filename to derive the S-RAM filename.
-> bool8 Memory.SaveSRAM (const char *filename)
Call this routine to save the emulated S-RAM area into a file so it can
be restored again the next time the user wants to play the game. Remember
to call this when just before the emulator exits or when the user has been
playing a game and is about to load another one.
-> void S9xMainLoop()
The emulator main loop. Call this from your own main loop that calls this
function (if a ROM image is loaded and the game is not paused), processes
any pending host system events, then goes back around the loop again until
the emulator exits.
S9xMainLoop normally returns control to your main loop once every emulated
frame, when it reaches the start of scan-line zero. However, the routine
can return more often if the DEBUGGER compile-time flag is defined and the
CPU has hit a break point, or the DEBUG_MODE_FLAG bit is set in CPU.Flags
or instruction single-stepping is enabled.
-> void S9xMixSamples (uint8 *buffer, int sample_count)
Call this routine from your host sound hardware handling code to fill the
specified buffer with ready mixed SNES sound data. If 16-bit sound mode is
choosen, then the buffer will be filled with an array of sample_count int16,
otherwise an array of sample_count uint8. If stereo sound generation is
selected the buffer is filled with the same number of samples, but in pairs,
first a left channel sample followed by the right channel sample.
There is a limit on how much data S9xMixSamples can deal with in one go and
hence a limit on the sample_count value; the limit is the value of the
MAX_BUFFER_SIZE symbol, normally 4096 bytes.
-> bool8 S9xSetSoundMute (bool8 mute)
Call with a TRUE parmeter to prevent S9xMixSamples from processing SNES
sample data and instead just filling the return buffer with silent sound
data. Useful if your sound system is interrupt or callback driven and the
game has been paused either directly or indirectly because the user
interacting with the emulator's user interface in some way.
-> bool8 S9xFreezeGame (const char *filename)
Call this routine to record the current SNES hardware state into a file,
the file can be loaded back using S9xUnfreezeGame at a later date effectively
restoring the current game to exact same spot. Call this routine while
you're processing any pending system events when S9xMainLoop has returned
control to you in your main loop.
-> bool8 S9xUnfreezeGame (const char *filename)
Restore the SNES hardware back to the exactly the state it was in when
S9xFreezeGame was used to generate the file specified. You have to arrange
the correct ROM is already loaded using Memory.LoadROM, an easy way to
arrange this is to base freeze-game filenames on the ROM image name. The
Linux, UNIX and DOS ports load freeze-game files when the user presses a
function key, with the names romfilename.000 for F1, romfilename.001 for F2,
etc. Games are frozen in the first place when the user presses Shift-function
key. You could choose some other scheme.
-> void S9xNextController ()
The real SNES allows several different types of devices to be plugged into
the game controller ports. The devices Snes9x emulates are a joy-pad,
multi-player adaptor (allowing a further 4 joy-pads to be plugged in),
a 2-button mouse and a light gun known as the SuperScope.
Each call to S9xNextController will step the current emulated device on to
the next device in the sequence multi-player, joy-pad, mouse on port 1,
mouse on port 2, light gun then back to multi-player again. Defines
allocating a number of each device type are in snes9x.h. The currently
selected device is stored in IPPU.Controller if you want to give some
feedback to the user. The initial value of IPPU.Controller (set when
S9xReset is called) is obtained from Settings.ControllerOption based on
currently enabled options.
Some ROMs object to certain non-joy-pad devices being plugged into the real
SNES while they are running, all Super FX games should only allow joy-pads to
be plugged in because the Super FX chip and any other device would overload
the SNES power supply. Tetris and Dr. Mario also objects for reasons best
known to itself. For this reason there are switches in the Settings
structure to enable and display the emulation of the various devices.
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 (bool8 apply)
void S9xRemoveCheats ()
void S9xAddCheat (uint32 address, bool8 cpu_address, bool8 sram, uint8 num_bytes,
uint8 byte1, uint8 byte2, uint8 byte3)
void S9xDeleteCheats ()
void S9xDoDebug ()
Interface Routines You Need to Implement
----------------------------------------
bool8 S9xOpenSnapshotFile (const char *base, bool8 read_only, STREAM *file)
***************************************************************************
void S9xCloseSnapshotFile (STREAM file)
***************************************
Routines to open and close freeze-game files. STREAM is defined as a
gzFile if ZLIB is defined else its defined as FILE *. The read_only parameter
is set to TRUE when reading a freeze-game file and FALSE when writing a
freeze-game file.
void S9xExit ()
***************
Called when some fatal error situation arises or when the 'q' debugger
command is used. The Mac port just beeps and drops back to the GUI when
S9xExit is called, the MS-DOS, Linux and Solaris ports all call exit () to
terminate the emulator process.
void S9xParseArg (char **argv, int &index, int argc)
****************************************************
void S9xExtraUsage ()
*********************
If you're going to be using the simple command line parser, when it
encounters an unknown option it calls S9xUsage which is supposed to report
all options the generic parse knows about (I haven't been keeping it up to
date of late). S9xUsage then, in turn calls S9xExtraUsage which you
implement to report any port-specific options available.
void S9xGraphicsMode ()
***********************
void S9xTextMode ()
*******************
The SNES debugger calls these routines to switch from a graphics screen
mode used to display the SNES game to a debugger screen used to display
debugger output. If the SNES screen can be displayed at the same time as
a text display, as would be the case when the host system implements a
graphical window system, or you're not going to support the SNES debugger,
then these routines should do nothing.
On the X Window System UNIX/Linux port, these routines do nothing where as
on the MS-DOS port they switch between a graphics screen mode and a text-only
screen mode.
bool8 S9xInitUpdate ()
**********************
Called just before Snes9x starts to render a SNES screen. The Windows port
uses this call to lock Direct X screen area to allow exclusive access; on
other existing ports its implemented as an empty function.
bool8 S9xDeinitDisplay (int width, int height, bool8 sixteen_bit)
*****************************************************************
Called once a complete SNES screen has been rendered into the GFX.Screen
memory buffer, now is your chance to copy the SNES rendered screen to the
host computer's screen memory. The problem is that you have to cope with
different sized SNES rendered screens. Width is always 256, unless you're
supporting SNES hi-res. screen modes (Settings.SupportHiRes is TRUE), in
which case it can be 256 or 512. The height parameter can be either 224 or
239 if you're only supporting SNES lo-res. screen modes, or 224, 239, 448 or
478 if hi-res. SNES screen modes are being supported.
All current ports support scaling the SNES screen to fill the host system's
screen, the many ports even supports interpolation - blending the colours of
adjacent pixels to help hide the fact they've been scaled - and scan-line
simulation - slightly darkening every other horizontal line.
Don't forget that if you're just placing the SNES image centerally in the
screen then you might need to clear areas of the screen if the SNES image
changes size between calls to S9xDeinitDisplay. The MS-DOS and UNIX ports
currently don't do this which results in junk being left on the screen if
the ROM changes SNES screen modes.
The sixteen_bit is just a copy of the Settings.SixteenBit setting and if
TRUE indicates a 16-bit SNES screen image has been rendered, 8-bit otherwise.
void S9xMessage (int type, int number, const char *message)
***********************************************************
I've started work on converting all the old printfs into calls to this
routine. When Snes9x wants to display an error, information or warning
message, it calls this routine. Check in messages.h for the types and
individual message numbers that Snes9x currently passes as parameters.
The idea is display the message string so the user can see it, but you
choose not to display anything at all, or change the message based on the
message number or message type.
Eventually all debug output will also go via this function, trace information
already does.
bool8 S9xOpenSoundDevice(int mode, bool8 stereo, int buffer_size)
*****************************************************************
S9xInitSound calls this function to actually open the host operating system's
sound device, or initialise the sound card in MS-DOS port.
The mode parameter is the value passed in on the command line with the -r
command line flag, assuming you're using the Snes9x parser. Its meant to
indicate what playback the sound hardware should be set to, value 1 to 7.
I think the real SNES sound chip playback rate is 30kHz, but such high
playback rates take a lot of native CPU power to emulate. The default
playback rate is 22kHz for the MS-DOS and UNIX ports.
The stereo flag indicates if the user wants stereo sound. Again, stereo
sound takes more CPU to power to emulate compared to mono sound.
The buffer_size value indicates what sample buffer size the user wants,
usually zero, meaning you should pick the value best suited to the current
playback rate. Sound data is normally passed to the sound hardware in
blocks, the smaller the block the less latency between the SNES game playing
a sound and it being heard by the user. But if you pick a too smaller value,
and you're having to periodically poll the operating system to see if it can
accept more sound data, then the sound output will break up because other
actions such as rendering the SNES screen can prevent you from polling the
hardware often enough and the operating system runs out of sound data to
play.
The MS-DOS port uses a buffer size of 128 samples since the sound card
sends an interrupt when more data is required which is acted upon promptly,
where as the Linux and Solaris ports use a buffer size of 512 samples or
more depending on the playback rate. Stereo and 16-bit sound both double the
actual size of the buffer in bytes.
uint32 S9xReadJoypad (int which1_0_to_4)
****************************************
This function is called to return a bit-wise mask of the state of one of the
five emulated SNES controllers. Return 0 if you're not supporting controllers
past a certain number or return the mask representing the current state of
the controller number passed as a parameter or'ed with 0x80000000.
Symbolic constants are defined in snes9x.h indicating the bit positions of
the various SNES buttons and direction indicators; they're all in the form
SNES_X_MASK where X is the SNES controller button name.
The MS-DOS and X Window System ports record what keys are currently pressed
and use that to build up a mask, the Windows port polls the operating system
when S9xReadJoypad is called to find out what keys are pressed. All ports
also implement host joysticks and joy-pads via this interface.
bool8 S9xReadMousePosition (int which1_0_to_1, int &x, int &y, uint32 &buttons)
*******************************************************************************
Used by Snes9x to get the current position of the host pointing device,
usually a mouse, used to emulated the SNES mouse. Snes9x converts the x and
y values to delta values required by the SNES mouse, so the actual x and y
values are unimportant, only the change in value since the last call to
this function is used.
Graphical windowing systems normally restrict the movement of the pointer on
the screen, if you're porting to such an environment you might want to make
a note of the change in position in the mouse since the last time you asked
the operating system the mouse position, add this change in value to some
saved x and y value, the reposition the pointer back to the centre of the
SNES display window. The saved x and y values will be the values returned
by this function.
The buttons return value is a bit-wise mask of the two SNES mouse buttons,
bit 0 for button 1 (left) and bit 1 for button 2 (right).
bool8 S9xReadSuperScopePosition (int &x, int &y, uint32 &buttons)
*****************************************************************
void S9xSetPalette ()
*********************
void S9xSyncSpeed ()
S9xUnixProcessSound
void _makepath(char *, char const *, char const *, char const *, char const *)
void _splitpath(char const *, char *, char *, char *, char *)
Sound Generation
----------------
Settings
--------
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#ifdef __DJGPP
#include <allegro.h>
#endif
#include "snes9x.h"
#include "port.h"
#include "gfx.h"
extern "C"
{
#ifdef MMX
void _2xSaILine (uint8 *srcPtr, uint8 *deltaPtr, uint32 srcPitch,
uint32 width, uint8 *dstPtr, uint32 dstPitch);
void _2xSaISuperEagleLine (uint8 *srcPtr, uint8 *deltaPtr,
uint32 srcPitch, uint32 width,
uint8 *dstPtr, uint32 dstPitch);
void _2xSaISuper2xSaILine (uint8 *srcPtr, uint8 *deltaPtr,
uint32 srcPitch, uint32 width,
uint8 *dstPtr, uint32 dstPitch);
void Init_2xSaIMMX (uint32 BitFormat);
void BilinearMMX (uint16 * A, uint16 * B, uint16 * C, uint16 * D,
uint16 * dx, uint16 * dy, uint8 *dP);
void BilinearMMXGrid0 (uint16 * A, uint16 * B, uint16 * C, uint16 * D,
uint16 * dx, uint16 * dy, uint8 *dP);
void BilinearMMXGrid1 (uint16 * A, uint16 * B, uint16 * C, uint16 * D,
uint16 * dx, uint16 * dy, uint8 *dP);
void EndMMX ();
#endif
}
bool8 cpu_mmx = 1;
static uint32 colorMask = 0xF7DEF7DE;
static uint32 lowPixelMask = 0x08210821;
static uint32 qcolorMask = 0xE79CE79C;
static uint32 qlowpixelMask = 0x18631863;
static uint32 redblueMask = 0xF81F;
static uint32 greenMask = 0x7E0;
int Init_2xSaI (uint32 BitFormat)
{
if (BitFormat == 565)
{
colorMask = 0xF7DEF7DE;
lowPixelMask = 0x08210821;
qcolorMask = 0xE79CE79C;
qlowpixelMask = 0x18631863;
redblueMask = 0xF81F;
greenMask = 0x7E0;
}
else if (BitFormat == 555)
{
colorMask = 0x7BDE7BDE;
lowPixelMask = 0x04210421;
qcolorMask = 0x739C739C;
qlowpixelMask = 0x0C630C63;
redblueMask = 0x7C1F;
greenMask = 0x3E0;
}
else
{
return 0;
}
#ifdef MMX
Init_2xSaIMMX (BitFormat);
#endif
return 1;
}
static __inline__ int GetResult1 (uint32 A, uint32 B, uint32 C, uint32 D,
uint32 /* E */)
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r += 1;
if (y <= 1)
r -= 1;
return r;
}
static __inline__ int GetResult2 (uint32 A, uint32 B, uint32 C, uint32 D,
uint32 /* E */)
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r -= 1;
if (y <= 1)
r += 1;
return r;
}
static __inline__ int GetResult (uint32 A, uint32 B, uint32 C, uint32 D)
{
int x = 0;
int y = 0;
int r = 0;
if (A == C)
x += 1;
else if (B == C)
y += 1;
if (A == D)
x += 1;
else if (B == D)
y += 1;
if (x <= 1)
r += 1;
if (y <= 1)
r -= 1;
return r;
}
static __inline__ uint32 INTERPOLATE (uint32 A, uint32 B)
{
if (A != B)
{
return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) +
(A & B & lowPixelMask));
}
else
return A;
}
static __inline__ uint32 Q_INTERPOLATE (uint32 A, uint32 B, uint32 C, uint32 D)
{
register uint32 x = ((A & qcolorMask) >> 2) +
((B & qcolorMask) >> 2) +
((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
register uint32 y = (A & qlowpixelMask) +
(B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask);
y = (y >> 2) & qlowpixelMask;
return x + y;
}
#define BLUE_MASK565 0x001F001F
#define RED_MASK565 0xF800F800
#define GREEN_MASK565 0x07E007E0
#define BLUE_MASK555 0x001F001F
#define RED_MASK555 0x7C007C00
#define GREEN_MASK555 0x03E003E0
void Super2xSaI (uint8 *srcPtr, uint32 srcPitch,
uint8 *deltaPtr, uint8 *dstPtr, uint32 dstPitch,
int width, int height)
{
uint16 *bP;
uint8 *dP;
uint32 inc_bP;
#ifdef MMX
if (cpu_mmx)
{
while (height--)
{
_2xSaISuper2xSaILine (srcPtr, deltaPtr, srcPitch, width,
dstPtr, dstPitch);
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
}
}
else
#endif
{
uint32 Nextline = srcPitch >> 1;
inc_bP = 1;
while (height--)
{
bP = (uint16 *) srcPtr;
dP = (uint8 *) dstPtr;
for (uint32 finish = width; finish; finish -= inc_bP)
{
uint32 color4, color5, color6;
uint32 color1, color2, color3;
uint32 colorA0, colorA1, colorA2, colorA3,
colorB0, colorB1, colorB2, colorB3, colorS1, colorS2;
uint32 product1a, product1b, product2a, product2b;
//--------------------------------------- B1 B2
// 4 5 6 S2
// 1 2 3 S1
// A1 A2
colorB0 = *(bP - Nextline - 1);
colorB1 = *(bP - Nextline);
colorB2 = *(bP - Nextline + 1);
colorB3 = *(bP - Nextline + 2);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + Nextline - 1);
color2 = *(bP + Nextline);
color3 = *(bP + Nextline + 1);
colorS1 = *(bP + Nextline + 2);
colorA0 = *(bP + Nextline + Nextline - 1);
colorA1 = *(bP + Nextline + Nextline);
colorA2 = *(bP + Nextline + Nextline + 1);
colorA3 = *(bP + Nextline + Nextline + 2);
//--------------------------------------
if (color2 == color6 && color5 != color3)
{
product2b = product1b = color2;
}
else if (color5 == color3 && color2 != color6)
{
product2b = product1b = color5;
}
else if (color5 == color3 && color2 == color6)
{
register int r = 0;
r += GetResult (color6, color5, color1, colorA1);
r += GetResult (color6, color5, color4, colorB1);
r += GetResult (color6, color5, colorA2, colorS1);
r += GetResult (color6, color5, colorB2, colorS2);
if (r > 0)
product2b = product1b = color6;
else if (r < 0)
product2b = product1b = color5;
else
{
product2b = product1b = INTERPOLATE (color5, color6);
}
}
else
{
if (color6 == color3 && color3 == colorA1
&& color2 != colorA2 && color3 != colorA0)
product2b =
Q_INTERPOLATE (color3, color3, color3, color2);
else if (color5 == color2 && color2 == colorA2
&& colorA1 != color3 && color2 != colorA3)
product2b =
Q_INTERPOLATE (color2, color2, color2, color3);
else
product2b = INTERPOLATE (color2, color3);
if (color6 == color3 && color6 == colorB1
&& color5 != colorB2 && color6 != colorB0)
product1b =
Q_INTERPOLATE (color6, color6, color6, color5);
else if (color5 == color2 && color5 == colorB2
&& colorB1 != color6 && color5 != colorB3)
product1b =
Q_INTERPOLATE (color6, color5, color5, color5);
else
product1b = INTERPOLATE (color5, color6);
}
if (color5 == color3 && color2 != color6 && color4 == color5
&& color5 != colorA2)
product2a = INTERPOLATE (color2, color5);
else
if (color5 == color1 && color6 == color5
&& color4 != color2 && color5 != colorA0)
product2a = INTERPOLATE (color2, color5);
else
product2a = color2;
if (color2 == color6 && color5 != color3 && color1 == color2
&& color2 != colorB2)
product1a = INTERPOLATE (color2, color5);
else
if (color4 == color2 && color3 == color2
&& color1 != color5 && color2 != colorB0)
product1a = INTERPOLATE (color2, color5);
else
product1a = color5;
product1a = product1a | (product1b << 16);
product2a = product2a | (product2b << 16);
*((uint32 *) dP) = product1a;
*((uint32 *) (dP + dstPitch)) = product2a;
bP += inc_bP;
dP += sizeof (uint32);
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
} // while (height--)
}
}
void SuperEagle (uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr,
uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
uint8 *dP;
uint16 *bP;
uint16 *xP;
uint32 inc_bP;
#ifdef MMX
if (cpu_mmx)
{
while (height--)
{
_2xSaISuperEagleLine (srcPtr, deltaPtr, srcPitch, width,
dstPtr, dstPitch);
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
}
}
else
#endif
{
inc_bP = 1;
uint32 Nextline = srcPitch >> 1;
while (height--)
{
bP = (uint16 *) srcPtr;
xP = (uint16 *) deltaPtr;
dP = dstPtr;
for (uint32 finish = width; finish; finish -= inc_bP)
{
uint32 color4, color5, color6;
uint32 color1, color2, color3;
uint32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
uint32 product1a, product1b, product2a, product2b;
colorB1 = *(bP - Nextline);
colorB2 = *(bP - Nextline + 1);
color4 = *(bP - 1);
color5 = *(bP);
color6 = *(bP + 1);
colorS2 = *(bP + 2);
color1 = *(bP + Nextline - 1);
color2 = *(bP + Nextline);
color3 = *(bP + Nextline + 1);
colorS1 = *(bP + Nextline + 2);
colorA1 = *(bP + Nextline + Nextline);
colorA2 = *(bP + Nextline + Nextline + 1);
// --------------------------------------
if (color2 == color6 && color5 != color3)
{
product1b = product2a = color2;
if ((color1 == color2) || (color6 == colorB2))
{
product1a = INTERPOLATE (color2, color5);
product1a = INTERPOLATE (color2, product1a);
// product1a = color2;
}
else
{
product1a = INTERPOLATE (color5, color6);
}
if ((color6 == colorS2) || (color2 == colorA1))
{
product2b = INTERPOLATE (color2, color3);
product2b = INTERPOLATE (color2, product2b);
// product2b = color2;
}
else
{
product2b = INTERPOLATE (color2, color3);
}
}
else if (color5 == color3 && color2 != color6)
{
product2b = product1a = color5;
if ((colorB1 == color5) || (color3 == colorS1))
{
product1b = INTERPOLATE (color5, color6);
product1b = INTERPOLATE (color5, product1b);
// product1b = color5;
}
else
{
product1b = INTERPOLATE (color5, color6);
}
if ((color3 == colorA2) || (color4 == color5))
{
product2a = INTERPOLATE (color5, color2);
product2a = INTERPOLATE (color5, product2a);
// product2a = color5;
}
else
{
product2a = INTERPOLATE (color2, color3);
}
}
else if (color5 == color3 && color2 == color6)
{
register int r = 0;
r += GetResult (color6, color5, color1, colorA1);
r += GetResult (color6, color5, color4, colorB1);
r += GetResult (color6, color5, colorA2, colorS1);
r += GetResult (color6, color5, colorB2, colorS2);
if (r > 0)
{
product1b = product2a = color2;
product1a = product2b = INTERPOLATE (color5, color6);
}
else if (r < 0)
{
product2b = product1a = color5;
product1b = product2a = INTERPOLATE (color5, color6);
}
else
{
product2b = product1a = color5;
product1b = product2a = color2;
}
}
else
{
product2b = product1a = INTERPOLATE (color2, color6);
product2b =
Q_INTERPOLATE (color3, color3, color3, product2b);
product1a =
Q_INTERPOLATE (color5, color5, color5, product1a);
product2a = product1b = INTERPOLATE (color5, color3);
product2a =
Q_INTERPOLATE (color2, color2, color2, product2a);
product1b =
Q_INTERPOLATE (color6, color6, color6, product1b);
// product1a = color5;
// product1b = color6;
// product2a = color2;
// product2b = color3;
}
product1a = product1a | (product1b << 16);
product2a = product2a | (product2b << 16);
*((uint32 *) dP) = product1a;
*((uint32 *) (dP + dstPitch)) = product2a;
*xP = color5;
bP += inc_bP;
xP += inc_bP;
dP += sizeof (uint32);
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
} // endof: while (height--)
}
}
void _2xSaI (uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr,
uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
uint8 *dP;
uint16 *bP;
uint32 inc_bP;
#ifdef MMX
if (cpu_mmx)
{
while (height--)
{
_2xSaILine (srcPtr, deltaPtr, srcPitch, width, dstPtr, dstPitch);
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
}
}
else
#endif
{
inc_bP = 1;
uint32 Nextline = srcPitch >> 1;
while (height--)
{
bP = (uint16 *) srcPtr;
dP = dstPtr;
for (uint32 finish = width; finish; finish -= inc_bP)
{
register uint32 colorA, colorB;
uint32 colorC, colorD,
colorE, colorF, colorG, colorH,
colorI, colorJ, colorK, colorL,
colorM, colorN, colorO, colorP;
uint32 product, product1, product2;
//---------------------------------------
// Map of the pixels: I|E F|J
// G|A B|K
// H|C D|L
// M|N O|P
colorI = *(bP - Nextline - 1);
colorE = *(bP - Nextline);
colorF = *(bP - Nextline + 1);
colorJ = *(bP - Nextline + 2);
colorG = *(bP - 1);
colorA = *(bP);
colorB = *(bP + 1);
colorK = *(bP + 2);
colorH = *(bP + Nextline - 1);
colorC = *(bP + Nextline);
colorD = *(bP + Nextline + 1);
colorL = *(bP + Nextline + 2);
colorM = *(bP + Nextline + Nextline - 1);
colorN = *(bP + Nextline + Nextline);
colorO = *(bP + Nextline + Nextline + 1);
colorP = *(bP + Nextline + Nextline + 2);
if ((colorA == colorD) && (colorB != colorC))
{
if (((colorA == colorE) && (colorB == colorL)) ||
((colorA == colorC) && (colorA == colorF)
&& (colorB != colorE) && (colorB == colorJ)))
{
product = colorA;
}
else
{
product = INTERPOLATE (colorA, colorB);
}
if (((colorA == colorG) && (colorC == colorO)) ||
((colorA == colorB) && (colorA == colorH)
&& (colorG != colorC) && (colorC == colorM)))
{
product1 = colorA;
}
else
{
product1 = INTERPOLATE (colorA, colorC);
}
product2 = colorA;
}
else if ((colorB == colorC) && (colorA != colorD))
{
if (((colorB == colorF) && (colorA == colorH)) ||
((colorB == colorE) && (colorB == colorD)
&& (colorA != colorF) && (colorA == colorI)))
{
product = colorB;
}
else
{
product = INTERPOLATE (colorA, colorB);
}
if (((colorC == colorH) && (colorA == colorF)) ||
((colorC == colorG) && (colorC == colorD)
&& (colorA != colorH) && (colorA == colorI)))
{
product1 = colorC;
}
else
{
product1 = INTERPOLATE (colorA, colorC);
}
product2 = colorB;
}
else if ((colorA == colorD) && (colorB == colorC))
{
if (colorA == colorB)
{
product = colorA;
product1 = colorA;
product2 = colorA;
}
else
{
register int r = 0;
product1 = INTERPOLATE (colorA, colorC);
product = INTERPOLATE (colorA, colorB);
r +=
GetResult1 (colorA, colorB, colorG, colorE,
colorI);
r +=
GetResult2 (colorB, colorA, colorK, colorF,
colorJ);
r +=
GetResult2 (colorB, colorA, colorH, colorN,
colorM);
r +=
GetResult1 (colorA, colorB, colorL, colorO,
colorP);
if (r > 0)
product2 = colorA;
else if (r < 0)
product2 = colorB;
else
{
product2 =
Q_INTERPOLATE (colorA, colorB, colorC,
colorD);
}
}
}
else
{
product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD);
if ((colorA == colorC) && (colorA == colorF)
&& (colorB != colorE) && (colorB == colorJ))
{
product = colorA;
}
else
if ((colorB == colorE) && (colorB == colorD)
&& (colorA != colorF) && (colorA == colorI))
{
product = colorB;
}
else
{
product = INTERPOLATE (colorA, colorB);
}
if ((colorA == colorB) && (colorA == colorH)
&& (colorG != colorC) && (colorC == colorM))
{
product1 = colorA;
}
else
if ((colorC == colorG) && (colorC == colorD)
&& (colorA != colorH) && (colorA == colorI))
{
product1 = colorC;
}
else
{
product1 = INTERPOLATE (colorA, colorC);
}
}
product = colorA | (product << 16);
product1 = product1 | (product2 << 16);
*((int32 *) dP) = product;
*((uint32 *) (dP + dstPitch)) = product1;
bP += inc_bP;
dP += sizeof (uint32);
} // end of for ( finish= width etc..)
srcPtr += srcPitch;
dstPtr += dstPitch * 2;
deltaPtr += srcPitch;
} // endof: while (height--)
}
}
#ifdef MMX
void Scale_2xSaI (uint8 *srcPtr, uint32 srcPitch, uint8 * /* deltaPtr */,
uint8 *dstPtr, uint32 dstPitch,
uint32 dstWidth, uint32 dstHeight, int width, int height)
{
uint8 *dP;
uint16 *bP;
uint32 w;
uint32 h;
uint32 dw;
uint32 dh;
uint32 hfinish;
uint32 wfinish;
uint32 Nextline;
uint16 colorA[4];
uint16 colorB[4];
uint16 colorC[4];
uint16 colorD[4];
uint16 dx[4];
uint16 dy[4];
Nextline = srcPitch >> 1;
wfinish = (width - 1) << 16; // convert to fixed point
hfinish = (height - 1) << 16; // convert to fixed point
dw = wfinish / (dstWidth - 1);
dh = hfinish / (dstHeight - 1);
for (h = 0; h < hfinish; h += dh)
{
uint32 y1, y2;
y1 = h & 0xffff; // fraction part of fixed point
y2 = 0x10000 - y1;
bP = (uint16 *) (srcPtr + ((h >> 16) * srcPitch));
dP = dstPtr;
for (w = 0; w < wfinish;)
{
uint32 A, B, C, D;
uint32 E, F, G, H;
uint32 I, J, K, L;
uint32 x1, x2, a1, f1, f2;
uint32 position;
for (int c = 0; c < 4; c++)
{
position = w >> 16;
A = bP[position]; // current pixel
B = bP[position + 1]; // next pixel
C = bP[position + Nextline];
D = bP[position + Nextline + 1];
E = bP[position - Nextline];
F = bP[position - Nextline + 1];
G = bP[position - 1];
H = bP[position + Nextline - 1];
I = bP[position + 2];
J = bP[position + Nextline + 2];
K = bP[position + Nextline + Nextline];
L = bP[position + Nextline + Nextline + 1];
x1 = w & 0xffff; // fraction part of fixed point
x2 = 0x10000 - x1;
/*1*/
if (A == D && B != C)
{
f1 = (x1 >> 1) + (0x10000 >> 2);
f2 = (y1 >> 1) + (0x10000 >> 2);
if (y1 <= f1 && A == J && A != E) // close to B
{
a1 = f1 - y1;
colorA[c] = A;
colorB[c] = B;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y1 >= f1 && A == G && A != L) // close to C
{
a1 = y1 - f1;
colorA[c] = A;
colorB[c] = C;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (x1 >= f2 && A == E && A != J) // close to B
{
a1 = x1 - f2;
colorA[c] = A;
colorB[c] = B;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (x1 <= f2 && A == L && A != G) // close to C
{
a1 = f2 - x1;
colorA[c] = A;
colorB[c] = C;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y1 >= x1) // close to C
{
a1 = y1 - x1;
colorA[c] = A;
colorB[c] = C;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y1 <= x1) // close to B
{
a1 = x1 - y1;
colorA[c] = A;
colorB[c] = B;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
}
else
/*2*/
if (B == C && A != D)
{
f1 = (x1 >> 1) + (0x10000 >> 2);
f2 = (y1 >> 1) + (0x10000 >> 2);
if (y2 >= f1 && B == H && B != F) // close to A
{
a1 = y2 - f1;
colorA[c] = B;
colorB[c] = A;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y2 <= f1 && B == I && B != K) // close to D
{
a1 = f1 - y2;
colorA[c] = B;
colorB[c] = D;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (x2 >= f2 && B == F && B != H) // close to A
{
a1 = x2 - f2;
colorA[c] = B;
colorB[c] = A;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (x2 <= f2 && B == K && B != I) // close to D
{
a1 = f2 - x2;
colorA[c] = B;
colorB[c] = D;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y2 >= x1) // close to A
{
a1 = y2 - x1;
colorA[c] = B;
colorB[c] = A;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
else if (y2 <= x1) // close to D
{
a1 = x1 - y2;
colorA[c] = B;
colorB[c] = D;
colorC[c] = 0;
colorD[c] = 0;
dx[c] = a1;
dy[c] = 0;
}
}
/*3*/
else
{
colorA[c] = A;
colorB[c] = B;
colorC[c] = C;
colorD[c] = D;
dx[c] = x1;
dy[c] = y1;
}
w += dw;
}
BilinearMMX (colorA, colorB, colorC, colorD, dx, dy, dP);
dP += 8;
}
dstPtr += dstPitch;
};
EndMMX ();
}
#else
static uint32 Bilinear (uint32 A, uint32 B, uint32 x)
{
unsigned long areaA, areaB;
unsigned long result;
if (A == B)
return A;
areaB = (x >> 11) & 0x1f; // reduce 16 bit fraction to 5 bits
areaA = 0x20 - areaB;
A = (A & redblueMask) | ((A & greenMask) << 16);
B = (B & redblueMask) | ((B & greenMask) << 16);
result = ((areaA * A) + (areaB * B)) >> 5;
return (result & redblueMask) | ((result >> 16) & greenMask);
}
static uint32 Bilinear4 (uint32 A, uint32 B, uint32 C, uint32 D, uint32 x,
uint32 y)
{
unsigned long areaA, areaB, areaC, areaD;
unsigned long result, xy;
x = (x >> 11) & 0x1f;
y = (y >> 11) & 0x1f;
xy = (x * y) >> 5;
A = (A & redblueMask) | ((A & greenMask) << 16);
B = (B & redblueMask) | ((B & greenMask) << 16);
C = (C & redblueMask) | ((C & greenMask) << 16);
D = (D & redblueMask) | ((D & greenMask) << 16);
areaA = 0x20 + xy - x - y;
areaB = x - xy;
areaC = y - xy;
areaD = xy;
result = ((areaA * A) + (areaB * B) + (areaC * C) + (areaD * D)) >> 5;
return (result & redblueMask) | ((result >> 16) & greenMask);
}
void Scale_2xSaI (uint8 *srcPtr, uint32 srcPitch, uint8 * /* deltaPtr */,
uint8 *dstPtr, uint32 dstPitch,
uint32 dstWidth, uint32 dstHeight, int width, int height)
{
uint8 *dP;
uint16 *bP;
uint32 w;
uint32 h;
uint32 dw;
uint32 dh;
uint32 hfinish;
uint32 wfinish;
uint32 Nextline = srcPitch >> 1;
wfinish = (width - 1) << 16; // convert to fixed point
dw = wfinish / (dstWidth - 1);
hfinish = (height - 1) << 16; // convert to fixed point
dh = hfinish / (dstHeight - 1);
for (h = 0; h < hfinish; h += dh)
{
uint32 y1, y2;
y1 = h & 0xffff; // fraction part of fixed point
bP = (uint16 *) (srcPtr + ((h >> 16) * srcPitch));
dP = dstPtr;
y2 = 0x10000 - y1;
w = 0;
for (; w < wfinish;)
{
uint32 A, B, C, D;
uint32 E, F, G, H;
uint32 I, J, K, L;
uint32 x1, x2, a1, f1, f2;
uint32 position, product1;
position = w >> 16;
A = bP[position]; // current pixel
B = bP[position + 1]; // next pixel
C = bP[position + Nextline];
D = bP[position + Nextline + 1];
E = bP[position - Nextline];
F = bP[position - Nextline + 1];
G = bP[position - 1];
H = bP[position + Nextline - 1];
I = bP[position + 2];
J = bP[position + Nextline + 2];
K = bP[position + Nextline + Nextline];
L = bP[position + Nextline + Nextline + 1];
x1 = w & 0xffff; // fraction part of fixed point
x2 = 0x10000 - x1;
/*0*/
if (A == B && C == D && A == C)
product1 = A;
else
/*1*/
if (A == D && B != C)
{
f1 = (x1 >> 1) + (0x10000 >> 2);
f2 = (y1 >> 1) + (0x10000 >> 2);
if (y1 <= f1 && A == J && A != E) // close to B
{
a1 = f1 - y1;
product1 = Bilinear (A, B, a1);
}
else if (y1 >= f1 && A == G && A != L) // close to C
{
a1 = y1 - f1;
product1 = Bilinear (A, C, a1);
}
else if (x1 >= f2 && A == E && A != J) // close to B
{
a1 = x1 - f2;
product1 = Bilinear (A, B, a1);
}
else if (x1 <= f2 && A == L && A != G) // close to C
{
a1 = f2 - x1;
product1 = Bilinear (A, C, a1);
}
else if (y1 >= x1) // close to C
{
a1 = y1 - x1;
product1 = Bilinear (A, C, a1);
}
else if (y1 <= x1) // close to B
{
a1 = x1 - y1;
product1 = Bilinear (A, B, a1);
}
}
else
/*2*/
if (B == C && A != D)
{
f1 = (x1 >> 1) + (0x10000 >> 2);
f2 = (y1 >> 1) + (0x10000 >> 2);
if (y2 >= f1 && B == H && B != F) // close to A
{
a1 = y2 - f1;
product1 = Bilinear (B, A, a1);
}
else if (y2 <= f1 && B == I && B != K) // close to D
{
a1 = f1 - y2;
product1 = Bilinear (B, D, a1);
}
else if (x2 >= f2 && B == F && B != H) // close to A
{
a1 = x2 - f2;
product1 = Bilinear (B, A, a1);
}
else if (x2 <= f2 && B == K && B != I) // close to D
{
a1 = f2 - x2;
product1 = Bilinear (B, D, a1);
}
else if (y2 >= x1) // close to A
{
a1 = y2 - x1;
product1 = Bilinear (B, A, a1);
}
else if (y2 <= x1) // close to D
{
a1 = x1 - y2;
product1 = Bilinear (B, D, a1);
}
}
/*3*/
else
{
product1 = Bilinear4 (A, B, C, D, x1, y1);
}
//end First Pixel
*(uint32 *) dP = product1;
dP += 2;
w += dw;
}
dstPtr += dstPitch;
}
}
#endif
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#ifdef __DJGPP
#include <allegro.h>
#undef TRUE
#endif
#include "snes9x.h"
#include "spc700.h"
#include "apu.h"
#include "soundux.h"
#include "cpuexec.h"
/* For note-triggered SPC dump support */
#include "snapshot.h"
extern "C" {const char *S9xGetFilenameInc (const char *);}
#ifdef USE_SPC_DUMP
int spc_is_dumping=0;
int spc_is_dumping_temp;
uint8 spc_dump_dsp[0x100];
#endif
extern int NoiseFreq [32];
static char _IAPU_RAM_[0x10000];
static char _IAPU_ShadowRAM_[0x10000];
static char _IAPU_CachedSamples_[0x40000];
bool8 S9xInitAPU ()
{
IAPU.RAM = (uint8 *) &_IAPU_RAM_;
IAPU.ShadowRAM = (uint8 *) &_IAPU_ShadowRAM_;
IAPU.CachedSamples = (uint8 *) &_IAPU_CachedSamples_;
bzero(IAPU.RAM,sizeof(_IAPU_RAM_));
bzero(IAPU.ShadowRAM,sizeof(_IAPU_ShadowRAM_));
bzero(IAPU.ShadowRAM,sizeof(_IAPU_CachedSamples_));
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 ()
{
IAPU.RAM = NULL;
IAPU.ShadowRAM = NULL;
IAPU.CachedSamples = NULL;
}
EXTERN_C uint8 APUROM [64];
void S9xResetAPU ()
{
int i;
Settings.APUEnabled = Settings.NextAPUEnabled;
#ifdef USE_SPC_DUMP
ZeroMemory(spc_dump_dsp, 0x100);
#endif
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);
#ifdef ENABLE_ECHO_SOUND
S9xSetEchoEnable (0);
#endif
}
void S9xSetAPUDSP (uint8 byte)
{
uint8 reg = IAPU.RAM [0xf2];
static uint8 KeyOn;
static uint8 KeyOnPrev;
int i;
#ifdef USE_SPC_DUMP
spc_dump_dsp[reg] = byte;
#endif
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;
#ifdef ENABLE_ECHO_SOUND
S9xSetEchoWriteEnable (FALSE);
#endif
// Kill sound
S9xResetSound (FALSE);
}
else
{
#ifdef ENABLE_ECHO_SOUND
S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED));
#endif
if (byte & APU_MUTE)
{
S9xSetSoundMute (TRUE);
}
else
S9xSetSoundMute (FALSE);
SoundData.noise_hertz = NoiseFreq [byte & 0x1f];
for (i = 0; i < 8; i++)
{
if (SoundData.channels [i].type == SOUND_NOISE)
S9xSetSoundFrequency (i, SoundData.noise_hertz);
}
}
break;
case APU_NON:
if (byte != APU.DSP [APU_NON])
{
uint8 mask = 1;
for (int c = 0; c < 8; c++, mask <<= 1)
{
int type;
if (byte & mask)
{
type = SOUND_NOISE;
}
else
{
type = SOUND_SAMPLE;
}
S9xSetSoundType (c, type);
}
}
break;
case APU_MVOL_LEFT:
#ifdef ENABLE_MASTER_VOLUMEN
if (byte != APU.DSP [APU_MVOL_LEFT])
{
S9xSetMasterVolume ((signed char) byte,
(signed char) APU.DSP [APU_MVOL_RIGHT]);
}
#endif
break;
case APU_MVOL_RIGHT:
#ifdef ENABLE_MASTER_VOLUMEN
if (byte != APU.DSP [APU_MVOL_RIGHT])
{
S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT],
(signed char) byte);
}
#endif
break;
case APU_EVOL_LEFT:
#ifdef ENABLE_ECHO_SOUND
if (byte != APU.DSP [APU_EVOL_LEFT])
{
S9xSetEchoVolume ((signed char) byte,
(signed char) APU.DSP [APU_EVOL_RIGHT]);
}
#endif
break;
case APU_EVOL_RIGHT:
#ifdef ENABLE_ECHO_SOUND
if (byte != APU.DSP [APU_EVOL_RIGHT])
{
S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT],
(signed char) byte);
}
#endif
break;
case APU_ENDX:
byte = 0;
break;
case APU_KOFF:
// if (byte)
{
uint8 mask = 1;
for (int c = 0; c < 8; c++, mask <<= 1)
{
if ((byte & mask) != 0)
{
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);
}
}
}
//KeyOnPrev=0;
APU.DSP [APU_KOFF] = byte;
return;
case APU_KON:
#ifdef USE_SPC_DUMP
if (spc_is_dumping)
{
if (byte & ~spc_is_dumping_temp)
{
APURegisters.PC = IAPU.PC - IAPU.RAM;
S9xAPUPackStatus();
S9xSPCDump (S9xGetFilenameInc (".spc"));
spc_is_dumping = 0;
}
}
#endif
if (byte)
{
uint8 mask = 1;
for (int c = 0; c < 8; c++, mask <<= 1)
{
if ((byte & mask) != 0)
{
// 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 USE_SPC_DUMP
spc_is_dumping_temp = byte;
#endif
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])
{
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])
{
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:
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:
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:
/* if (byte != APU.DSP [reg]) {
S9xSetSoundSample (reg >> 4, byte);
} */
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])
{
{
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])
{
{
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])
{
{
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:
break;
case APU_PMON:
if (byte != APU.DSP [APU_PMON])
{
S9xSetFrequencyModulationEnable (byte);
}
break;
case APU_EON:
#ifdef ENABLE_ECHO_SOUND
if (byte != APU.DSP [APU_EON])
{
S9xSetEchoEnable (byte);
}
#endif
break;
case APU_EFB:
#ifdef ENABLE_ECHO_SOUND
S9xSetEchoFeedback ((signed char) byte);
#endif
break;
case APU_ESA:
break;
case APU_EDL:
#ifdef ENABLE_ECHO_SOUND
S9xSetEchoDelay (byte & 0xf);
#endif
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)
{
// ADSR mode
static unsigned long AttackRate [16] = {
4100, 2600, 1500, 1000, 640, 380, 260, 160,
96, 64, 40, 24, 16, 10, 6, 1
};
static unsigned long DecayRate [8] = {
1200, 740, 440, 290, 180, 110, 74, 37
};
static unsigned long SustainRate [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
};
// XXX: can DSP be switched to ADSR mode directly from GAIN/INCREASE/
// DECREASE mode? And if so, what stage of the sequence does it start
// at?
if (S9xSetSoundMode (channel, MODE_ADSR))
{
// Hack for ROMs that use a very short attack rate, key on a
// channel, then switch to decay mode. e.g. Final Fantasy II.
int attack = AttackRate [adsr1 & 0xf];
#ifdef USE_SOUND_DESYNC
if (attack == 1)
attack = 0;
#endif
S9xSetSoundADSR (channel, attack,
DecayRate [(adsr1 >> 4) & 7],
SustainRate [adsr2 & 0x1f],
(adsr2 >> 5) & 7, 8);
}
}
else
{
// Gain mode
if ((gain & 0x80) == 0)
{
if (S9xSetSoundMode (channel, MODE_GAIN))
{
S9xSetEnvelopeRate (channel, 0, 0, gain & 0x7f);
S9xSetEnvelopeHeight (channel, gain & 0x7f);
}
}
else
{
static unsigned long IncreaseRate [32] = {
~0, 4100, 3100, 2600, 2000, 1500, 1300, 1000,
770, 640, 510, 380, 320, 260, 190, 160,
130, 96, 80, 64, 48, 40, 32, 24,
20, 16, 12, 10, 8, 6, 4, 2
};
static unsigned long DecreaseRateExp [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
};
if (gain & 0x40)
{
// Increase mode
if (S9xSetSoundMode (channel, (gain & 0x20) ?
MODE_INCREASE_BENT_LINE :
MODE_INCREASE_LINEAR))
{
S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f],
1, 127);
}
}
else
{
uint32 rate = (gain & 0x20) ? DecreaseRateExp [gain & 0x1f] / 2 :
IncreaseRate [gain & 0x1f];
int mode = (gain & 0x20) ? MODE_DECREASE_EXPONENTIAL
: MODE_DECREASE_LINEAR;
if (S9xSetSoundMode (channel, mode))
S9xSetEnvelopeRate (channel, rate, -1, 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 * 10000L >= IAPU.NextAPUTimerPos)
// if (CPU.Cycles * 10000L >= IAPU.NextAPUTimerPos)
{
IAPU.NextAPUTimerPos += SNES_APUTIMER2_CYCLEx10000;
if (APU.TimerEnabled [2])
{
APU.Timer [2] ++;
if (APU.Timer [2] >= APU.TimerTarget [2])
{
APU.Timer [2] = 0;
IAPU.RAM [0xff] = (IAPU.RAM [0xff] + 1) & 0xf;
#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])
{
APU.Timer [0] = 0;
IAPU.RAM [0xfd] = (IAPU.RAM [0xfd] + 1) & 0xf;
#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 ((SoundData.channels [reg >> 4].sample >> 8) |
(SoundData.channels [reg >> 4].sample & 0xff));
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 0;
// return ((uint8) 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);
}
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#include <math.h>
#include <stdlib.h>
#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);
}
void C4LoaDMem(char *C4RAM)
{
memmove(C4RAM+(READ_WORD(C4RAM+0x1f45)&0x1fff),
S9xGetMemPointer(READ_3WORD(C4RAM+0x1f40)),
READ_WORD(C4RAM+0x1f43));
}
}//end extern C
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <math.h>
#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
// CMemory_C4RAM = &CMemory_FillRAM [0x6000];
memset(CMemory_C4RAM, 0, 0x2000);
}
uint8 S9xGetC4 (uint16 Address)
{
return (CMemory_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=CMemory_C4RAM+(CMemory_C4RAM[0x626]<<2);
for(uint8 *i=CMemory_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(CMemory_C4RAM+0x0621);
globalY=READ_WORD(CMemory_C4RAM+0x0623);
OAMptr2=CMemory_C4RAM+0x200+(CMemory_C4RAM[0x626]>>2);
if(CMemory_C4RAM[0x0620]!=0){
SprCount=128-CMemory_C4RAM[0x626];
uint8 offset=(CMemory_C4RAM[0x626]&3)<<1;
for(int prio=0x30; prio>=0; prio-=0x10){
uint8 *srcptr=CMemory_C4RAM+0x220;
for(int i=CMemory_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=S9xGetMemPointer(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<<offset);
if(X&0x100) *OAMptr2 |= 1<<offset;
if(sprptr[0]&0x20) *OAMptr2 |= 2<<offset;
OAMptr+=4;
SprCount--;
offset=(offset+2)&6;
if(offset==0) OAMptr2++;
}
}
}
} else if(SprCount>0){
OAMptr[0]=(uint8)SprX;
OAMptr[1]=(uint8)SprY;
OAMptr[2]=SprName;
OAMptr[3]=SprAttr;
*OAMptr2 &= ~(3<<offset);
if(SprX&0x100) *OAMptr2 |= 3<<offset;
else *OAMptr2 |= 2<<offset;
OAMptr+=4;
SprCount--;
offset=(offset+2)&6;
if(offset==0) OAMptr2++;
}
}
}
}
// XXX: Copy to OAM? I doubt it.
}
static void C4DoScaleRotate(int row_padding){
int16 A, B, C, D;
// Calculate matrix
int32 XScale=READ_WORD(CMemory_C4RAM+0x1f8f);
if(XScale&0x8000) XScale=0x7fff;
int32 YScale=READ_WORD(CMemory_C4RAM+0x1f92);
if(YScale&0x8000) YScale=0x7fff;
if(READ_WORD(CMemory_C4RAM+0x1f80)==0)
{ // no rotation
// XXX: only do this for C and D?
// XXX: and then only when YScale is 0x1000?
A=(int16)XScale;
B=0;
C=0;
D=(int16)YScale;
}
else if(READ_WORD(CMemory_C4RAM+0x1f80)==128){ // 90 degree rotation
// XXX: Really do this?
A=0;
B=(int16)(-YScale);
C=(int16)XScale;
D=0;
} else if(READ_WORD(CMemory_C4RAM+0x1f80)==256){ // 180 degree rotation
// XXX: Really do this?
A=(int16)(-XScale);
B=0;
C=0;
D=(int16)(-YScale);
} else if(READ_WORD(CMemory_C4RAM+0x1f80)==384){ // 270 degree rotation
// XXX: Really do this?
A=0;
B=(int16)YScale;
C=(int16)(-XScale);
D=0;
} else {
A=(int16)SAR(C4CosTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]*XScale, 15);
B=(int16)(-SAR(C4SinTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]*YScale, 15));
C=(int16)SAR(C4SinTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]*XScale, 15);
D=(int16)SAR(C4CosTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]*YScale, 15);
}
// Calculate Pixel Resolution
uint8 w=CMemory_C4RAM[0x1f89]&~7;
uint8 h=CMemory_C4RAM[0x1f8c]&~7;
// printf("%dx%d XScale=%04x YScale=%04x angle=%03x\n", w, h, XScale, YScale, READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff);
// printf("Matrix: [%10g %10g] [%04x %04x]\n", A/4096.0, B/4096.0, A&0xffff, B&0xffff);
// printf(" [%10g %10g] [%04x %04x]\n", C/4096.0, D/4096.0, C&0xffff, D&0xffff);
// Clear the output RAM
memset(CMemory_C4RAM, 0, (w+(row_padding>>2))*(h>>1));
int32 Cx=(int16)READ_WORD(CMemory_C4RAM+0x1f83);
int32 Cy=(int16)READ_WORD(CMemory_C4RAM+0x1f86);
// Calculate start position (i.e. (Ox, Oy) = (0, 0))
// The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
// the function. We do Cx*A etc normally because the matrix parameters
// already have the fractional parts.
int32 LineX=(Cx<<12) - Cx*A - Cx*B;
int32 LineY=(Cy<<12) - Cy*C - Cy*D;
// Start loop
uint32 X, Y;
uint8 byte;
int outidx=0;
uint8 bit=0x80;
for(int y=0; y<h; y++){
X=LineX;
Y=LineY;
for(int x=0; x<w; x++){
if((X>>12)>=w || (Y>>12)>=h){
byte=0;
} else {
uint32 addr=(Y>>12)*w+(X>>12);
byte=CMemory_C4RAM[0x600+(addr>>1)];
if(addr&1) byte>>=4;
}
// De-bitplanify
if(byte&1) CMemory_C4RAM[outidx]|=bit;
if(byte&2) CMemory_C4RAM[outidx+1]|=bit;
if(byte&4) CMemory_C4RAM[outidx+16]|=bit;
if(byte&8) CMemory_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<<2)+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=CMemory_C4RAM[0x1f90];
C4WFX2Val=CMemory_C4RAM[0x1f86];
C4WFY2Val=CMemory_C4RAM[0x1f87];
C4WFDist=CMemory_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)<<1;
uint8 bit=0x80>>((X1>>8)&7);
CMemory_C4RAM[addr+0x300]&=~bit;
CMemory_C4RAM[addr+0x301]&=~bit;
if(Color&1) CMemory_C4RAM[addr+0x300]|=bit;
if(Color&2) CMemory_C4RAM[addr+0x301]|=bit;
}
X1+=X2;
Y1+=Y2;
}
}
static void C4DrawWireFrame(void)
{
uint8 *line=S9xGetMemPointer(READ_3WORD(CMemory_C4RAM+0x1f80));
uint8 *point1, *point2;
int16 X1, Y1, Z1;
int16 X2, Y2, Z2;
uint8 Color;
for(int i=CMemory_C4RAM[0x0295]; i>0; i--, line+=5){
if(line[0]==0xff && line[1]==0xff){
uint8 *tmp=line-5;
while(line[2]==0xff && line[3]==0xff) tmp-=5;
point1=S9xGetMemPointer((CMemory_C4RAM[0x1f82]<<16) | (tmp[2]<<8) | tmp[3]);
} else {
point1=S9xGetMemPointer((CMemory_C4RAM[0x1f82]<<16) | (line[0]<<8) | line[1]);
}
point2=S9xGetMemPointer((CMemory_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=CMemory_C4RAM[0x1f83];
C4WFY2Val=CMemory_C4RAM[0x1f86];
C4WFDist=CMemory_C4RAM[0x1f89];
C4WFScale=CMemory_C4RAM[0x1f8c];
// transform vertices
uint8 *ptr=CMemory_C4RAM;
{
for(int i=READ_WORD(CMemory_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(CMemory_C4RAM+0x600, 23);
WRITE_WORD(CMemory_C4RAM+0x602, 0x60);
WRITE_WORD(CMemory_C4RAM+0x605, 0x40);
WRITE_WORD(CMemory_C4RAM+0x600+8, 23);
WRITE_WORD(CMemory_C4RAM+0x602+8, 0x60);
WRITE_WORD(CMemory_C4RAM+0x605+8, 0x40);
ptr=CMemory_C4RAM+0xb02;
uint8 *ptr2=CMemory_C4RAM;
{
for(int i=READ_WORD(CMemory_C4RAM+0xb00); i>0; i--, ptr+=2, ptr2+=8)
{
C4WFXVal=READ_WORD(CMemory_C4RAM+(ptr[0]<<4)+1);
C4WFYVal=READ_WORD(CMemory_C4RAM+(ptr[0]<<4)+5);
C4WFX2Val=READ_WORD(CMemory_C4RAM+(ptr[1]<<4)+1);
C4WFY2Val=READ_WORD(CMemory_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=CMemory_C4RAM;
uint32 waveptr=CMemory_C4RAM[0x1f83];
uint16 mask1=0xc0c0;
uint16 mask2=0x3f3f;
for(int j=0; j<0x10; j++){
do {
int16 height=-((int8)CMemory_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(CMemory_C4RAM+0xa00+(height<<1));
} 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)CMemory_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(CMemory_C4RAM+0xa10+(height<<1));
} 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=CMemory_C4RAM[0x1f89];
height=CMemory_C4RAM[0x1f8c];
Cx=(int16)READ_WORD(CMemory_C4RAM+0x1f80);
Cy=(int16)READ_WORD(CMemory_C4RAM+0x1f83);
scaleX=(int16)READ_WORD(CMemory_C4RAM+0x1f86);
scaleY=(int16)READ_WORD(CMemory_C4RAM+0x1f8f);
StartX=-Cx*scaleX+(Cx<<8);
StartY=-Cy*scaleY+(Cy<<8);
src=CMemory_C4RAM+0x600;
memset(CMemory_C4RAM, 0, width*(height>>1));
for(uint32 y=StartY, i=0; i<height; i++, y+=scaleY)
{
for(uint32 x=StartX, j=0; j<width; j++, x+=scaleX)
{
if((x>>8)<width && (y>>8)<height && (y>>8)*width+(x>>8)<0x2000)
{
uint8 pixel=(j&1)?(*src>>4):*src;
int idx=(y>>11)*(width<<2)+(x>>11)*32+((y>>8)&7)<<1;
uint8 mask=0x80>>((x>>8)&7);
if(pixel&1) CMemory_C4RAM[idx]|=mask;
if(pixel&2) CMemory_C4RAM[idx+1]|=mask;
if(pixel&4) CMemory_C4RAM[idx+16]|=mask;
if(pixel&8) CMemory_C4RAM[idx+17]|=mask;
}
if(j&1) src++;
}
}
}
static void S9xC4ProcessSprites()
{
switch(CMemory_C4RAM[0x1f4d])
{
case 0x00: // Build OAM
C4ConvOAM();
break;
case 0x03: // Scale/Rotate
C4DoScaleRotate(0);
break;
case 0x05: // Transform Lines
C4TransformLines();
break;
case 0x07: // Scale/Rotate
C4DoScaleRotate(64);
break;
case 0x08: // Draw wireframe
C4DrawWireFrame();
break;
case 0x0b: // Disintegrate
C4SprDisintegrate();
break;
case 0x0c: // Wave
C4BitPlaneWave();
break;
default:
break;
}
}
void S9xSetC4 (uint8 byte, uint16 Address)
{
int i;
CMemory_C4RAM [Address-0x6000] = byte;
if (Address == 0x7f4f)
{
if(CMemory_C4RAM[0x1f4d]==0x0e && byte<0x40 && (byte&3)==0)
{
CMemory_C4RAM[0x1f80]=byte>>2;
}
else
{
switch (byte)
{
case 0x00: // Sprite
S9xC4ProcessSprites();
break;
case 0x01: // Draw wireframe
memset(CMemory_C4RAM+0x300, 0, 16*12*3*4);
C4DrawWireFrame();
break;
case 0x05: // Propulsion (?)
{
int32 tmp=0x10000;
if(READ_WORD(CMemory_C4RAM+0x1f83)){
tmp=SAR((tmp/READ_WORD(CMemory_C4RAM+0x1f83))*READ_WORD(CMemory_C4RAM+0x1f81), 8);
}
WRITE_WORD(CMemory_C4RAM+0x1f80, (uint16)tmp);
}
break;
case 0x0d: // Set vector length
C41FXVal=READ_WORD(CMemory_C4RAM+0x1f80);
C41FYVal=READ_WORD(CMemory_C4RAM+0x1f83);
C41FDistVal=READ_WORD(CMemory_C4RAM+0x1f86);
C4Op0D();
WRITE_WORD(CMemory_C4RAM+0x1f89, C41FXVal);
WRITE_WORD(CMemory_C4RAM+0x1f8c, C41FYVal);
break;
case 0x10: // Polar to rectangluar
{
int32 tmp=SAR((int32)READ_WORD(CMemory_C4RAM+0x1f83)*C4CosTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]<<1, 16);
WRITE_3WORD(CMemory_C4RAM+0x1f86, tmp);
tmp=SAR((int32)READ_WORD(CMemory_C4RAM+0x1f83)*C4SinTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]<<1, 16);
WRITE_3WORD(CMemory_C4RAM+0x1f89, (tmp-SAR(tmp, 6)));
}
break;
case 0x13: // Polar to rectangluar
{
int32 tmp=SAR((int32)READ_WORD(CMemory_C4RAM+0x1f83)*C4CosTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]<<1, 8);
WRITE_3WORD(CMemory_C4RAM+0x1f86, tmp);
tmp=SAR((int32)READ_WORD(CMemory_C4RAM+0x1f83)*C4SinTable[READ_WORD(CMemory_C4RAM+0x1f80)&0x1ff]<<1, 8);
WRITE_3WORD(CMemory_C4RAM+0x1f89, tmp);
}
break;
case 0x15: // Pythagorean
C41FXVal=READ_WORD(CMemory_C4RAM+0x1f80);
C41FYVal=READ_WORD(CMemory_C4RAM+0x1f83);
C41FDist=(int16)sqrt((double)C41FXVal*C41FXVal + (double)C41FYVal*C41FYVal);
WRITE_WORD(CMemory_C4RAM+0x1f80, C41FDist);
break;
case 0x1f: // atan
C41FXVal=READ_WORD(CMemory_C4RAM+0x1f80);
C41FYVal=READ_WORD(CMemory_C4RAM+0x1f83);
C4Op1F();
WRITE_WORD(CMemory_C4RAM+0x1f86, C41FAngleRes);
break;
case 0x22: // Trapezoid
{
int16 angle1=READ_WORD(CMemory_C4RAM+0x1f8c)&0x1ff;
int16 angle2=READ_WORD(CMemory_C4RAM+0x1f8f)&0x1ff;
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(CMemory_C4RAM+0x1f83) - READ_WORD(CMemory_C4RAM+0x1f89);
int16 left, right;
for(int j=0; j<225; j++)
{
if(y>=0)
{
left = SAR((int32)tan1*y, 16) -
READ_WORD(CMemory_C4RAM+0x1f80) +
READ_WORD(CMemory_C4RAM+0x1f86);
right = SAR((int32)tan2*y, 16) -
READ_WORD(CMemory_C4RAM+0x1f80) +
READ_WORD(CMemory_C4RAM+0x1f86) +
READ_WORD(CMemory_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;
}
CMemory_C4RAM[j+0x800] = (uint8)left;
CMemory_C4RAM[j+0x900] = (uint8)right;
y++;
}
}
break;
case 0x25: // Multiply
{
int32 foo=READ_3WORD(CMemory_C4RAM+0x1f80);
int32 bar=READ_3WORD(CMemory_C4RAM+0x1f83);
foo*=bar;
WRITE_3WORD(CMemory_C4RAM+0x1f80, foo);
}
break;
case 0x2d: // Transform Coords
C4WFXVal=READ_WORD(CMemory_C4RAM+0x1f81);
C4WFYVal=READ_WORD(CMemory_C4RAM+0x1f84);
C4WFZVal=READ_WORD(CMemory_C4RAM+0x1f87);
C4WFX2Val=CMemory_C4RAM[0x1f89];
C4WFY2Val=CMemory_C4RAM[0x1f8a];
C4WFDist=CMemory_C4RAM[0x1f8b];
C4WFScale=READ_WORD(CMemory_C4RAM+0x1f90);
C4TransfWireFrame2();
WRITE_WORD(CMemory_C4RAM+0x1f80, C4WFXVal);
WRITE_WORD(CMemory_C4RAM+0x1f83, C4WFYVal);
break;
case 0x40: // Sum
{
uint16 sum=0;
for(int i=0; i<0x800; sum+=CMemory_C4RAM[i++]);
WRITE_WORD(CMemory_C4RAM+0x1f80, sum);
}
break;
case 0x54: // Square
{
int64 a=SAR((int64)READ_3WORD(CMemory_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(CMemory_C4RAM+0x1f83, a);
WRITE_3WORD(CMemory_C4RAM+0x1f86, (a>>24));
}
break;
case 0x5c: // Immediate Reg
for (i = 0; i < 12 * 4; i++)
CMemory_C4RAM [i] = C4TestPattern [i];
break;
case 0x89: // Immediate ROM
CMemory_C4RAM [0x1f80] = 0x36;
CMemory_C4RAM [0x1f81] = 0x43;
CMemory_C4RAM [0x1f82] = 0x05;
break;
default:
break;
}
}
} else if (Address == 0x7f47) {
memmove(CMemory_C4RAM+(READ_WORD(CMemory_C4RAM+0x1f45)&0x1fff),
S9xGetMemPointer(READ_3WORD(CMemory_C4RAM+0x1f40)),
READ_WORD(CMemory_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
};
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#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)
{
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;
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);
uint32 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);
*_address=address;
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)))
#define _CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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) &&
_CC_(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]);
}
}
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "snes9x.h"
#include "cheats.h"
#include "memmap.h"
extern SCheatData Cheat;
void S9xInitCheatData ()
{
Cheat.RAM = CMemory_RAM;
Cheat.SRAM = CMemory_SRAM;
Cheat.FillRAM = CMemory_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;
Cheat.c [Cheat.num_cheats].enabled = TRUE;
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 >> MEMMAP_SHIFT) & MEMMAP_MASK;
uint8 *ptr = CMemory_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 >> MEMMAP_SHIFT) & MEMMAP_MASK;
uint8 *ptr = CMemory_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);
}
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#include <stdlib.h>
#include "snes9x.h"
#include "memmap.h"
#include "ppu.h"
struct Band
{
uint32 Left;
uint32 Right;
};
#undef MIN
#undef MAX
#define MIN(A,B) ((A) < (B) ? (A) : (B))
#define MAX(A,B) ((A) > (B) ? (A) : (B))
#define BAND_EMPTY(B) (B.Left >= B.Right)
#define BANDS_INTERSECT(A,B) ((A.Left >= B.Left && A.Left < B.Right) || \
(B.Left >= A.Left && B.Left < A.Right))
#define OR_BANDS(R,A,B) {\
R.Left = MIN(A.Left, B.Left); \
R.Right = MAX(A.Right, B.Right);}
#define AND_BANDS(R,A,B) {\
R.Left = MAX(A.Left, B.Left); \
R.Right = MIN(A.Right, B.Right);}
static int IntCompare (const void *d1, const void *d2)
{
if (*(uint32 *) d1 > *(uint32 *) d2)
return (1);
else
if (*(uint32 *) d1 < *(uint32 *) d2)
return (-1);
return (0);
}
static int BandCompare (const void *d1, const void *d2)
{
if (((struct Band *) d1)->Left > ((struct Band *) d2)->Left)
return (1);
else
if (((struct Band *) d1)->Left < ((struct Band *) d2)->Left)
return (-1);
return (0);
}
void ComputeClipWindows ()
{
struct ClipData *pClip = &IPPU.Clip [0];
// Loop around the main screen then the sub-screen.
for (int c = 0; c < 2; c++, pClip++)
{
// Loop around the colour window then a clip window for each of the
// background layers.
for (int w = 5; w >= 0; w--)
{
pClip->Count[w] = 0;
if (w == 5) // The colour window...
{
if (c == 0) // ... on the main screen
{
if ((CMemory_FillRAM [0x2130] & 0xc0) == 0xc0)
{
// The whole of the main screen is switched off,
// completely clip everything.
for (int i = 0; i < 6; i++)
{
IPPU.Clip [c].Count [i] = 1;
IPPU.Clip [c].Left [0][i] = 1;
IPPU.Clip [c].Right [0][i] = 0;
}
continue;
}
else
if ((CMemory_FillRAM [0x2130] & 0xc0) == 0x00)
continue;
}
else
{
// .. colour window on the sub-screen.
if ((CMemory_FillRAM [0x2130] & 0x30) == 0x30)
{
// The sub-screen is switched off, completely
// clip everything.
for (int i = 0; i < 6; i++)
{
IPPU.Clip [1].Count [i] = 1;
IPPU.Clip [1].Left [0][i] = 1;
IPPU.Clip [1].Right [0][i] = 0;
}
return;
}
else
if ((CMemory_FillRAM [0x2130] & 0x30) == 0x00)
continue;
}
}
#ifdef ENABLE_GRAPHIC_WINDOWS
if (w == 5 || pClip->Count [5] ||
(CMemory_FillRAM [0x212c + c] &
CMemory_FillRAM [0x212e + c] & (1 << w)))
{
struct Band Win1[3];
struct Band Win2[3];
uint32 Window1Enabled = 0;
uint32 Window2Enabled = 0;
bool8 invert = (w == 5 &&
((c == 1 && (CMemory_FillRAM [0x2130] & 0x30) == 0x10) ||
(c == 0 && (CMemory_FillRAM [0x2130] & 0xc0) == 0x40)));
if (w == 5 ||
(CMemory_FillRAM [0x212c + c] & CMemory_FillRAM [0x212e + c] & (1 << w)))
{
if (PPU.ClipWindow1Enable [w])
{
if (!PPU.ClipWindow1Inside [w])
{
Win1[Window1Enabled].Left = PPU.Window1Left;
Win1[Window1Enabled++].Right = PPU.Window1Right + 1;
}
else
{
if (PPU.Window1Left <= PPU.Window1Right)
{
if (PPU.Window1Left > 0)
{
Win1[Window1Enabled].Left = 0;
Win1[Window1Enabled++].Right = PPU.Window1Left;
}
if (PPU.Window1Right < 255)
{
Win1[Window1Enabled].Left = PPU.Window1Right + 1;
Win1[Window1Enabled++].Right = 256;
}
if (Window1Enabled == 0)
{
Win1[Window1Enabled].Left = 1;
Win1[Window1Enabled++].Right = 0;
}
}
else
{
// 'outside' a window with no range -
// appears to be the whole screen.
Win1[Window1Enabled].Left = 0;
Win1[Window1Enabled++].Right = 256;
}
}
}
if (PPU.ClipWindow2Enable [w])
{
if (!PPU.ClipWindow2Inside [w])
{
Win2[Window2Enabled].Left = PPU.Window2Left;
Win2[Window2Enabled++].Right = PPU.Window2Right + 1;
}
else
{
if (PPU.Window2Left <= PPU.Window2Right)
{
if (PPU.Window2Left > 0)
{
Win2[Window2Enabled].Left = 0;
Win2[Window2Enabled++].Right = PPU.Window2Left;
}
if (PPU.Window2Right < 255)
{
Win2[Window2Enabled].Left = PPU.Window2Right + 1;
Win2[Window2Enabled++].Right = 256;
}
if (Window2Enabled == 0)
{
Win2[Window2Enabled].Left = 1;
Win2[Window2Enabled++].Right = 0;
}
}
else
{
Win2[Window2Enabled].Left = 0;
Win2[Window2Enabled++].Right = 256;
}
}
}
}
if (Window1Enabled && Window2Enabled)
{
// Overlap logic
//
// Each window will be in one of three states:
// 1. <no range> (Left > Right. One band)
// 2. | ---------------- | (Left >= 0, Right <= 255, Left <= Right. One band)
// 3. |------------ ----------| (Left1 == 0, Right1 < Left2; Left2 > Right1, Right2 == 255. Two bands)
struct Band Bands [6];
int B = 0;
switch (PPU.ClipWindowOverlapLogic [w] ^ 1)
{
case CLIP_OR:
if (Window1Enabled == 1)
{
if (BAND_EMPTY(Win1[0]))
{
B = Window2Enabled;
memmove (Bands, Win2,
sizeof(Win2[0]) * Window2Enabled);
}
else
{
if (Window2Enabled == 1)
{
if (BAND_EMPTY (Win2[0]))
Bands[B++] = Win1[0];
else
{
if (BANDS_INTERSECT (Win1[0], Win2[0]))
{
OR_BANDS(Bands[0],Win1[0], Win2[0])
B = 1;
}
else
{
Bands[B++] = Win1[0];
Bands[B++] = Win2[0];
}
}
}
else
{
if (BANDS_INTERSECT(Win1[0], Win2[0]))
{
OR_BANDS(Bands[0], Win1[0], Win2[0])
if (BANDS_INTERSECT(Win1[0], Win2[1]))
OR_BANDS(Bands[1], Win1[0], Win2[1])
else
Bands[1] = Win2[1];
B = 1;
if (BANDS_INTERSECT(Bands[0], Bands[1]))
OR_BANDS(Bands[0], Bands[0], Bands[1])
else
B = 2;
}
else
if (BANDS_INTERSECT(Win1[0], Win2[1]))
{
Bands[B++] = Win2[0];
OR_BANDS(Bands[B], Win1[0], Win2[1]);
B++;
}
else
{
Bands[0] = Win2[0];
Bands[1] = Win1[0];
Bands[2] = Win2[1];
B = 3;
}
}
}
}
else
if (Window2Enabled == 1)
{
if (BAND_EMPTY(Win2[0]))
{
// Window 2 defines an empty range - just
// use window 1 as the clipping (which
// could also be empty).
B = Window1Enabled;
memmove (Bands, Win1,
sizeof(Win1[0]) * Window1Enabled);
}
else
{
// Window 1 has two bands and Window 2 has one.
// Neither is an empty region.
if (BANDS_INTERSECT(Win2[0], Win1[0]))
{
OR_BANDS(Bands[0], Win2[0], Win1[0])
if (BANDS_INTERSECT(Win2[0], Win1[1]))
OR_BANDS(Bands[1], Win2[0], Win1[1])
else
Bands[1] = Win1[1];
B = 1;
if (BANDS_INTERSECT(Bands[0], Bands[1]))
OR_BANDS(Bands[0], Bands[0], Bands[1])
else
B = 2;
}
else
if (BANDS_INTERSECT(Win2[0], Win1[1]))
{
Bands[B++] = Win1[0];
OR_BANDS(Bands[B], Win2[0], Win1[1]);
B++;
}
else
{
Bands[0] = Win1[0];
Bands[1] = Win2[0];
Bands[2] = Win1[1];
B = 3;
}
}
}
else
{
// Both windows have two bands
OR_BANDS(Bands[0], Win1[0], Win2[0]);
OR_BANDS(Bands[1], Win1[1], Win2[1]);
B = 1;
if (BANDS_INTERSECT(Bands[0], Bands[1]))
OR_BANDS(Bands[0], Bands[0], Bands[1])
else
B = 2;
}
break;
case CLIP_AND:
if (Window1Enabled == 1)
{
// Window 1 has one band
if (BAND_EMPTY(Win1[0]))
Bands [B++] = Win1[0];
else
if (Window2Enabled == 1)
{
if (BAND_EMPTY (Win2[0]))
Bands [B++] = Win2[0];
else
{
AND_BANDS(Bands[0], Win1[0], Win2[0]);
B = 1;
}
}
else
{
AND_BANDS(Bands[0], Win1[0], Win2[0]);
AND_BANDS(Bands[1], Win1[0], Win2[1]);
B = 2;
}
}
else
if (Window2Enabled == 1)
{
if (BAND_EMPTY(Win2[0]))
Bands[B++] = Win2[0];
else
{
// Window 1 has two bands.
AND_BANDS(Bands[0], Win1[0], Win2[0]);
AND_BANDS(Bands[1], Win1[1], Win2[0]);
B = 2;
}
}
else
{
// Both windows have two bands.
AND_BANDS(Bands[0], Win1[0], Win2[0]);
AND_BANDS(Bands[1], Win1[1], Win2[1]);
B = 2;
if (BANDS_INTERSECT(Win1[0], Win2[1]))
{
AND_BANDS(Bands[2], Win1[0], Win2[1]);
B = 3;
}
else
if (BANDS_INTERSECT(Win1[1], Win2[0]))
{
AND_BANDS(Bands[2], Win1[1], Win2[0]);
B = 3;
}
}
break;
case CLIP_XNOR:
invert = !invert;
// Fall...
case CLIP_XOR:
if (Window1Enabled == 1 && BAND_EMPTY(Win1[0]))
{
B = Window2Enabled;
memmove (Bands, Win2,
sizeof(Win2[0]) * Window2Enabled);
}
else
if (Window2Enabled == 1 && BAND_EMPTY(Win2[0]))
{
B = Window1Enabled;
memmove (Bands, Win1,
sizeof(Win1[0]) * Window1Enabled);
}
else
{
uint32 p = 0;
uint32 points [10];
uint32 i;
invert = !invert;
// Build an array of points (window edges)
points [p++] = 0;
for (i = 0; i < Window1Enabled; i++)
{
points [p++] = Win1[i].Left;
points [p++] = Win1[i].Right;
}
for (i = 0; i < Window2Enabled; i++)
{
points [p++] = Win2[i].Left;
points [p++] = Win2[i].Right;
}
points [p++] = 256;
// Sort them
qsort ((void *) points, p, sizeof (points [0]),
IntCompare);
for (i = 0; i < p; i += 2)
{
if (points [i] == points [i + 1])
continue;
Bands [B].Left = points [i];
while (i + 2 < p &&
points [i + 1] == points [i + 2])
{
i += 2;
}
Bands [B++].Right = points [i + 1];
}
}
break;
}
if (invert)
{
int b;
int j = 0;
int empty_band_count = 0;
// First remove all empty bands from the list.
for (b = 0; b < B; b++)
{
if (!BAND_EMPTY(Bands[b]))
{
if (b != j)
Bands[j] = Bands[b];
j++;
}
else
empty_band_count++;
}
if (j > 0)
{
if (j == 1)
{
j = 0;
// Easy case to deal with, so special case it.
if (Bands[0].Left > 0)
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = Bands[0].Left + 1;
}
if (Bands[0].Right < 256)
{
pClip->Left[j][w] = Bands[0].Right;
pClip->Right[j++][w] = 256;
}
if (j == 0)
{
pClip->Left[j][w] = 1;
pClip->Right[j++][w] = 0;
}
}
else
{
// Now sort the bands into order
B = j;
qsort ((void *) Bands, B,
sizeof (Bands [0]), BandCompare);
// Now invert the area the bands cover
j = 0;
for (b = 0; b < B; b++)
{
if (b == 0 && Bands[b].Left > 0)
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = Bands[b].Left + 1;
}
else
if (b == B - 1 && Bands[b].Right < 256)
{
pClip->Left[j][w] = Bands[b].Right;
pClip->Right[j++][w] = 256;
}
if (b < B - 1)
{
pClip->Left[j][w] = Bands[b].Right;
pClip->Right[j++][w] = Bands[b + 1].Left + 1;
}
}
}
}
else
{
// Inverting a window that consisted of only
// empty bands is the whole width of the screen.
// Needed for Mario Kart's rear-view mirror display.
if (empty_band_count)
{
pClip->Left[j][w] = 0;
pClip->Right[j][w] = 256;
j++;
}
}
pClip->Count[w] = j;
}
else
{
for (int j = 0; j < B; j++)
{
pClip->Left[j][w] = Bands[j].Left;
pClip->Right[j][w] = Bands[j].Right;
}
pClip->Count [w] = B;
}
}
else
{
// Only one window enabled so no need to perform
// complex overlap logic...
if (Window1Enabled)
{
if (invert)
{
int j = 0;
if (Window1Enabled == 1)
{
if (Win1[0].Left <= Win1[0].Right)
{
if (Win1[0].Left > 0)
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = Win1[0].Left;
}
if (Win1[0].Right < 256)
{
pClip->Left[j][w] = Win1[0].Right;
pClip->Right[j++][w] = 256;
}
if (j == 0)
{
pClip->Left[j][w] = 1;
pClip->Right[j++][w] = 0;
}
}
else
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = 256;
}
}
else
{
pClip->Left [j][w] = Win1[0].Right;
pClip->Right[j++][w] = Win1[1].Left;
}
pClip->Count [w] = j;
}
else
{
for (uint32 j = 0; j < Window1Enabled; j++)
{
pClip->Left [j][w] = Win1[j].Left;
pClip->Right [j][w] = Win1[j].Right;
}
pClip->Count [w] = Window1Enabled;
}
}
else
if (Window2Enabled)
{
if (invert)
{
int j = 0;
if (Window2Enabled == 1)
{
if (Win2[0].Left <= Win2[0].Right)
{
if (Win2[0].Left > 0)
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = Win2[0].Left;
}
if (Win2[0].Right < 256)
{
pClip->Left[j][w] = Win2[0].Right;
pClip->Right[j++][w] = 256;
}
if (j == 0)
{
pClip->Left[j][w] = 1;
pClip->Right[j++][w] = 0;
}
}
else
{
pClip->Left[j][w] = 0;
pClip->Right[j++][w] = 256;
}
}
else
{
pClip->Left [j][w] = Win2[0].Right;
pClip->Right[j++][w] = Win2[1].Left + 1;
}
pClip->Count [w] = j;
}
else
{
for (uint32 j = 0; j < Window2Enabled; j++)
{
pClip->Left [j][w] = Win2[j].Left;
pClip->Right [j][w] = Win2[j].Right;
}
pClip->Count [w] = Window2Enabled;
}
}
}
if (w != 5 && pClip->Count [5])
{
// Colour window enabled. Set the
// clip windows for all remaining backgrounds to be
// the same as the colour window.
if (pClip->Count [w] == 0)
{
pClip->Count [w] = pClip->Count [5];
for (uint32 i = 0; i < pClip->Count [w]; i++)
{
pClip->Left [i][w] = pClip->Left [i][5];
pClip->Right [i][w] = pClip->Right [i][5];
}
}
else
{
// Intersect the colour window with the bg's
// own clip window.
for (uint32 i = 0; i < pClip->Count [w]; i++)
{
uint32 j;
for (j = 0; j < pClip->Count [5]; j++)
{
if((pClip->Left[i][w] >= pClip->Left[j][5] && pClip->Left[i][w] < pClip->Right[j][5]) || (pClip->Left[j][5] >= pClip->Left[i][w] && pClip->Left[j][5] < pClip->Right[i][w])){
// Found an intersection!
pClip->Left[i][w]=MAX(pClip->Left[i][w], pClip->Left[j][5]);
pClip->Right[i][w]=MIN(pClip->Right[i][w], pClip->Right[j][5]);
goto Clip_ok;
}
}
// no intersection, nullify it
pClip->Left[i][w]=1;
pClip->Right[i][w]=0;
Clip_ok:
j=0; // dummy statement
}
}
}
} // if (w == 5 | ...
#endif
} // for (int w...
} // for (int c...
}
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#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"
#include "cheats.h"
#include "srtc.h"
#include "sdd1.h"
#include "spc7110.h"
#include "obc1.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;
FxReset (&SuperFX);
}
#endif
void S9xResetCPU ()
{
Registers.PB = 0;
Registers.PC = S9xGetWord (0xFFFC);
Registers.D.W = 0;
Registers.DB = 0;
Registers.SH = 1;
Registers.SL = 0xFF;
Registers.XH = 0;
Registers.YH = 0;
Registers.P.W = 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 = FALSE;
CPU.WhichEvent = HBLANK_START_EVENT;
CPU.PC = NULL;
CPU.PCBase = NULL;
CPU.PCAtOpcodeStart = NULL;
CPU.WaitAddress = NULL;
CPU.WaitCounter = 0;
CPU.Cycles = 0;
CPU.NextEvent = Settings.HBlankStart;
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.NMITriggerPoint = 4; // Set when ROM image loaded
CPU.BRKTriggered = FALSE;
//CPU.TriedInterleavedMode2 = FALSE; // Reset when ROM image loaded
CPU.NMICycleCount = 0;
CPU.IRQCycleCount = 0;
S9xSetPCBase (Registers.PC);
ICPU.S9xOpcodes = S9xOpcodesE1;
ICPU.CPUExecuting = TRUE;
S9xUnpackStatus();
}
#ifdef ZSNES_FX
START_EXTERN_C
void S9xResetSuperFX ();
bool8 WinterGold = 0;
extern uint8 *C4Ram;
END_EXTERN_C
#endif
#ifdef USE_MMU
void set_mmu_mappings(void);
#endif
void S9xReset (void)
{
#ifdef USE_MMU
set_mmu_mappings();
#endif
if (Settings.SuperFX)
S9xResetSuperFX ();
#ifdef ZSNES_FX
WinterGold = Settings.WinterGold;
#endif
ZeroMemory (CMemory_FillRAM, 0x8000);
memset (CMemory_VRAM, 0x00, 0x10000);
memset (CMemory_RAM, 0x55, 0x20000);
#ifdef USE_MMU
dcache_flush_range((unsigned)&CMemory_FillRAM[0],0x8000);
dcache_flush_range((unsigned)&CMemory_VRAM[0],0x10000);
dcache_flush_range((unsigned)&CMemory_RAM[0],0x20000);
memcpy((void *)0x7e0000,(void *)&CMemory_RAM[0],0x20000);
#endif
if(Settings.SPC7110)
S9xSpc7110Reset();
S9xResetCPU ();
S9xResetPPU ();
S9xResetSRTC ();
if (Settings.SDD1)
S9xResetSDD1 ();
S9xResetDMA ();
S9xResetAPU ();
S9xResetDSP1 ();
S9xSA1Init ();
if (Settings.C4)
S9xInitC4 ();
S9xInitCheatData ();
if(Settings.OBC1)
ResetOBC1();
// Settings.Paused = FALSE;
#ifdef USE_MMU
// set_mmu_mappings();
#endif
}
void S9xSoftReset (void)
{
#ifdef USE_MMU
set_mmu_mappings();
#endif
if (Settings.SuperFX)
S9xResetSuperFX ();
#ifdef ZSNES_FX
WinterGold = Settings.WinterGold;
#endif
ZeroMemory (CMemory_FillRAM, 0x8000);
memset (CMemory_VRAM, 0x00, 0x10000);
// memset (CMemory_RAM, 0x55, 0x20000);
#ifdef USE_MMU
dcache_flush_range((unsigned)&CMemory_FillRAM[0],0x8000);
dcache_flush_range((unsigned)&CMemory_VRAM[0],0x10000);
dcache_flush_range((unsigned)&CMemory_RAM[0],0x20000);
memcpy((void *)0x7e0000,(void *)&CMemory_RAM[0],0x20000);
#endif
if(Settings.SPC7110)
S9xSpc7110Reset();
S9xResetCPU ();
S9xSoftResetPPU ();
S9xResetSRTC ();
if (Settings.SDD1)
S9xResetSDD1 ();
S9xResetDMA ();
S9xResetAPU ();
S9xResetDSP1 ();
if(Settings.OBC1)
ResetOBC1();
S9xSA1Init ();
if (Settings.C4)
S9xInitC4 ();
S9xInitCheatData ();
// Settings.Paused = FALSE;
#ifdef USE_MMU
// set_mmu_mappings();
#endif
}
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
#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 "fxemu.h"
#include "sa1.h"
#include "spc7110.h"
#include "snes4all.h"
extern "C" void S9xSaveStateProcess();
#ifdef DEBUG_CPU
extern int cpu_debugging;
#endif
#ifndef USE_OPC_ASM_MIXTO
void S9xMainLoop (void)
{
for (;;)
{
#ifdef DEBUG_MAXCOUNT
CPU.GlobalLoopCount++;
if(Settings.MaxCount && CPU.GlobalLoopCount == Settings.MaxCount) {
fprintf(stderr, "Max loop count reached: %ld \n", Settings.MaxCount);
S9xExit();
}
#endif
#ifdef USE_ALWAYS_APU_SYNC
APU_EXECUTE ();
#else
if (snes4all_sound_enable>1) {
APU_EXECUTE ();
}
#endif
if (CPU.Flags)
{
if (CPU.Flags & NMI_FLAG)
{
if (--CPU.NMICycleCount == 0)
{
CPU.Flags &= ~NMI_FLAG;
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
CPU.PC++;
}
S9xOpcode_NMI ();
}
}
CHECK_SOUND ();
if (CPU.Flags & IRQ_PENDING_FLAG)
{
if (CPU.IRQCycleCount == 0)
{
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = FALSE;
CPU.PC++;
}
if (CPU.IRQActive && !Settings.DisableIRQ)
{
if (!CheckFlag (IRQ))
S9xOpcode_IRQ ();
}
else
CPU.Flags &= ~IRQ_PENDING_FLAG;
}
else
{
if(--CPU.IRQCycleCount==0 && CheckFlag (IRQ))
CPU.IRQCycleCount=1;
}
}
}
#ifdef DEBUG_CPU
if (cpu_debugging)
puts("/");
#endif
{
unsigned timeslice=snes4all_timeslice;
if (CPU.Flags) timeslice=1;
while(timeslice--) {
#ifdef CPU_SHUTDOWN
CPU.PCAtOpcodeStart = CPU.PC;
#endif
#ifdef USE_MEMORY_SPEED
CPU.Cycles += CPU.MemSpeed;
#else
CPU.Cycles += 8;
#endif
#ifdef DEBUG_CPU
if (cpu_debugging) {
S9xPackStatus ();
printf("PC=%.4X, Opcode=%.2X %s\n",CPU.PC - CPU.PCBase,*CPU.PC,ICPU.S9xOpcodes==S9xOpcodesE1?"E1":ICPU.S9xOpcodes==S9xOpcodesM1X1?"M1X1":ICPU.S9xOpcodes==S9xOpcodesM1X0?"M1X0":ICPU.S9xOpcodes==S9xOpcodesM0X0?"M0X0":ICPU.S9xOpcodes==S9xOpcodesM0X1?"M0X1":"???");
printf("\tPB=%.2X DB=%.2X P=%.4X A=%.4X D=%.4X S=%.4X X=%.4X Y=%.4X\n",Registers.PB,Registers.DB,Registers.P.W,Registers.A.W,Registers.D.W,Registers.S.W,Registers.X.W,Registers.Y.W);
}
#endif
(*ICPU.S9xOpcodes [*CPU.PC++].S9xOpcode) ();
#ifdef DEBUG_CPU
if (cpu_debugging)
puts(".");
#endif
}
}
#ifdef DEBUG_CPU
if (cpu_debugging)
puts("\\");
#endif
if (SA1.Executing) {
#ifdef DEBUG_CPU
if (cpu_debugging) {
// S9xSA1PackStatus();
printf("/SA1 PC=%.4X, Opcode=%.2X %s\n",SA1.PC - SA1.PCBase,*SA1.PC,SA1.S9xOpcodes==S9xSA1OpcodesM1X1?"M1X1":SA1.S9xOpcodes==S9xSA1OpcodesM1X0?"M1X0":SA1.S9xOpcodes==S9xSA1OpcodesM0X0?"M0X0":SA1.S9xOpcodes==S9xSA1OpcodesM0X1?"M0X1":"???");
printf("\tPB=%.2X DB=%.2X P=%.4X A=%.4X D=%.4X S=%.4X X=%.4X Y=%.4X\n",SA1Registers.PB,SA1Registers.DB,SA1Registers.P.W,SA1Registers.A.W,SA1Registers.D.W,SA1Registers.S.W,SA1Registers.X.W,SA1Registers.Y.W);
}
#endif
S9xSA1MainLoop ();
#ifdef DEBUG_CPU
if (cpu_debugging)
printf("SA1\\ PC=%.4X\n",SA1.PC - SA1.PCBase);
#endif
}
DO_HBLANK_CHECK();
}
}
void S9xSetIRQ (uint32 source)
{
CPU.IRQActive |= source;
CPU.Flags |= IRQ_PENDING_FLAG;
CPU.IRQCycleCount = 3;
if (CPU.WaitingForInterrupt)
{
// Force IRQ to trigger immediately after WAI -
// Final Fantasy Mystic Quest crashes without this.
CPU.IRQCycleCount = 0;
CPU.WaitingForInterrupt = FALSE;
CPU.PC++;
}
}
void S9xClearIRQ (uint32 source)
{
CLEAR_IRQ_SOURCE (source);
}
void S9xDoHBlankProcessing ()
{
snes4all_prof_start(1);
#ifdef CPU_SHUTDOWN
CPU.WaitCounter++;
#endif
#ifndef USE_OPC_ASM_MIXTO
S9xUpdateAPUTimer();
#endif
switch (CPU.WhichEvent)
{
case HBLANK_START_EVENT:
// .hblank_start:
if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
IPPU.HDMA = S9xDoHDMA (IPPU.HDMA);
break;
case HBLANK_END_EVENT:
// .hblank_end:
S9xSuperFXExec ();
#ifndef USE_SOUND_DESYNC
{
static int valor=0;
valor++;
if (valor>=snes4all_sound_throttle) {
S9xGenerateSound ();
valor=0;
}
}
#endif
CPU.Cycles -= Settings.H_Max;
IAPU.NextAPUTimerPos -= snes4all_apu_hmax;
if (IAPU.APUExecuting)
{
APU.Cycles -= Settings.H_Max;
#ifdef MK_APU
S9xCatchupCount();
#endif
}
else
APU.Cycles = 0;
CPU.NextEvent = -1;
ICPU.Scanline++;
CPU.V_Counter=snes4all_vcounter[CPU.V_Counter];
if (CPU.V_Counter >= snes4all_max_vcounter)
{
#ifdef USE_OLD_SYNC_SPEED
CPU.V_Counter = 0;
CMemory_FillRAM[0x213F]^=0x80;
PPU.RangeTimeOver = 0;
CPU.NMIActive = FALSE;
ICPU.Frame++;
PPU.HVBeamCounterLatched = 0;
#endif
S9xSyncSpeed ();
}
else
// L162:
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE)
{
// Start of V-blank
S9xEndScreenRefresh ();
#ifdef USE_OLD_END_REFRESH
IPPU.HDMA = 0;
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
IPPU.MaxBrightness = PPU.Brightness;
PPU.ForcedBlanking = (CMemory_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;
}
CMemory_FillRAM[0x4210] = 0x80 |Model->_5A22;
if (CMemory_FillRAM[0x4200] & 0x80)
{
CPU.NMIActive = TRUE;
CPU.Flags |= NMI_FLAG;
CPU.NMICycleCount = CPU.NMITriggerPoint;
}
#endif
#ifdef OLD_SNAPSHOT_CODE
if (CPU.Flags & SAVE_SNAPSHOT_FLAG)
{
CPU.Flags &= ~SAVE_SNAPSHOT_FLAG;
Registers.PC = CPU.PC - CPU.PCBase;
S9xPackStatus ();
S9xAPUPackStatus ();
Snapshot (NULL);
}
#else
{
extern int savestate_state;
if (savestate_state)
S9xSaveStateProcess();
}
#endif
}
// L161:
if (PPU.VTimerEnabled && !PPU.HTimerEnabled &&
CPU.V_Counter == PPU.IRQVBeamPos)
{
// L163:
S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE);
}
// L165:
if (CPU.V_Counter == FIRST_VISIBLE_LINE)
{
#ifdef USE_OLD_START_REFRESH
S9xUpdateJoypads ();
CMemory_FillRAM[0x4210] = Model->_5A22;
CPU.Flags &= ~NMI_FLAG;
#endif
S9xStartScreenRefresh ();
}
// L177:
if (CPU.V_Counter >= FIRST_VISIBLE_LINE &&
CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE)
{
RenderLine (CPU.V_Counter - FIRST_VISIBLE_LINE);
}
break;
case HTIMER_BEFORE_EVENT:
case HTIMER_AFTER_EVENT:
if (PPU.HTimerEnabled &&
(!PPU.VTimerEnabled || CPU.V_Counter == PPU.IRQVBeamPos))
{
S9xSetIRQ (PPU_H_BEAM_IRQ_SOURCE);
}
break;
}
S9xReschedule ();
#ifdef DEBUG_CPU
if (cpu_debugging) {
printf("HSYNC, APU Cyles=%u, PC=%.4X\n\tS=%.2X, X=%.2X, P=%.2X, A=%.2X, Y=%.2X\n",APU.Cycles,APURegisters.PC,APURegisters.S,APURegisters.X,APURegisters.P,APURegisters.YA.B.A,APURegisters.YA.B.Y);
}
#endif
snes4all_prof_end(1);
}
#endif // USE_OPC_ASM_MIXTO
/*******************************************************************************
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 2001 - 2004 John Weidman (jweidman@slip.net)
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
funkyass (funkyass@spam.shaw.ca),
Joel Yliluoma (http://iki.fi/bisqwit/)
Kris Bleakley (codeviolation@hotmail.com),
Matthew Kendora,
Nach (n-a-c-h@users.sourceforge.net),
Peter Bortas (peter@bortas.org) and
zones (kasumitokoduck@yahoo.com)
C4 x86 assembler and some C emulation code
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
_Demo_ (_demo_@zsnes.com), and Nach
C4 C++ code
(c) Copyright 2003 Brad Jorsch
DSP-1 emulator code
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
John Weidman, neviksti (neviksti@hotmail.com),
Kris Bleakley, Andreas Naive
DSP-2 emulator code
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
Lord Nightmare (lord_nightmare@users.sourceforge.net
OBC1 emulator code
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
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, and Dark Force
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
S-RTC C emulator code
(c) Copyright 2001 John Weidman
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
Super FX x86 assembler emulator code
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
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 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.
*******************************************************************************/
/*****************************************************************************/
/* CPU-S9xOpcodes.CPP */
/* This file contains all the opcodes */
/*****************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#include "debug.h"
#include "missing.h"
#include "apu.h"
#include "sa1.h"
#include "spc7110.h"
#include "dsp1.h"
START_EXTERN_C
extern uint8 A1, A2, A3, A4, W1, W2, W3, W4;
extern uint8 Ans8;
extern uint16 Ans16;
extern uint32 Ans32;
extern uint8 Work8;
extern uint16 Work16;
extern uint32 Work32;
extern signed char Int8;
extern short Int16;
extern long Int32;
END_EXTERN_C
#ifdef USE_MEMORY_SPEED
#define MEMSPEED CPU.MemSpeed
#define MEM2XSPEED CPU.MemSpeed2x
#else
#define MEMSPEED 8
#define MEM2XSPEED 16
#endif
#include "cpuexec.h"
#include "cpuaddr.h"
#include "cpuops.h"
#include "cpumacro.h"
#include "apu.h"
//#if defined(ZSNES_FX) || !defined(USE_OPC_ASM)
#if 1
/* ADC *************************************************************************************** */
static void Op69M1 (void)
{
Immediate8 (READ);
ADC8 ();
}
static void Op69M0 (void)
{
Immediate16 (READ);
ADC16 ();
}
static void Op65M1 (void)
{
Direct (READ);
ADC8 ();
}
static void Op65M0 (void)
{
Direct (READ);
ADC16 ();
}
static void Op75M1 (void)
{
DirectIndexedX (READ);
ADC8 ();
}
static void Op75M0 (void)
{
DirectIndexedX (READ);
ADC16 ();
}
static void Op72M1 (void)
{
DirectIndirect (READ);
ADC8 ();
}
static void Op72M0 (void)
{
DirectIndirect (READ);
ADC16 ();
}
static void Op61M1 (void)
{
DirectIndexedIndirect (READ);
ADC8 ();
}
static void Op61M0 (void)
{
DirectIndexedIndirect (READ);
ADC16 ();
}
static void Op71M1 (void)
{
DirectIndirectIndexed (READ);
ADC8 ();
}
static void Op71M0 (void)
{
DirectIndirectIndexed (READ);
ADC16 ();
}
static void Op67M1 (void)
{
DirectIndirectLong (READ);
ADC8 ();
}
static void Op67M0 (void)
{
DirectIndirectLong (READ);
ADC16 ();
}
static void Op77M1 (void)
{
DirectIndirectIndexedLong (READ);
ADC8 ();
}
static void Op77M0 (void)
{
DirectIndirectIndexedLong (READ);
ADC16 ();
}
static void Op6DM1 (void)
{
Absolute (READ);
ADC8 ();
}
static void Op6DM0 (void)
{
Absolute (READ);
ADC16 ();
}
static void Op7DM1 (void)
{
AbsoluteIndexedX (READ);
ADC8 ();
}
static void Op7DM0 (void)
{
AbsoluteIndexedX (READ);
ADC16 ();
}
static void Op79M1 (void)
{
AbsoluteIndexedY (READ);
ADC8 ();
}
static void Op79M0 (void)
{
AbsoluteIndexedY (READ);
ADC16 ();
}
static void Op6FM1 (void)
{
AbsoluteLong (READ);
ADC8 ();
}
static void Op6FM0 (void)
{
AbsoluteLong (READ);
ADC16 ();
}
static void Op7FM1 (void)
{
AbsoluteLongIndexedX (READ);
ADC8 ();
}
static void Op7FM0 (void)
{
AbsoluteLongIndexedX (READ);
ADC16 ();
}
static void Op63M1 (void)
{
StackRelative (READ);
ADC8 ();
}
static void Op63M0 (void)
{
StackRelative (READ);
ADC16 ();
}
static void Op73M1 (void)
{
StackRelativeIndirectIndexed (READ);
ADC8 ();
}
static void Op73M0 (void)
{
StackRelativeIndirectIndexed (READ);
ADC16 ();
}
/**********************************************************************************************/
/* AND *************************************************************************************** */
static void Op29M1 (void)
{
Registers.AL &= *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.AL);
}
static void Op29M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.A.W &= *(uint16 *) CPU.PC;
#else
Registers.A.W &= *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.A.W);
}
static void Op25M1 (void)
{
Direct (READ);
AND8 ();
}
static void Op25M0 (void)
{
Direct (READ);
AND16 ();
}
static void Op35M1 (void)
{
DirectIndexedX (READ);
AND8 ();
}
static void Op35M0 (void)
{
DirectIndexedX (READ);
AND16 ();
}
static void Op32M1 (void)
{
DirectIndirect (READ);
AND8 ();
}
static void Op32M0 (void)
{
DirectIndirect (READ);
AND16 ();
}
static void Op21M1 (void)
{
DirectIndexedIndirect (READ);
AND8 ();
}
static void Op21M0 (void)
{
DirectIndexedIndirect (READ);
AND16 ();
}
static void Op31M1 (void)
{
DirectIndirectIndexed (READ);
AND8 ();
}
static void Op31M0 (void)
{
DirectIndirectIndexed (READ);
AND16 ();
}
static void Op27M1 (void)
{
DirectIndirectLong (READ);
AND8 ();
}
static void Op27M0 (void)
{
DirectIndirectLong (READ);
AND16 ();
}
static void Op37M1 (void)
{
DirectIndirectIndexedLong (READ);
AND8 ();
}
static void Op37M0 (void)
{
DirectIndirectIndexedLong (READ);
AND16 ();
}
static void Op2DM1 (void)
{
Absolute (READ);
AND8 ();
}
static void Op2DM0 (void)
{
Absolute (READ);
AND16 ();
}
static void Op3DM1 (void)
{
AbsoluteIndexedX (READ);
AND8 ();
}
static void Op3DM0 (void)
{
AbsoluteIndexedX (READ);
AND16 ();
}
static void Op39M1 (void)
{
AbsoluteIndexedY (READ);
AND8 ();
}
static void Op39M0 (void)
{
AbsoluteIndexedY (READ);
AND16 ();
}
static void Op2FM1 (void)
{
AbsoluteLong (READ);
AND8 ();
}
static void Op2FM0 (void)
{
AbsoluteLong (READ);
AND16 ();
}
static void Op3FM1 (void)
{
AbsoluteLongIndexedX (READ);
AND8 ();
}
static void Op3FM0 (void)
{
AbsoluteLongIndexedX (READ);
AND16 ();
}
static void Op23M1 (void)
{
StackRelative (READ);
AND8 ();
}
static void Op23M0 (void)
{
StackRelative (READ);
AND16 ();
}
static void Op33M1 (void)
{
StackRelativeIndirectIndexed (READ);
AND8 ();
}
static void Op33M0 (void)
{
StackRelativeIndirectIndexed (READ);
AND16 ();
}
/**********************************************************************************************/
/* ASL *************************************************************************************** */
static void Op0AM1 (void)
{
A_ASL8 ();
}
static void Op0AM0 (void)
{
A_ASL16 ();
}
static void Op06M1 (void)
{
Direct (MODIFY);
ASL8 ();
}
static void Op06M0 (void)
{
Direct (MODIFY);
ASL16 ();
}
static void Op16M1 (void)
{
DirectIndexedX (MODIFY);
ASL8 ();
}
static void Op16M0 (void)
{
DirectIndexedX (MODIFY);
ASL16 ();
}
static void Op0EM1 (void)
{
Absolute (MODIFY);
ASL8 ();
}
static void Op0EM0 (void)
{
Absolute (MODIFY);
ASL16 ();
}
static void Op1EM1 (void)
{
AbsoluteIndexedX (MODIFY);
ASL8 ();
}
static void Op1EM0 (void)
{
AbsoluteIndexedX (MODIFY);
ASL16 ();
}
/**********************************************************************************************/
/* BIT *************************************************************************************** */
static void Op89M1 (void)
{
ICPU._Zero = Registers.AL & *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
}
static void Op89M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
ICPU._Zero = (Registers.A.W & *(uint16 *) CPU.PC) != 0;
#else
ICPU._Zero = (Registers.A.W & (*CPU.PC + (*(CPU.PC + 1) << 8))) != 0;
#endif
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
CPU.PC += 2;
}
static void Op24M1 (void)
{
Direct (READ);
BIT8 ();
}
static void Op24M0 (void)
{
Direct (READ);
BIT16 ();
}
static void Op34M1 (void)
{
DirectIndexedX (READ);
BIT8 ();
}
static void Op34M0 (void)
{
DirectIndexedX (READ);
BIT16 ();
}
static void Op2CM1 (void)
{
Absolute (READ);
BIT8 ();
}
static void Op2CM0 (void)
{
Absolute (READ);
BIT16 ();
}
static void Op3CM1 (void)
{
AbsoluteIndexedX (READ);
BIT8 ();
}
static void Op3CM0 (void)
{
AbsoluteIndexedX (READ);
BIT16 ();
}
/**********************************************************************************************/
/* CMP *************************************************************************************** */
static void OpC9M1 (void)
{
Int32 = (int) Registers.AL - (int) *CPU.PC++;
ICPU._Carry = Int32 >= 0;
SetZN8 ((uint8) Int32);
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
}
static void OpC9M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Int32 = (long) Registers.A.W - (long) *(uint16 *) CPU.PC;
#else
Int32 = (long) Registers.A.W -
(long) (*CPU.PC + (*(CPU.PC + 1) << 8));
#endif
ICPU._Carry = Int32 >= 0;
SetZN16 ((uint16) Int32);
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
}
static void OpC5M1 (void)
{
Direct (READ);
CMP8 ();
}
static void OpC5M0 (void)
{
Direct (READ);
CMP16 ();
}
static void OpD5M1 (void)
{
DirectIndexedX (READ);
CMP8 ();
}
static void OpD5M0 (void)
{
DirectIndexedX (READ);
CMP16 ();
}
static void OpD2M1 (void)
{
DirectIndirect (READ);
CMP8 ();
}
static void OpD2M0 (void)
{
DirectIndirect (READ);
CMP16 ();
}
static void OpC1M1 (void)
{
DirectIndexedIndirect (READ);
CMP8 ();
}
static void OpC1M0 (void)
{
DirectIndexedIndirect (READ);
CMP16 ();
}
static void OpD1M1 (void)
{
DirectIndirectIndexed (READ);
CMP8 ();
}
static void OpD1M0 (void)
{
DirectIndirectIndexed (READ);
CMP16 ();
}
static void OpC7M1 (void)
{
DirectIndirectLong (READ);
CMP8 ();
}
static void OpC7M0 (void)
{
DirectIndirectLong (READ);
CMP16 ();
}
static void OpD7M1 (void)
{
DirectIndirectIndexedLong (READ);
CMP8 ();
}
static void OpD7M0 (void)
{
DirectIndirectIndexedLong (READ);
CMP16 ();
}
static void OpCDM1 (void)
{
Absolute (READ);
CMP8 ();
}
static void OpCDM0 (void)
{
Absolute (READ);
CMP16 ();
}
static void OpDDM1 (void)
{
AbsoluteIndexedX (READ);
CMP8 ();
}
static void OpDDM0 (void)
{
AbsoluteIndexedX (READ);
CMP16 ();
}
static void OpD9M1 (void)
{
AbsoluteIndexedY (READ);
CMP8 ();
}
static void OpD9M0 (void)
{
AbsoluteIndexedY (READ);
CMP16 ();
}
static void OpCFM1 (void)
{
AbsoluteLong (READ);
CMP8 ();
}
static void OpCFM0 (void)
{
AbsoluteLong (READ);
CMP16 ();
}
static void OpDFM1 (void)
{
AbsoluteLongIndexedX (READ);
CMP8 ();
}
static void OpDFM0 (void)
{
AbsoluteLongIndexedX (READ);
CMP16 ();
}
static void OpC3M1 (void)
{
StackRelative (READ);
CMP8 ();
}
static void OpC3M0 (void)
{
StackRelative (READ);
CMP16 ();
}
static void OpD3M1 (void)
{
StackRelativeIndirectIndexed (READ);
CMP8 ();
}
static void OpD3M0 (void)
{
StackRelativeIndirectIndexed (READ);
CMP16 ();
}
/**********************************************************************************************/
/* CMX *************************************************************************************** */
static void OpE0X1 (void)
{
Int32 = (int) Registers.XL - (int) *CPU.PC++;
ICPU._Carry = Int32 >= 0;
SetZN8 ((uint8) Int32);
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
}
static void OpE0X0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Int32 = (long) Registers.X.W - (long) *(uint16 *) CPU.PC;
#else
Int32 = (long) Registers.X.W -
(long) (*CPU.PC + (*(CPU.PC + 1) << 8));
#endif
ICPU._Carry = Int32 >= 0;
SetZN16 ((uint16) Int32);
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
}
static void OpE4X1 (void)
{
Direct (READ);
CMX8 ();
}
static void OpE4X0 (void)
{
Direct (READ);
CMX16 ();
}
static void OpECX1 (void)
{
Absolute (READ);
CMX8 ();
}
static void OpECX0 (void)
{
Absolute (READ);
CMX16 ();
}
/**********************************************************************************************/
/* CMY *************************************************************************************** */
static void OpC0X1 (void)
{
Int32 = (int) Registers.YL - (int) *CPU.PC++;
ICPU._Carry = Int32 >= 0;
SetZN8 ((uint8) Int32);
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
}
static void OpC0X0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Int32 = (long) Registers.Y.W - (long) *(uint16 *) CPU.PC;
#else
Int32 = (long) Registers.Y.W -
(long) (*CPU.PC + (*(CPU.PC + 1) << 8));
#endif
ICPU._Carry = Int32 >= 0;
SetZN16 ((uint16) Int32);
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
}
static void OpC4X1 (void)
{
Direct (READ);
CMY8 ();
}
static void OpC4X0 (void)
{
Direct (READ);
CMY16 ();
}
static void OpCCX1 (void)
{
Absolute (READ);
CMY8 ();
}
static void OpCCX0 (void)
{
Absolute (READ);
CMY16 ();
}
/**********************************************************************************************/
/* DEC *************************************************************************************** */
static void Op3AM1 (void)
{
A_DEC8 ();
}
static void Op3AM0 (void)
{
A_DEC16 ();
}
static void OpC6M1 (void)
{
Direct (MODIFY);
DEC8 ();
}
static void OpC6M0 (void)
{
Direct (MODIFY);
DEC16 ();
}
static void OpD6M1 (void)
{
DirectIndexedX (MODIFY);
DEC8 ();
}
static void OpD6M0 (void)
{
DirectIndexedX (MODIFY);
DEC16 ();
}
static void OpCEM1 (void)
{
Absolute (MODIFY);
DEC8 ();
}
static void OpCEM0 (void)
{
Absolute (MODIFY);
DEC16 ();
}
static void OpDEM1 (void)
{
AbsoluteIndexedX (MODIFY);
DEC8 ();
}
static void OpDEM0 (void)
{
AbsoluteIndexedX (MODIFY);
DEC16 ();
}
/**********************************************************************************************/
/* EOR *************************************************************************************** */
static void Op49M1 (void)
{
Registers.AL ^= *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.AL);
}
static void Op49M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.A.W ^= *(uint16 *) CPU.PC;
#else
Registers.A.W ^= *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.A.W);
}
static void Op45M1 (void)
{
Direct (READ);
EOR8 ();
}
static void Op45M0 (void)
{
Direct (READ);
EOR16 ();
}
static void Op55M1 (void)
{
DirectIndexedX (READ);
EOR8 ();
}
static void Op55M0 (void)
{
DirectIndexedX (READ);
EOR16 ();
}
static void Op52M1 (void)
{
DirectIndirect (READ);
EOR8 ();
}
static void Op52M0 (void)
{
DirectIndirect (READ);
EOR16 ();
}
static void Op41M1 (void)
{
DirectIndexedIndirect (READ);
EOR8 ();
}
static void Op41M0 (void)
{
DirectIndexedIndirect (READ);
EOR16 ();
}
static void Op51M1 (void)
{
DirectIndirectIndexed (READ);
EOR8 ();
}
static void Op51M0 (void)
{
DirectIndirectIndexed (READ);
EOR16 ();
}
static void Op47M1 (void)
{
DirectIndirectLong (READ);
EOR8 ();
}
static void Op47M0 (void)
{
DirectIndirectLong (READ);
EOR16 ();
}
static void Op57M1 (void)
{
DirectIndirectIndexedLong (READ);
EOR8 ();
}
static void Op57M0 (void)
{
DirectIndirectIndexedLong (READ);
EOR16 ();
}
static void Op4DM1 (void)
{
Absolute (READ);
EOR8 ();
}
static void Op4DM0 (void)
{
Absolute (READ);
EOR16 ();
}
static void Op5DM1 (void)
{
AbsoluteIndexedX (READ);
EOR8 ();
}
static void Op5DM0 (void)
{
AbsoluteIndexedX (READ);
EOR16 ();
}
static void Op59M1 (void)
{
AbsoluteIndexedY (READ);
EOR8 ();
}
static void Op59M0 (void)
{
AbsoluteIndexedY (READ);
EOR16 ();
}
static void Op4FM1 (void)
{
AbsoluteLong (READ);
EOR8 ();
}
static void Op4FM0 (void)
{
AbsoluteLong (READ);
EOR16 ();
}
static void Op5FM1 (void)
{
AbsoluteLongIndexedX (READ);
EOR8 ();
}
static void Op5FM0 (void)
{
AbsoluteLongIndexedX (READ);
EOR16 ();
}
static void Op43M1 (void)
{
StackRelative (READ);
EOR8 ();
}
static void Op43M0 (void)
{
StackRelative (READ);
EOR16 ();
}
static void Op53M1 (void)
{
StackRelativeIndirectIndexed (READ);
EOR8 ();
}
static void Op53M0 (void)
{
StackRelativeIndirectIndexed (READ);
EOR16 ();
}
/**********************************************************************************************/
/* INC *************************************************************************************** */
static void Op1AM1 (void)
{
A_INC8 ();
}
static void Op1AM0 (void)
{
A_INC16 ();
}
static void OpE6M1 (void)
{
Direct (MODIFY);
INC8 ();
}
static void OpE6M0 (void)
{
Direct (MODIFY);
INC16 ();
}
static void OpF6M1 (void)
{
DirectIndexedX (MODIFY);
INC8 ();
}
static void OpF6M0 (void)
{
DirectIndexedX (MODIFY);
INC16 ();
}
static void OpEEM1 (void)
{
Absolute (MODIFY);
INC8 ();
}
static void OpEEM0 (void)
{
Absolute (MODIFY);
INC16 ();
}
static void OpFEM1 (void)
{
AbsoluteIndexedX (MODIFY);
INC8 ();
}
static void OpFEM0 (void)
{
AbsoluteIndexedX (MODIFY);
INC16 ();
}
/**********************************************************************************************/
/* LDA *************************************************************************************** */
static void OpA9M1 (void)
{
Registers.AL = *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.AL);
}
static void OpA9M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.A.W = *(uint16 *) CPU.PC;
#else
Registers.A.W = *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.A.W);
}
static void OpA5M1 (void)
{
Direct (READ);
LDA8 ();
}
static void OpA5M0 (void)
{
Direct (READ);
LDA16 ();
}
static void OpB5M1 (void)
{
DirectIndexedX (READ);
LDA8 ();
}
static void OpB5M0 (void)
{
DirectIndexedX (READ);
LDA16 ();
}
static void OpB2M1 (void)
{
DirectIndirect (READ);
LDA8 ();
}
static void OpB2M0 (void)
{
DirectIndirect (READ);
LDA16 ();
}
static void OpA1M1 (void)
{
DirectIndexedIndirect (READ);
LDA8 ();
}
static void OpA1M0 (void)
{
DirectIndexedIndirect (READ);
LDA16 ();
}
static void OpB1M1 (void)
{
DirectIndirectIndexed (READ);
LDA8 ();
}
static void OpB1M0 (void)
{
DirectIndirectIndexed (READ);
LDA16 ();
}
static void OpA7M1 (void)
{
DirectIndirectLong (READ);
LDA8 ();
}
static void OpA7M0 (void)
{
DirectIndirectLong (READ);
LDA16 ();
}
static void OpB7M1 (void)
{
DirectIndirectIndexedLong (READ);
LDA8 ();
}
static void OpB7M0 (void)
{
DirectIndirectIndexedLong (READ);
LDA16 ();
}
static void OpADM1 (void)
{
Absolute (READ);
LDA8 ();
}
static void OpADM0 (void)
{
Absolute (READ);
LDA16 ();
}
static void OpBDM1 (void)
{
AbsoluteIndexedX (READ);
LDA8 ();
}
static void OpBDM0 (void)
{
AbsoluteIndexedX (READ);
LDA16 ();
}
static void OpB9M1 (void)
{
AbsoluteIndexedY (READ);
LDA8 ();
}
static void OpB9M0 (void)
{
AbsoluteIndexedY (READ);
LDA16 ();
}
static void OpAFM1 (void)
{
AbsoluteLong (READ);
LDA8 ();
}
static void OpAFM0 (void)
{
AbsoluteLong (READ);
LDA16 ();
}
static void OpBFM1 (void)
{
AbsoluteLongIndexedX (READ);
LDA8 ();
}
static void OpBFM0 (void)
{
AbsoluteLongIndexedX (READ);
LDA16 ();
}
static void OpA3M1 (void)
{
StackRelative (READ);
LDA8 ();
}
static void OpA3M0 (void)
{
StackRelative (READ);
LDA16 ();
}
static void OpB3M1 (void)
{
StackRelativeIndirectIndexed (READ);
LDA8 ();
}
static void OpB3M0 (void)
{
StackRelativeIndirectIndexed (READ);
LDA16 ();
}
/**********************************************************************************************/
/* LDX *************************************************************************************** */
static void OpA2X1 (void)
{
Registers.XL = *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.XL);
}
static void OpA2X0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.X.W = *(uint16 *) CPU.PC;
#else
Registers.X.W = *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.X.W);
}
static void OpA6X1 (void)
{
Direct (READ);
LDX8 ();
}
static void OpA6X0 (void)
{
Direct (READ);
LDX16 ();
}
static void OpB6X1 (void)
{
DirectIndexedY (READ);
LDX8 ();
}
static void OpB6X0 (void)
{
DirectIndexedY (READ);
LDX16 ();
}
static void OpAEX1 (void)
{
Absolute (READ);
LDX8 ();
}
static void OpAEX0 (void)
{
Absolute (READ);
LDX16 ();
}
static void OpBEX1 (void)
{
AbsoluteIndexedY (READ);
LDX8 ();
}
static void OpBEX0 (void)
{
AbsoluteIndexedY (READ);
LDX16 ();
}
/**********************************************************************************************/
/* LDY *************************************************************************************** */
static void OpA0X1 (void)
{
Registers.YL = *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.YL);
}
static void OpA0X0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.Y.W = *(uint16 *) CPU.PC;
#else
Registers.Y.W = *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.Y.W);
}
static void OpA4X1 (void)
{
Direct (READ);
LDY8 ();
}
static void OpA4X0 (void)
{
Direct (READ);
LDY16 ();
}
static void OpB4X1 (void)
{
DirectIndexedX (READ);
LDY8 ();
}
static void OpB4X0 (void)
{
DirectIndexedX (READ);
LDY16 ();
}
static void OpACX1 (void)
{
Absolute (READ);
LDY8 ();
}
static void OpACX0 (void)
{
Absolute (READ);
LDY16 ();
}
static void OpBCX1 (void)
{
AbsoluteIndexedX (READ);
LDY8 ();
}
static void OpBCX0 (void)
{
AbsoluteIndexedX (READ);
LDY16 ();
}
/**********************************************************************************************/
/* LSR *************************************************************************************** */
static void Op4AM1 (void)
{
A_LSR8 ();
}
static void Op4AM0 (void)
{
A_LSR16 ();
}
static void Op46M1 (void)
{
Direct (MODIFY);
LSR8 ();
}
static void Op46M0 (void)
{
Direct (MODIFY);
LSR16 ();
}
static void Op56M1 (void)
{
DirectIndexedX (MODIFY);
LSR8 ();
}
static void Op56M0 (void)
{
DirectIndexedX (MODIFY);
LSR16 ();
}
static void Op4EM1 (void)
{
Absolute (MODIFY);
LSR8 ();
}
static void Op4EM0 (void)
{
Absolute (MODIFY);
LSR16 ();
}
static void Op5EM1 (void)
{
AbsoluteIndexedX (MODIFY);
LSR8 ();
}
static void Op5EM0 (void)
{
AbsoluteIndexedX (MODIFY);
LSR16 ();
}
/**********************************************************************************************/
/* ORA *************************************************************************************** */
static void Op09M1 (void)
{
Registers.AL |= *CPU.PC++;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED;
#endif
SetZN8 (Registers.AL);
}
static void Op09M0 (void)
{
#ifdef FAST_LSB_WORD_ACCESS
Registers.A.W |= *(uint16 *) CPU.PC;
#else
Registers.A.W |= *CPU.PC + (*(CPU.PC + 1) << 8);
#endif
CPU.PC += 2;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED;
#endif
SetZN16 (Registers.A.W);
}
static void Op05M1 (void)
{
Direct (READ);
ORA8 ();
}
static void Op05M0 (void)
{
Direct (READ);
ORA16 ();
}
static void Op15M1 (void)
{
DirectIndexedX (READ);
ORA8 ();
}
static void Op15M0 (void)
{
DirectIndexedX (READ);
ORA16 ();
}
static void Op12M1 (void)
{
DirectIndirect (READ);
ORA8 ();
}
static void Op12M0 (void)
{
DirectIndirect (READ);
ORA16 ();
}
static void Op01M1 (void)
{
DirectIndexedIndirect (READ);
ORA8 ();
}
static void Op01M0 (void)
{
DirectIndexedIndirect (READ);
ORA16 ();
}
static void Op11M1 (void)
{
DirectIndirectIndexed (READ);
ORA8 ();
}
static void Op11M0 (void)
{
DirectIndirectIndexed (READ);
ORA16 ();
}
static void Op07M1 (void)
{
DirectIndirectLong (READ);
ORA8 ();
}
static void Op07M0 (void)
{
DirectIndirectLong (READ);
ORA16 ();
}
static void Op17M1 (void)
{
DirectIndirectIndexedLong (READ);
ORA8 ();
}
static void Op17M0 (void)
{
DirectIndirectIndexedLong (READ);
ORA16 ();
}
static void Op0DM1 (void)
{
Absolute (READ);
ORA8 ();
}
static void Op0DM0 (void)
{
Absolute (READ);
ORA16 ();
}
static void Op1DM1 (void)
{
AbsoluteIndexedX (READ);
ORA8 ();
}
static void Op1DM0 (void)
{
AbsoluteIndexedX (READ);
ORA16 ();
}
static void Op19M1 (void)
{
AbsoluteIndexedY (READ);
ORA8 ();
}
static void Op19M0 (void)
{
AbsoluteIndexedY (READ);
ORA16 ();
}
static void Op0FM1 (void)
{
AbsoluteLong (READ);
ORA8 ();
}
static void Op0FM0 (void)
{
AbsoluteLong (READ);
ORA16 ();
}
static void Op1FM1 (void)
{
AbsoluteLongIndexedX (READ);
ORA8 ();
}
static void Op1FM0 (void)
{
AbsoluteLongIndexedX (READ);
ORA16 ();
}
static void Op03M1 (void)
{
StackRelative (READ);
ORA8 ();
}
static void Op03M0 (void)
{
StackRelative (READ);
ORA16 ();
}
static void Op13M1 (void)
{
StackRelativeIndirectIndexed (READ);
ORA8 ();
}
static void Op13M0 (void)
{
StackRelativeIndirectIndexed (READ);
ORA16 ();
}
/**********************************************************************************************/
/* ROL *************************************************************************************** */
static void Op2AM1 (void)
{
A_ROL8 ();
}
static void Op2AM0 (void)
{
A_ROL16 ();
}
static void Op26M1 (void)
{
Direct (MODIFY);
ROL8 ();
}
static void Op26M0 (void)
{
Direct (MODIFY);
ROL16 ();
}
static void Op36M1 (void)
{
DirectIndexedX (MODIFY);
ROL8 ();
}
static void Op36M0 (void)
{
DirectIndexedX (MODIFY);
ROL16 ();
}
static void Op2EM1 (void)
{
Absolute (MODIFY);
ROL8 ();
}
static void Op2EM0 (void)
{
Absolute (MODIFY);
ROL16 ();
}
static void Op3EM1 (void)
{
AbsoluteIndexedX (MODIFY);
ROL8 ();
}
static void Op3EM0 (void)
{
AbsoluteIndexedX (MODIFY);
ROL16 ();
}
/**********************************************************************************************/
/* ROR *************************************************************************************** */
static void Op6AM1 (void)
{
A_ROR8 ();
}
static void Op6AM0 (void)
{
A_ROR16 ();
}
static void Op66M1 (void)
{
Direct (MODIFY);
ROR8 ();
}
static void Op66M0 (void)
{
Direct (MODIFY);
ROR16 ();
}
static void Op76M1 (void)
{
DirectIndexedX (MODIFY);
ROR8 ();
}
static void Op76M0 (void)
{
DirectIndexedX (MODIFY);
ROR16 ();
}
static void Op6EM1 (void)
{
Absolute (MODIFY);
ROR8 ();
}
static void Op6EM0 (void)
{
Absolute (MODIFY);
ROR16 ();
}
static void Op7EM1 (void)
{
AbsoluteIndexedX (MODIFY);
ROR8 ();
}
static void Op7EM0 (void)
{
AbsoluteIndexedX (MODIFY);
ROR16 ();
}
/**********************************************************************************************/
/* SBC *************************************************************************************** */
static void OpE9M1 (void)
{
Immediate8 (READ);
SBC8 ();
}
static void OpE9M0 (void)
{
Immediate16 (READ);
SBC16 ();
}
static void OpE5M1 (void)
{
Direct (READ);
SBC8 ();
}
static void OpE5M0 (void)
{
Direct (READ);
SBC16 ();
}
static void OpF5M1 (void)
{
DirectIndexedX (READ);
SBC8 ();
}
static void OpF5M0 (void)
{
DirectIndexedX (READ);
SBC16 ();
}
static void OpF2M1 (void)
{
DirectIndirect (READ);
SBC8 ();
}
static void OpF2M0 (void)
{
DirectIndirect (READ);
SBC16 ();
}
static void OpE1M1 (void)
{
DirectIndexedIndirect (READ);
SBC8 ();
}
static void OpE1M0 (void)
{
DirectIndexedIndirect (READ);
SBC16 ();
}
static void OpF1M1 (void)
{
DirectIndirectIndexed (READ);
SBC8 ();
}
static void OpF1M0 (void)
{
DirectIndirectIndexed (READ);
SBC16 ();
}
static void OpE7M1 (void)
{
DirectIndirectLong (READ);
SBC8 ();
}
static void OpE7M0 (void)
{
DirectIndirectLong (READ);
SBC16 ();
}
static void OpF7M1 (void)
{
DirectIndirectIndexedLong (READ);
SBC8 ();
}
static void OpF7M0 (void)
{
DirectIndirectIndexedLong (READ);
SBC16 ();
}
static void OpEDM1 (void)
{
Absolute (READ);
SBC8 ();
}
static void OpEDM0 (void)
{
Absolute (READ);
SBC16 ();
}
static void OpFDM1 (void)
{
AbsoluteIndexedX (READ);
SBC8 ();
}
static void OpFDM0 (void)
{
AbsoluteIndexedX (READ);
SBC16 ();
}
static void OpF9M1 (void)
{
AbsoluteIndexedY (READ);
SBC8 ();
}
static void OpF9M0 (void)
{
AbsoluteIndexedY (READ);
SBC16 ();
}
static void OpEFM1 (void)
{
AbsoluteLong (READ);
SBC8 ();
}
static void OpEFM0 (void)
{
AbsoluteLong (READ);
SBC16 ();
}
static void OpFFM1 (void)
{
AbsoluteLongIndexedX (READ);
SBC8 ();
}
static void OpFFM0 (void)
{
AbsoluteLongIndexedX (READ);
SBC16 ();
}
static void OpE3M1 (void)
{
StackRelative (READ);
SBC8 ();
}
static void OpE3M0 (void)
{
StackRelative (READ);
SBC16 ();
}
static void OpF3M1 (void)
{
StackRelativeIndirectIndexed (READ);
SBC8 ();
}
static void OpF3M0 (void)
{
StackRelativeIndirectIndexed (READ);
SBC16 ();
}
/**********************************************************************************************/
/* STA *************************************************************************************** */
static void Op85M1 (void)
{
Direct (WRITE);
STA8 ();
}
static void Op85M0 (void)
{
Direct (WRITE);
STA16 ();
}
static void Op95M1 (void)
{
DirectIndexedX (WRITE);
STA8 ();
}
static void Op95M0 (void)
{
DirectIndexedX (WRITE);
STA16 ();
}
static void Op92M1 (void)
{
DirectIndirect (WRITE);
STA8 ();
}
static void Op92M0 (void)
{
DirectIndirect (WRITE);
STA16 ();
}
static void Op81M1 (void)
{
DirectIndexedIndirect (WRITE);
STA8 ();
#ifdef noVAR_CYCLES
if (CheckIndex ())
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op81M0 (void)
{
DirectIndexedIndirect (WRITE);
STA16 ();
#ifdef noVAR_CYCLES
if (CheckIndex ())
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op91M1 (void)
{
DirectIndirectIndexed (WRITE);
STA8 ();
}
static void Op91M0 (void)
{
DirectIndirectIndexed (WRITE);
STA16 ();
}
static void Op87M1 (void)
{
DirectIndirectLong (WRITE);
STA8 ();
}
static void Op87M0 (void)
{
DirectIndirectLong (WRITE);
STA16 ();
}
static void Op97M1 (void)
{
DirectIndirectIndexedLong (WRITE);
STA8 ();
}
static void Op97M0 (void)
{
DirectIndirectIndexedLong (WRITE);
STA16 ();
}
static void Op8DM1 (void)
{
Absolute (WRITE);
STA8 ();
}
static void Op8DM0 (void)
{
Absolute (WRITE);
STA16 ();
}
static void Op9DM1 (void)
{
AbsoluteIndexedX (WRITE);
STA8 ();
}
static void Op9DM0 (void)
{
AbsoluteIndexedX (WRITE);
STA16 ();
}
static void Op99M1 (void)
{
AbsoluteIndexedY (WRITE);
STA8 ();
}
static void Op99M0 (void)
{
AbsoluteIndexedY (WRITE);
STA16 ();
}
static void Op8FM1 (void)
{
AbsoluteLong (WRITE);
STA8 ();
}
static void Op8FM0 (void)
{
AbsoluteLong (WRITE);
STA16 ();
}
static void Op9FM1 (void)
{
AbsoluteLongIndexedX (WRITE);
STA8 ();
}
static void Op9FM0 (void)
{
AbsoluteLongIndexedX (WRITE);
STA16 ();
}
static void Op83M1 (void)
{
StackRelative (WRITE);
STA8 ();
}
static void Op83M0 (void)
{
StackRelative (WRITE);
STA16 ();
}
static void Op93M1 (void)
{
StackRelativeIndirectIndexed (WRITE);
STA8 ();
}
static void Op93M0 (void)
{
StackRelativeIndirectIndexed (WRITE);
STA16 ();
}
/**********************************************************************************************/
/* STX *************************************************************************************** */
static void Op86X1 (void)
{
Direct (WRITE);
STX8 ();
}
static void Op86X0 (void)
{
Direct (WRITE);
STX16 ();
}
static void Op96X1 (void)
{
DirectIndexedY (WRITE);
STX8 ();
}
static void Op96X0 (void)
{
DirectIndexedY (WRITE);
STX16 ();
}
static void Op8EX1 (void)
{
Absolute (WRITE);
STX8 ();
}
static void Op8EX0 (void)
{
Absolute (WRITE);
STX16 ();
}
/**********************************************************************************************/
/* STY *************************************************************************************** */
static void Op84X1 (void)
{
Direct (WRITE);
STY8 ();
}
static void Op84X0 (void)
{
Direct (WRITE);
STY16 ();
}
static void Op94X1 (void)
{
DirectIndexedX (WRITE);
STY8 ();
}
static void Op94X0 (void)
{
DirectIndexedX (WRITE);
STY16 ();
}
static void Op8CX1 (void)
{
Absolute (WRITE);
STY8 ();
}
static void Op8CX0 (void)
{
Absolute (WRITE);
STY16 ();
}
/**********************************************************************************************/
/* STZ *************************************************************************************** */
static void Op64M1 (void)
{
Direct (WRITE);
STZ8 ();
}
static void Op64M0 (void)
{
Direct (WRITE);
STZ16 ();
}
static void Op74M1 (void)
{
DirectIndexedX (WRITE);
STZ8 ();
}
static void Op74M0 (void)
{
DirectIndexedX (WRITE);
STZ16 ();
}
static void Op9CM1 (void)
{
Absolute (WRITE);
STZ8 ();
}
static void Op9CM0 (void)
{
Absolute (WRITE);
STZ16 ();
}
static void Op9EM1 (void)
{
AbsoluteIndexedX (WRITE);
STZ8 ();
}
static void Op9EM0 (void)
{
AbsoluteIndexedX (WRITE);
STZ16 ();
}
/**********************************************************************************************/
/* TRB *************************************************************************************** */
static void Op14M1 (void)
{
Direct (MODIFY);
TRB8 ();
}
static void Op14M0 (void)
{
Direct (MODIFY);
TRB16 ();
}
static void Op1CM1 (void)
{
Absolute (MODIFY);
TRB8 ();
}
static void Op1CM0 (void)
{
Absolute (MODIFY);
TRB16 ();
}
/**********************************************************************************************/
/* TSB *************************************************************************************** */
static void Op04M1 (void)
{
Direct (MODIFY);
TSB8 ();
}
static void Op04M0 (void)
{
Direct (MODIFY);
TSB16 ();
}
static void Op0CM1 (void)
{
Absolute (MODIFY);
TSB8 ();
}
static void Op0CM0 (void)
{
Absolute (MODIFY);
TSB16 ();
}
/**********************************************************************************************/
/* Branch Instructions *********************************************************************** */
#ifndef SA1_OPCODES
#define BranchCheck0()\
if( CPU.BranchSkip)\
{\
CPU.BranchSkip = FALSE;\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
}
#define BranchCheck1()\
if( CPU.BranchSkip)\
{\
CPU.BranchSkip = FALSE;\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
}
#define BranchCheck2()\
if( CPU.BranchSkip)\
{\
CPU.BranchSkip = FALSE;\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
}
#else
#define BranchCheck0()
#define BranchCheck1()
#define BranchCheck2()
#endif
#ifdef CPU_SHUTDOWN
#ifndef SA1_OPCODES
__inline__ void CPUShutdown()
{
if (Settings.Shutdown && CPU.PC == 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 = NULL;
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 && CPU.PC == CPU.WaitAddress)
{
if (CPU.WaitCounter >= 1)
{
SA1.Executing = FALSE;
SA1.CPUExecuting = FALSE;
}
else
CPU.WaitCounter++;
}
}
#endif
#else
#define CPUShutdown()
#endif
/* BCC */
static void Op90 (void)
{
Relative (JUMP);
BranchCheck0 ();
if (!CheckCarry ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BCS */
static void OpB0 (void)
{
Relative (JUMP);
BranchCheck0 ();
if (CheckCarry ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BEQ */
static void OpF0 (void)
{
Relative (JUMP);
BranchCheck2 ();
if (CheckZero ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BMI */
static void Op30 (void)
{
Relative (JUMP);
BranchCheck1 ();
if (CheckNegative ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BNE */
static void OpD0 (void)
{
Relative (JUMP);
BranchCheck1 ();
if (!CheckZero ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BPL */
static void Op10 (void)
{
Relative (JUMP);
BranchCheck1 ();
if (!CheckNegative ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BRA */
static void Op80 (void)
{
Relative (JUMP);
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
/* BVC */
static void Op50 (void)
{
Relative (JUMP);
BranchCheck0 ();
if (!CheckOverflow ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/* BVS */
static void Op70 (void)
{
Relative (JUMP);
BranchCheck0 ();
if (CheckOverflow ())
{
CPU.PC = CPU.PCBase + OpAddress;
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
CPUShutdown ();
}
}
/**********************************************************************************************/
/* ClearFlag Instructions ******************************************************************** */
/* CLC */
static void Op18 (void)
{
ClearCarry ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/* CLD */
static void OpD8 (void)
{
ClearDecimal ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/* CLI */
static void Op58 (void)
{
ClearIRQ ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
/* CHECK_FOR_IRQ(); */
}
/* CLV */
static void OpB8 (void)
{
ClearOverflow ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/**********************************************************************************************/
/* DEX/DEY *********************************************************************************** */
static void OpCAX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.XL--;
SetZN8 (Registers.XL);
}
static void OpCAX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.X.W--;
SetZN16 (Registers.X.W);
}
static void Op88X1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.YL--;
SetZN8 (Registers.YL);
}
static void Op88X0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.Y.W--;
SetZN16 (Registers.Y.W);
}
/**********************************************************************************************/
/* INX/INY *********************************************************************************** */
static void OpE8X1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.XL++;
SetZN8 (Registers.XL);
}
static void OpE8X0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.X.W++;
SetZN16 (Registers.X.W);
}
static void OpC8X1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.YL++;
SetZN8 (Registers.YL);
}
static void OpC8X0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
#ifdef CPU_SHUTDOWN
CPU.WaitAddress = NULL;
#endif
Registers.Y.W++;
SetZN16 (Registers.Y.W);
}
/**********************************************************************************************/
/* NOP *************************************************************************************** */
static void OpEA (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/**********************************************************************************************/
/* PUSH Instructions ************************************************************************* */
/* #define PushW(w) \
* S9xSetWord (w, Registers.S.W - 1);\
* Registers.S.W -= 2;
*/
#define PushB(b)\
S9xSetByte (b, Registers.S.W--);
#define PushBE(b)\
S9xSetByte (b, Registers.S.W--);\
Registers.SH=0x01;
#define PushW(w) \
S9xSetByte ((w)>>8, Registers.S.W);\
S9xSetByte ((w)&0xff, (Registers.S.W - 1)&0xFFFF);\
Registers.S.W -= 2;
#define PushWE(w) \
S9xSetByte ((w)>>8, Registers.S.W--);\
Registers.SH=0x01;\
S9xSetByte ((w)&0xff, (Registers.S.W--)&0xFFFF);\
Registers.SH = 0x01;
#define PushWENew(w) \
S9xSetByte ((w)>>8, Registers.S.W--);\
S9xSetByte ((w)&0xff, (Registers.S.W--)&0xFFFF);\
Registers.SH = 0x01;
//PEA NL
static void OpF4E1 (void)
{
Absolute (NONE);
PushWENew ((unsigned short)OpAddress);
}
static void OpF4 (void)
{
Absolute (NONE);
PushW ((unsigned short)OpAddress);
}
//PEI NL
static void OpD4E1 (void)
{
DirectIndirect (NONE);
PushWENew ((unsigned short)OpAddress);
}
static void OpD4 (void)
{
DirectIndirect (NONE);
PushW ((unsigned short)OpAddress);
}
//PER NL
static void Op62E1 (void)
{
RelativeLong (NONE);
PushWENew ((unsigned short)OpAddress);
}
static void Op62 (void)
{
RelativeLong (NONE);
PushW ((unsigned short)OpAddress);
}
//PHA
static void Op48E1 (void)
{
PushBE (Registers.AL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op48M1 (void)
{
PushB (Registers.AL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op48M0 (void)
{
PushW (Registers.A.W);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHB
static void Op8BE1 (void)
{
PushBE (Registers.DB);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op8B (void)
{
PushB (Registers.DB);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHD NL
static void Op0BE1 (void)
{
PushWENew (Registers.D.W);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op0B (void)
{
PushW (Registers.D.W);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHK
static void Op4BE1 (void)
{
PushBE (Registers.PB);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op4B (void)
{
PushB (Registers.PB);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHP
static void Op08E1 (void)
{
S9xPackStatus ();
PushBE (Registers.PL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op08 (void)
{
S9xPackStatus ();
PushB (Registers.PL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHX
static void OpDAE1 (void)
{
PushBE (Registers.XL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void OpDAX1 (void)
{
PushB (Registers.XL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void OpDAX0 (void)
{
PushW (Registers.X.W);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//PHY
static void Op5AE1 (void)
{
PushBE (Registers.YL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op5AX1 (void)
{
PushB (Registers.YL);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op5AX0 (void)
{
PushW (Registers.Y.W);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/**********************************************************************************************/
/* PULL Instructions ************************************************************************* */
#define PullW(w) \
w = S9xGetByte (++Registers.S.W); \
w |= (S9xGetByte (++Registers.S.W)<<8);
/* w = S9xGetWord (Registers.S.W + 1); \
Registers.S.W += 2;
*/
#define PullB(b)\
b = S9xGetByte (++Registers.S.W);
#define PullBE(b)\
Registers.S.W++;\
Registers.SH=0x01;\
b = S9xGetByte (Registers.S.W);
#define PullWE(w) \
Registers.S.W++;\
Registers.SH=0x01;\
w = S9xGetByte (Registers.S.W); \
Registers.S.W++; \
Registers.SH=0x01;\
w |= (S9xGetByte (Registers.S.W)<<8);
#define PullWENew(w) \
PullW(w);\
Registers.SH=0x01;
//PLA
static void Op68E1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullBE (Registers.AL);
SetZN8 (Registers.AL);
}
static void Op68M1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullB (Registers.AL);
SetZN8 (Registers.AL);
}
static void Op68M0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullW (Registers.A.W);
SetZN16 (Registers.A.W);
}
//PLB
static void OpABE1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullBE (Registers.DB);
SetZN8 (Registers.DB);
ICPU.ShiftedDB = Registers.DB << 16;
}
static void OpAB (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullB (Registers.DB);
SetZN8 (Registers.DB);
ICPU.ShiftedDB = Registers.DB << 16;
}
/* PHP */
//PLD NL
static void Op2BE1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullWENew (Registers.D.W);
SetZN16 (Registers.D.W);
}
static void Op2B (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullW (Registers.D.W);
SetZN16 (Registers.D.W);
}
/* PLP */
/* // NOT USED ???
static void Op28E1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullBE (Registers.PL);
S9xUnpackStatus ();
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
// CHECK_FOR_IRQ();
}
*/
static void Op28 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullB (Registers.PL);
S9xUnpackStatus ();
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
/* CHECK_FOR_IRQ();*/
}
//PLX
static void OpFAE1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullBE (Registers.XL);
SetZN8 (Registers.XL);
}
static void OpFAX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullB (Registers.XL);
SetZN8 (Registers.XL);
}
static void OpFAX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullW (Registers.X.W);
SetZN16 (Registers.X.W);
}
//PLY
static void Op7AE1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullBE (Registers.YL);
SetZN8 (Registers.YL);
}
static void Op7AX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullB (Registers.YL);
SetZN8 (Registers.YL);
}
static void Op7AX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
PullW (Registers.Y.W);
SetZN16 (Registers.Y.W);
}
/**********************************************************************************************/
/* SetFlag Instructions ********************************************************************** */
/* SEC */
static void Op38 (void)
{
SetCarry ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/* SED */
static void OpF8 (void)
{
SetDecimal ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/* SEI */
static void Op78 (void)
{
SetIRQ ();
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/**********************************************************************************************/
/* Transfer Instructions ********************************************************************* */
/* TAX8 */
static void OpAAX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.XL = Registers.AL;
SetZN8 (Registers.XL);
}
/* TAX16 */
static void OpAAX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.X.W = Registers.A.W;
SetZN16 (Registers.X.W);
}
/* TAY8 */
static void OpA8X1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.YL = Registers.AL;
SetZN8 (Registers.YL);
}
/* TAY16 */
static void OpA8X0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.Y.W = Registers.A.W;
SetZN16 (Registers.Y.W);
}
static void Op5B (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.D.W = Registers.A.W;
SetZN16 (Registers.D.W);
}
static void Op1B (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.S.W = Registers.A.W;
if (CheckEmulation())
Registers.SH = 1;
}
static void Op7B (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.A.W = Registers.D.W;
SetZN16 (Registers.A.W);
}
static void Op3B (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.A.W = Registers.S.W;
SetZN16 (Registers.A.W);
}
static void OpBAX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.XL = Registers.SL;
SetZN8 (Registers.XL);
}
static void OpBAX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.X.W = Registers.S.W;
SetZN16 (Registers.X.W);
}
static void Op8AM1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.AL = Registers.XL;
SetZN8 (Registers.AL);
}
static void Op8AM0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.A.W = Registers.X.W;
SetZN16 (Registers.A.W);
}
static void Op9A (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.S.W = Registers.X.W;
if (CheckEmulation())
Registers.SH = 1;
}
static void Op9BX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.YL = Registers.XL;
SetZN8 (Registers.YL);
}
static void Op9BX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.Y.W = Registers.X.W;
SetZN16 (Registers.Y.W);
}
static void Op98M1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.AL = Registers.YL;
SetZN8 (Registers.AL);
}
static void Op98M0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.A.W = Registers.Y.W;
SetZN16 (Registers.A.W);
}
static void OpBBX1 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.XL = Registers.YL;
SetZN8 (Registers.XL);
}
static void OpBBX0 (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
Registers.X.W = Registers.Y.W;
SetZN16 (Registers.X.W);
}
/**********************************************************************************************/
/* XCE *************************************************************************************** */
static void OpFB (void)
{
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
A1 = ICPU._Carry;
A2 = Registers.PH;
ICPU._Carry = A2 & 1;
Registers.PH = A1;
if (CheckEmulation())
{
SetFlags (MemoryFlag | IndexFlag);
Registers.SH = 1;
}
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
}
/**********************************************************************************************/
/* BRK *************************************************************************************** */
static void Op00 (void)
{
#ifndef SA1_OPCODES
CPU.BRKTriggered = TRUE;
#endif
if (!CheckEmulation())
{
PushB (Registers.PB);
PushW (CPU.PC - CPU.PCBase + 1);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
S9xSetPCBase (S9xGetWord (0xFFE6));
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
else
{
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
S9xSetPCBase (S9xGetWord (0xFFFE));
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
/**********************************************************************************************/
/* BRL ************************************************************************************** */
static void Op82 (void)
{
RelativeLong (JUMP);
S9xSetPCBase (ICPU.ShiftedPB + OpAddress);
}
/**********************************************************************************************/
/* IRQ *************************************************************************************** */
void S9xOpcode_IRQ (void)
{
if (!CheckEmulation())
{
PushB (Registers.PB);
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
#ifdef SA1_OPCODES
S9xSA1SetPCBase (CMemory_FillRAM [0x2207] |
(CMemory_FillRAM [0x2208] << 8));
#else
if (Settings.SA1 && (CMemory_FillRAM [0x2209] & 0x40))
S9xSetPCBase (CMemory_FillRAM [0x220e] |
(CMemory_FillRAM [0x220f] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFEE));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
else
{
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
#ifdef SA1_OPCODES
S9xSA1SetPCBase (CMemory_FillRAM [0x2207] |
(CMemory_FillRAM [0x2208] << 8));
#else
if (Settings.SA1 && (CMemory_FillRAM [0x2209] & 0x40))
S9xSetPCBase (CMemory_FillRAM [0x220e] |
(CMemory_FillRAM [0x220f] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFFE));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
/**********************************************************************************************/
/* NMI *************************************************************************************** */
void S9xOpcode_NMI (void)
{
if (!CheckEmulation())
{
PushB (Registers.PB);
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
#ifdef SA1_OPCODES
S9xSA1SetPCBase (CMemory_FillRAM [0x2205] |
(CMemory_FillRAM [0x2206] << 8));
#else
if (Settings.SA1 && (CMemory_FillRAM [0x2209] & 0x20))
S9xSetPCBase (CMemory_FillRAM [0x220c] |
(CMemory_FillRAM [0x220d] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFEA));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
else
{
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
#ifdef SA1_OPCODES
S9xSA1SetPCBase (CMemory_FillRAM [0x2205] |
(CMemory_FillRAM [0x2206] << 8));
#else
if (Settings.SA1 && (CMemory_FillRAM [0x2209] & 0x20))
S9xSetPCBase (CMemory_FillRAM [0x220c] |
(CMemory_FillRAM [0x220d] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFFA));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
/**********************************************************************************************/
/* COP *************************************************************************************** */
static void Op02 (void)
{
if (!CheckEmulation())
{
PushB (Registers.PB);
PushW (CPU.PC - CPU.PCBase + 1);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
S9xSetPCBase (S9xGetWord (0xFFE4));
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
else
{
PushW (CPU.PC - CPU.PCBase);
S9xPackStatus ();
PushB (Registers.PL);
OpenBus = Registers.PL;
ClearDecimal ();
SetIRQ ();
Registers.PB = 0;
ICPU.ShiftedPB = 0;
S9xSetPCBase (S9xGetWord (0xFFF4));
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
/**********************************************************************************************/
/* JML *************************************************************************************** */
static void OpDC (void)
{
AbsoluteIndirectLong (JUMP);
Registers.PB = (uint8) (OpAddress >> 16);
ICPU.ShiftedPB = OpAddress & 0xff0000;
S9xSetPCBase (OpAddress);
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
static void Op5C (void)
{
AbsoluteLong (JUMP);
Registers.PB = (uint8) (OpAddress >> 16);
ICPU.ShiftedPB = OpAddress & 0xff0000;
S9xSetPCBase (OpAddress);
}
/**********************************************************************************************/
/* JMP *************************************************************************************** */
static void Op4C (void)
{
Absolute (JUMP);
S9xSetPCBase (ICPU.ShiftedPB + (OpAddress & 0xffff));
#if defined(CPU_SHUTDOWN) && defined(SA1_OPCODES)
CPUShutdown ();
#endif
}
static void Op6C (void)
{
AbsoluteIndirect (JUMP);
S9xSetPCBase (ICPU.ShiftedPB + (OpAddress & 0xffff));
}
static void Op7C (void)
{
AbsoluteIndexedIndirect (JUMP);
S9xSetPCBase (ICPU.ShiftedPB + OpAddress);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
/**********************************************************************************************/
/* JSL/RTL *********************************************************************************** */
static void Op22E1 (void)
{
AbsoluteLong (JUMP);
PushB (Registers.PB);
PushWENew (CPU.PC - CPU.PCBase - 1);
Registers.PB = (uint8) (OpAddress >> 16);
ICPU.ShiftedPB = OpAddress & 0xff0000;
S9xSetPCBase (OpAddress);
}
static void Op22 (void)
{
AbsoluteLong (JUMP);
PushB (Registers.PB);
PushW (CPU.PC - CPU.PCBase - 1);
Registers.PB = (uint8) (OpAddress >> 16);
ICPU.ShiftedPB = OpAddress & 0xff0000;
S9xSetPCBase (OpAddress);
}
static void Op6BE1 (void)
{
PullWENew (Registers.PC);
PullB (Registers.PB);
ICPU.ShiftedPB = Registers.PB << 16;
S9xSetPCBase (ICPU.ShiftedPB + ((Registers.PC + 1) & 0xffff));
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
static void Op6B (void)
{
PullW (Registers.PC);
PullB (Registers.PB);
ICPU.ShiftedPB = Registers.PB << 16;
S9xSetPCBase (ICPU.ShiftedPB + ((Registers.PC + 1) & 0xffff));
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
/**********************************************************************************************/
/* JSR/RTS *********************************************************************************** */
static void Op20 (void)
{
Absolute (JUMP);
PushW (CPU.PC - CPU.PCBase - 1);
S9xSetPCBase (ICPU.ShiftedPB + (OpAddress & 0xffff));
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
//JSR a,x
static void OpFCE1 (void)
{
AbsoluteIndexedIndirect (JUMP);
PushWENew (CPU.PC - CPU.PCBase - 1);
S9xSetPCBase (ICPU.ShiftedPB + OpAddress);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void OpFC (void)
{
AbsoluteIndexedIndirect (JUMP);
PushW (CPU.PC - CPU.PCBase - 1);
S9xSetPCBase (ICPU.ShiftedPB + OpAddress);
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
static void Op60 (void)
{
PullW (Registers.PC);
S9xSetPCBase (ICPU.ShiftedPB + ((Registers.PC + 1) & 0xffff));
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE * 3;
#endif
}
/**********************************************************************************************/
/* MVN/MVP *********************************************************************************** */
static void Op54X1 (void)
{
uint32 SrcBank;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED + TWO_CYCLES;
#endif
Registers.DB = *CPU.PC++;
ICPU.ShiftedDB = Registers.DB << 16;
OpenBus = SrcBank = *CPU.PC++;
S9xSetByte (S9xGetByte ((SrcBank << 16) + Registers.X.W),
ICPU.ShiftedDB + Registers.Y.W);
Registers.XL++;
Registers.YL++;
Registers.A.W--;
if (Registers.A.W != 0xffff)
CPU.PC -= 3;
}
static void Op54X0 (void)
{
uint32 SrcBank;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED + TWO_CYCLES;
#endif
Registers.DB = *CPU.PC++;
ICPU.ShiftedDB = Registers.DB << 16;
OpenBus = SrcBank = *CPU.PC++;
S9xSetByte (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)
CPU.PC -= 3;
}
static void Op44X1 (void)
{
uint32 SrcBank;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED + TWO_CYCLES;
#endif
Registers.DB = *CPU.PC++;
ICPU.ShiftedDB = Registers.DB << 16;
OpenBus = SrcBank = *CPU.PC++;
S9xSetByte (S9xGetByte ((SrcBank << 16) + Registers.X.W),
ICPU.ShiftedDB + Registers.Y.W);
Registers.XL--;
Registers.YL--;
Registers.A.W--;
if (Registers.A.W != 0xffff)
CPU.PC -= 3;
}
static void Op44X0 (void)
{
uint32 SrcBank;
#ifndef SA1_OPCODES
CPU.Cycles += MEM2XSPEED + TWO_CYCLES;
#endif
Registers.DB = *CPU.PC++;
ICPU.ShiftedDB = Registers.DB << 16;
OpenBus = SrcBank = *CPU.PC++;
S9xSetByte (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)
CPU.PC -= 3;
}
/**********************************************************************************************/
/* REP/SEP *********************************************************************************** */
static void OpC2 (void)
{
Work8 = ~*CPU.PC++;
Registers.PL &= Work8;
ICPU._Carry &= Work8;
ICPU._Overflow &= (Work8 >> 6);
ICPU._Negative &= Work8;
ICPU._Zero |= ~Work8 & Zero;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED + ONE_CYCLE;
#endif
if (CheckEmulation())
{
SetFlags (MemoryFlag | IndexFlag);
}
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
/* CHECK_FOR_IRQ(); */
}
static void OpE2 (void)
{
Work8 = *CPU.PC++;
Registers.PL |= Work8;
ICPU._Carry |= Work8 & 1;
ICPU._Overflow |= (Work8 >> 6) & 1;
ICPU._Negative |= Work8;
if (Work8 & Zero)
ICPU._Zero = 0;
#ifndef SA1_OPCODES
CPU.Cycles += MEMSPEED + ONE_CYCLE;
#endif
if (CheckEmulation())
{
SetFlags (MemoryFlag | IndexFlag);
}
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
}
/**********************************************************************************************/
/* XBA *************************************************************************************** */
static void OpEB (void)
{
Work8 = Registers.AL;
Registers.AL = Registers.AH;
Registers.AH = Work8;
SetZN8 (Registers.AL);
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
/**********************************************************************************************/
/* RTI *************************************************************************************** */
static void Op40 (void)
{
PullB (Registers.PL);
S9xUnpackStatus ();
PullW (Registers.PC);
if (!CheckEmulation())
{
PullB (Registers.PB);
ICPU.ShiftedPB = Registers.PB << 16;
}
else
{
SetFlags (MemoryFlag | IndexFlag);
}
S9xSetPCBase (ICPU.ShiftedPB + Registers.PC);
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
S9xFixCycles();
/* CHECK_FOR_IRQ(); */
}
/**********************************************************************************************/
/* STP/WAI/DB ******************************************************************************** */
// WAI
static void OpCB (void)
{
// Ok, let's just C-ify the ASM versions separately.
#ifdef SA1_OPCODES
SA1.WaitingForInterrupt = TRUE;
SA1.PC--;
#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 USE_NO_WAIT_WHEN_IRQ
if (CPU.IRQActive)
{
#if !defined(SA1_OPCODES) || defined(VAR_CYCLES)
CPU.Cycles += TWO_CYCLES;
#endif
}
else
#endif
{
#ifndef USE_OLD_DSP1
if (DSP1.version == 3) return;
#endif
CPU.WaitingForInterrupt = TRUE;
CPU.PC--;
#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
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
#endif
}
#endif // SA1_OPCODES
}
// STP
static void OpDB (void)
{
CPU.PC--;
CPU.Flags |= DEBUG_MODE_FLAG;
}
// Reserved S9xOpcode
static void Op42 (void)
{
}
/*****************************************************************************/
/*****************************************************************************/
/* CPU-S9xOpcodes Definitions */
/*****************************************************************************/
struct SOpcodes S9xOpcodesM1X1[256] =
{
{Op00}, {Op01M1}, {Op02}, {Op03M1}, {Op04M1}, // 0 - 4
{Op05M1}, {Op06M1}, {Op07M1}, {Op08}, {Op09M1}, // 5 - 9
{Op0AM1}, {Op0B}, {Op0CM1}, {Op0DM1}, {Op0EM1}, // 10 - 14
{Op0FM1}, {Op10}, {Op11M1}, {Op12M1}, {Op13M1}, // 15 - 19
{Op14M1}, {Op15M1}, {Op16M1}, {Op17M1}, {Op18}, // 20 - 24
{Op19M1}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1}, // 25 - 29
{Op1EM1}, {Op1FM1}, {Op20}, {Op21M1}, {Op22}, // 30 - 34
{Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1}, // 35 - 39
{Op28}, {Op29M1}, {Op2AM1}, {Op2B}, {Op2CM1},
{Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30}, {Op31M1},
{Op32M1}, {Op33M1}, {Op34M1}, {Op35M1}, {Op36M1},
{Op37M1}, {Op38}, {Op39M1}, {Op3AM1}, {Op3B},
{Op3CM1}, {Op3DM1}, {Op3EM1}, {Op3FM1}, {Op40},
{Op41M1}, {Op42}, {Op43M1}, {Op44X1}, {Op45M1},
{Op46M1}, {Op47M1}, {Op48M1}, {Op49M1}, {Op4AM1},
{Op4B}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1},
{Op50}, {Op51M1}, {Op52M1}, {Op53M1}, {Op54X1},
{Op55M1}, {Op56M1}, {Op57M1}, {Op58}, {Op59M1},
{Op5AX1}, {Op5B}, {Op5C}, {Op5DM1}, {Op5EM1},
{Op5FM1}, {Op60}, {Op61M1}, {Op62}, {Op63M1},
{Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68M1},
{Op69M1}, {Op6AM1}, {Op6B}, {Op6C}, {Op6DM1},
{Op6EM1}, {Op6FM1}, {Op70}, {Op71M1}, {Op72M1},
{Op73M1}, {Op74M1}, {Op75M1}, {Op76M1}, {Op77M1},
{Op78}, {Op79M1}, {Op7AX1}, {Op7B}, {Op7C},
{Op7DM1}, {Op7EM1}, {Op7FM1}, {Op80}, {Op81M1},
{Op82}, {Op83M1}, {Op84X1}, {Op85M1}, {Op86X1},
{Op87M1}, {Op88X1}, {Op89M1}, {Op8AM1}, {Op8B},
{Op8CX1}, {Op8DM1}, {Op8EX1}, {Op8FM1}, {Op90},
{Op91M1}, {Op92M1}, {Op93M1}, {Op94X1}, {Op95M1},
{Op96X1}, {Op97M1}, {Op98M1}, {Op99M1}, {Op9A},
{Op9BX1}, {Op9CM1}, {Op9DM1}, {Op9EM1}, {Op9FM1},
{OpA0X1}, {OpA1M1}, {OpA2X1}, {OpA3M1}, {OpA4X1},
{OpA5M1}, {OpA6X1}, {OpA7M1}, {OpA8X1}, {OpA9M1},
{OpAAX1}, {OpAB}, {OpACX1}, {OpADM1}, {OpAEX1},
{OpAFM1}, {OpB0}, {OpB1M1}, {OpB2M1}, {OpB3M1},
{OpB4X1}, {OpB5M1}, {OpB6X1}, {OpB7M1}, {OpB8},
{OpB9M1}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM1},
{OpBEX1}, {OpBFM1}, {OpC0X1}, {OpC1M1}, {OpC2},
{OpC3M1}, {OpC4X1}, {OpC5M1}, {OpC6M1}, {OpC7M1},
{OpC8X1}, {OpC9M1}, {OpCAX1}, {OpCB}, {OpCCX1},
{OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0}, {OpD1M1},
{OpD2M1}, {OpD3M1}, {OpD4}, {OpD5M1}, {OpD6M1},
{OpD7M1}, {OpD8}, {OpD9M1}, {OpDAX1}, {OpDB},
{OpDC}, {OpDDM1}, {OpDEM1}, {OpDFM1}, {OpE0X1},
{OpE1M1}, {OpE2}, {OpE3M1}, {OpE4X1}, {OpE5M1},
{OpE6M1}, {OpE7M1}, {OpE8X1}, {OpE9M1}, {OpEA},
{OpEB}, {OpECX1}, {OpEDM1}, {OpEEM1}, {OpEFM1},
{OpF0}, {OpF1M1}, {OpF2M1}, {OpF3M1}, {OpF4},
{OpF5M1}, {OpF6M1}, {OpF7M1}, {OpF8}, {OpF9M1},
{OpFAX1}, {OpFB}, {OpFC}, {OpFDM1}, {OpFEM1},
{OpFFM1}
};
struct SOpcodes S9xOpcodesM1X0[256] =
{
{Op00}, {Op01M1}, {Op02}, {Op03M1}, {Op04M1},
{Op05M1}, {Op06M1}, {Op07M1}, {Op08}, {Op09M1},
{Op0AM1}, {Op0B}, {Op0CM1}, {Op0DM1}, {Op0EM1},
{Op0FM1}, {Op10}, {Op11M1}, {Op12M1}, {Op13M1},
{Op14M1}, {Op15M1}, {Op16M1}, {Op17M1}, {Op18},
{Op19M1}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1},
{Op1EM1}, {Op1FM1}, {Op20}, {Op21M1}, {Op22},
{Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1},
{Op28}, {Op29M1}, {Op2AM1}, {Op2B}, {Op2CM1},
{Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30}, {Op31M1},
{Op32M1}, {Op33M1}, {Op34M1}, {Op35M1}, {Op36M1},
{Op37M1}, {Op38}, {Op39M1}, {Op3AM1}, {Op3B},
{Op3CM1}, {Op3DM1}, {Op3EM1}, {Op3FM1}, {Op40},
{Op41M1}, {Op42}, {Op43M1}, {Op44X0}, {Op45M1},
{Op46M1}, {Op47M1}, {Op48M1}, {Op49M1}, {Op4AM1},
{Op4B}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1},
{Op50}, {Op51M1}, {Op52M1}, {Op53M1}, {Op54X0},
{Op55M1}, {Op56M1}, {Op57M1}, {Op58}, {Op59M1},
{Op5AX0}, {Op5B}, {Op5C}, {Op5DM1}, {Op5EM1},
{Op5FM1}, {Op60}, {Op61M1}, {Op62}, {Op63M1},
{Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68M1},
{Op69M1}, {Op6AM1}, {Op6B}, {Op6C}, {Op6DM1},
{Op6EM1}, {Op6FM1}, {Op70}, {Op71M1}, {Op72M1},
{Op73M1}, {Op74M1}, {Op75M1}, {Op76M1}, {Op77M1},
{Op78}, {Op79M1}, {Op7AX0}, {Op7B}, {Op7C},
{Op7DM1}, {Op7EM1}, {Op7FM1}, {Op80}, {Op81M1},
{Op82}, {Op83M1}, {Op84X0}, {Op85M1}, {Op86X0},
{Op87M1}, {Op88X0}, {Op89M1}, {Op8AM1}, {Op8B},
{Op8CX0}, {Op8DM1}, {Op8EX0}, {Op8FM1}, {Op90},
{Op91M1}, {Op92M1}, {Op93M1}, {Op94X0}, {Op95M1},
{Op96X0}, {Op97M1}, {Op98M1}, {Op99M1}, {Op9A},
{Op9BX0}, {Op9CM1}, {Op9DM1}, {Op9EM1}, {Op9FM1},
{OpA0X0}, {OpA1M1}, {OpA2X0}, {OpA3M1}, {OpA4X0},
{OpA5M1}, {OpA6X0}, {OpA7M1}, {OpA8X0}, {OpA9M1},
{OpAAX0}, {OpAB}, {OpACX0}, {OpADM1}, {OpAEX0},
{OpAFM1}, {OpB0}, {OpB1M1}, {OpB2M1}, {OpB3M1},
{OpB4X0}, {OpB5M1}, {OpB6X0}, {OpB7M1}, {OpB8},
{OpB9M1}, {OpBAX0}, {OpBBX0}, {OpBCX0}, {OpBDM1},
{OpBEX0}, {OpBFM1}, {OpC0X0}, {OpC1M1}, {OpC2},
{OpC3M1}, {OpC4X0}, {OpC5M1}, {OpC6M1}, {OpC7M1},
{OpC8X0}, {OpC9M1}, {OpCAX0}, {OpCB}, {OpCCX0},
{OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0}, {OpD1M1},
{OpD2M1}, {OpD3M1}, {OpD4}, {OpD5M1}, {OpD6M1},
{OpD7M1}, {OpD8}, {OpD9M1}, {OpDAX0}, {OpDB},
{OpDC}, {OpDDM1}, {OpDEM1}, {OpDFM1}, {OpE0X0},
{OpE1M1}, {OpE2}, {OpE3M1}, {OpE4X0}, {OpE5M1},
{OpE6M1}, {OpE7M1}, {OpE8X0}, {OpE9M1}, {OpEA},
{OpEB}, {OpECX0}, {OpEDM1}, {OpEEM1}, {OpEFM1},
{OpF0}, {OpF1M1}, {OpF2M1}, {OpF3M1}, {OpF4},
{OpF5M1}, {OpF6M1}, {OpF7M1}, {OpF8}, {OpF9M1},
{OpFAX0}, {OpFB}, {OpFC}, {OpFDM1}, {OpFEM1},
{OpFFM1}
};
struct SOpcodes S9xOpcodesM0X0[256] =
{
{Op00}, {Op01M0}, {Op02}, {Op03M0}, {Op04M0},
{Op05M0}, {Op06M0}, {Op07M0}, {Op08}, {Op09M0},
{Op0AM0}, {Op0B}, {Op0CM0}, {Op0DM0}, {Op0EM0},
{Op0FM0}, {Op10}, {Op11M0}, {Op12M0}, {Op13M0},
{Op14M0}, {Op15M0}, {Op16M0}, {Op17M0}, {Op18},
{Op19M0}, {Op1AM0}, {Op1B}, {Op1CM0}, {Op1DM0},
{Op1EM0}, {Op1FM0}, {Op20}, {Op21M0}, {Op22},
{Op23M0}, {Op24M0}, {Op25M0}, {Op26M0}, {Op27M0},
{Op28}, {Op29M0}, {Op2AM0}, {Op2B}, {Op2CM0},
{Op2DM0}, {Op2EM0}, {Op2FM0}, {Op30}, {Op31M0},
{Op32M0}, {Op33M0}, {Op34M0}, {Op35M0}, {Op36M0},
{Op37M0}, {Op38}, {Op39M0}, {Op3AM0}, {Op3B},
{Op3CM0}, {Op3DM0}, {Op3EM0}, {Op3FM0}, {Op40},
{Op41M0}, {Op42}, {Op43M0}, {Op44X0}, {Op45M0},
{Op46M0}, {Op47M0}, {Op48M0}, {Op49M0}, {Op4AM0},
{Op4B}, {Op4C}, {Op4DM0}, {Op4EM0}, {Op4FM0},
{Op50}, {Op51M0}, {Op52M0}, {Op53M0}, {Op54X0},
{Op55M0}, {Op56M0}, {Op57M0}, {Op58}, {Op59M0},
{Op5AX0}, {Op5B}, {Op5C}, {Op5DM0}, {Op5EM0},
{Op5FM0}, {Op60}, {Op61M0}, {Op62}, {Op63M0},
{Op64M0}, {Op65M0}, {Op66M0}, {Op67M0}, {Op68M0},
{Op69M0}, {Op6AM0}, {Op6B}, {Op6C}, {Op6DM0},
{Op6EM0}, {Op6FM0}, {Op70}, {Op71M0}, {Op72M0},
{Op73M0}, {Op74M0}, {Op75M0}, {Op76M0}, {Op77M0},
{Op78}, {Op79M0}, {Op7AX0}, {Op7B}, {Op7C},
{Op7DM0}, {Op7EM0}, {Op7FM0}, {Op80}, {Op81M0},
{Op82}, {Op83M0}, {Op84X0}, {Op85M0}, {Op86X0},
{Op87M0}, {Op88X0}, {Op89M0}, {Op8AM0}, {Op8B},
{Op8CX0}, {Op8DM0}, {Op8EX0}, {Op8FM0}, {Op90},
{Op91M0}, {Op92M0}, {Op93M0}, {Op94X0}, {Op95M0},
{Op96X0}, {Op97M0}, {Op98M0}, {Op99M0}, {Op9A},
{Op9BX0}, {Op9CM0}, {Op9DM0}, {Op9EM0}, {Op9FM0},
{OpA0X0}, {OpA1M0}, {OpA2X0}, {OpA3M0}, {OpA4X0},
{OpA5M0}, {OpA6X0}, {OpA7M0}, {OpA8X0}, {OpA9M0},
{OpAAX0}, {OpAB}, {OpACX0}, {OpADM0}, {OpAEX0},
{OpAFM0}, {OpB0}, {OpB1M0}, {OpB2M0}, {OpB3M0},
{OpB4X0}, {OpB5M0}, {OpB6X0}, {OpB7M0}, {OpB8},
{OpB9M0}, {OpBAX0}, {OpBBX0}, {OpBCX0}, {OpBDM0},
{OpBEX0}, {OpBFM0}, {OpC0X0}, {OpC1M0}, {OpC2},
{OpC3M0}, {OpC4X0}, {OpC5M0}, {OpC6M0}, {OpC7M0},
{OpC8X0}, {OpC9M0}, {OpCAX0}, {OpCB}, {OpCCX0},
{OpCDM0}, {OpCEM0}, {OpCFM0}, {OpD0}, {OpD1M0},
{OpD2M0}, {OpD3M0}, {OpD4}, {OpD5M0}, {OpD6M0},
{OpD7M0}, {OpD8}, {OpD9M0}, {OpDAX0}, {OpDB},
{OpDC}, {OpDDM0}, {OpDEM0}, {OpDFM0}, {OpE0X0},
{OpE1M0}, {OpE2}, {OpE3M0}, {OpE4X0}, {OpE5M0},
{OpE6M0}, {OpE7M0}, {OpE8X0}, {OpE9M0}, {OpEA},
{OpEB}, {OpECX0}, {OpEDM0}, {OpEEM0}, {OpEFM0},
{OpF0}, {OpF1M0}, {OpF2M0}, {OpF3M0}, {OpF4},
{OpF5M0}, {OpF6M0}, {OpF7M0}, {OpF8}, {OpF9M0},
{OpFAX0}, {OpFB}, {OpFC}, {OpFDM0}, {OpFEM0},
{OpFFM0}
};
struct SOpcodes S9xOpcodesM0X1[256] =
{
{Op00}, {Op01M0}, {Op02}, {Op03M0}, {Op04M0}, // 0 - 4
{Op05M0}, {Op06M0}, {Op07M0}, {Op08}, {Op09M0}, // 5 - 9
{Op0AM0}, {Op0B}, {Op0CM0}, {Op0DM0}, {Op0EM0}, // 10
{Op0FM0}, {Op10}, {Op11M0}, {Op12M0}, {Op13M0}, // 15
{Op14M0}, {Op15M0}, {Op16M0}, {Op17M0}, {Op18}, // 20
{Op19M0}, {Op1AM0}, {Op1B}, {Op1CM0}, {Op1DM0}, // 25
{Op1EM0}, {Op1FM0}, {Op20}, {Op21M0}, {Op22}, // 30
{Op23M0}, {Op24M0}, {Op25M0}, {Op26M0}, {Op27M0}, // 35
{Op28}, {Op29M0}, {Op2AM0}, {Op2B}, {Op2CM0}, // 40
{Op2DM0}, {Op2EM0}, {Op2FM0}, {Op30}, {Op31M0}, // 45
{Op32M0}, {Op33M0}, {Op34M0}, {Op35M0}, {Op36M0}, // 50
{Op37M0}, {Op38}, {Op39M0}, {Op3AM0}, {Op3B}, // 55
{Op3CM0}, {Op3DM0}, {Op3EM0}, {Op3FM0}, {Op40}, // 60
{Op41M0}, {Op42}, {Op43M0}, {Op44X1}, {Op45M0}, // 65
{Op46M0}, {Op47M0}, {Op48M0}, {Op49M0}, {Op4AM0}, // 70
{Op4B}, {Op4C}, {Op4DM0}, {Op4EM0}, {Op4FM0}, // 75
{Op50}, {Op51M0}, {Op52M0}, {Op53M0}, {Op54X1}, // 80
{Op55M0}, {Op56M0}, {Op57M0}, {Op58}, {Op59M0}, // 85
{Op5AX1}, {Op5B}, {Op5C}, {Op5DM0}, {Op5EM0}, // 90
{Op5FM0}, {Op60}, {Op61M0}, {Op62}, {Op63M0}, // 95
{Op64M0}, {Op65M0}, {Op66M0}, {Op67M0}, {Op68M0}, // 100
{Op69M0}, {Op6AM0}, {Op6B}, {Op6C}, {Op6DM0}, // 105
{Op6EM0}, {Op6FM0}, {Op70}, {Op71M0}, {Op72M0}, // 110
{Op73M0}, {Op74M0}, {Op75M0}, {Op76M0}, {Op77M0}, // 115
{Op78}, {Op79M0}, {Op7AX1}, {Op7B}, {Op7C}, // 120
{Op7DM0}, {Op7EM0}, {Op7FM0}, {Op80}, {Op81M0}, // 125
{Op82}, {Op83M0}, {Op84X1}, {Op85M0}, {Op86X1}, // 130
{Op87M0}, {Op88X1}, {Op89M0}, {Op8AM0}, {Op8B}, // 135
{Op8CX1}, {Op8DM0}, {Op8EX1}, {Op8FM0}, {Op90}, // 140
{Op91M0}, {Op92M0}, {Op93M0}, {Op94X1}, {Op95M0}, // 145
{Op96X1}, {Op97M0}, {Op98M0}, {Op99M0}, {Op9A},
{Op9BX1}, {Op9CM0}, {Op9DM0}, {Op9EM0}, {Op9FM0},
{OpA0X1}, {OpA1M0}, {OpA2X1}, {OpA3M0}, {OpA4X1},
{OpA5M0}, {OpA6X1}, {OpA7M0}, {OpA8X1}, {OpA9M0},
{OpAAX1}, {OpAB}, {OpACX1}, {OpADM0}, {OpAEX1},
{OpAFM0}, {OpB0}, {OpB1M0}, {OpB2M0}, {OpB3M0},
{OpB4X1}, {OpB5M0}, {OpB6X1}, {OpB7M0}, {OpB8},
{OpB9M0}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM0},
{OpBEX1}, {OpBFM0}, {OpC0X1}, {OpC1M0}, {OpC2},
{OpC3M0}, {OpC4X1}, {OpC5M0}, {OpC6M0}, {OpC7M0},
{OpC8X1}, {OpC9M0}, {OpCAX1}, {OpCB}, {OpCCX1},
{OpCDM0}, {OpCEM0}, {OpCFM0}, {OpD0}, {OpD1M0},
{OpD2M0}, {OpD3M0}, {OpD4}, {OpD5M0}, {OpD6M0},
{OpD7M0}, {OpD8}, {OpD9M0}, {OpDAX1}, {OpDB},
{OpDC}, {OpDDM0}, {OpDEM0}, {OpDFM0}, {OpE0X1},
{OpE1M0}, {OpE2}, {OpE3M0}, {OpE4X1}, {OpE5M0},
{OpE6M0}, {OpE7M0}, {OpE8X1}, {OpE9M0}, {OpEA},
{OpEB}, {OpECX1}, {OpEDM0}, {OpEEM0}, {OpEFM0},
{OpF0}, {OpF1M0}, {OpF2M0}, {OpF3M0}, {OpF4},
{OpF5M0}, {OpF6M0}, {OpF7M0}, {OpF8}, {OpF9M0},
{OpFAX1}, {OpFB}, {OpFC}, {OpFDM0}, {OpFEM0},
{OpFFM0}
};
/*
#endif
#if defined(ZSNES_FX)
*/
struct SOpcodes S9xOpcodesE1[256] =
{
{Op00}, {Op01M1}, {Op02}, {Op03M1}, {Op04M1},
{Op05M1}, {Op06M1}, {Op07M1}, {Op08E1}, {Op09M1},
{Op0AM1}, {Op0BE1}, {Op0CM1}, {Op0DM1}, {Op0EM1},
{Op0FM1}, {Op10}, {Op11M1}, {Op12M1}, {Op13M1},
{Op14M1}, {Op15M1}, {Op16M1}, {Op17M1}, {Op18},
{Op19M1}, {Op1AM1}, {Op1B}, {Op1CM1}, {Op1DM1},
{Op1EM1}, {Op1FM1}, {Op20}, {Op21M1}, {Op22E1},
{Op23M1}, {Op24M1}, {Op25M1}, {Op26M1}, {Op27M1},
{Op28}, {Op29M1}, {Op2AM1}, {Op2BE1}, {Op2CM1},
{Op2DM1}, {Op2EM1}, {Op2FM1}, {Op30}, {Op31M1},
{Op32M1}, {Op33M1}, {Op34M1}, {Op35M1}, {Op36M1},
{Op37M1}, {Op38}, {Op39M1}, {Op3AM1}, {Op3B},
{Op3CM1}, {Op3DM1}, {Op3EM1}, {Op3FM1}, {Op40},
{Op41M1}, {Op42}, {Op43M1}, {Op44X1}, {Op45M1},
{Op46M1}, {Op47M1}, {Op48E1}, {Op49M1}, {Op4AM1},
{Op4BE1}, {Op4C}, {Op4DM1}, {Op4EM1}, {Op4FM1},
{Op50}, {Op51M1}, {Op52M1}, {Op53M1}, {Op54X1},
{Op55M1}, {Op56M1}, {Op57M1}, {Op58}, {Op59M1},
{Op5AE1}, {Op5B}, {Op5C}, {Op5DM1}, {Op5EM1},
{Op5FM1}, {Op60}, {Op61M1}, {Op62E1}, {Op63M1},
{Op64M1}, {Op65M1}, {Op66M1}, {Op67M1}, {Op68E1},
{Op69M1}, {Op6AM1}, {Op6BE1}, {Op6C}, {Op6DM1},
{Op6EM1}, {Op6FM1}, {Op70}, {Op71M1}, {Op72M1},
{Op73M1}, {Op74M1}, {Op75M1}, {Op76M1}, {Op77M1},
{Op78}, {Op79M1}, {Op7AE1}, {Op7B}, {Op7C},
{Op7DM1}, {Op7EM1}, {Op7FM1}, {Op80}, {Op81M1},
{Op82}, {Op83M1}, {Op84X1}, {Op85M1}, {Op86X1},
{Op87M1}, {Op88X1}, {Op89M1}, {Op8AM1}, {Op8BE1},
{Op8CX1}, {Op8DM1}, {Op8EX1}, {Op8FM1}, {Op90},
{Op91M1}, {Op92M1}, {Op93M1}, {Op94X1}, {Op95M1},
{Op96X1}, {Op97M1}, {Op98M1}, {Op99M1}, {Op9A},
{Op9BX1}, {Op9CM1}, {Op9DM1}, {Op9EM1}, {Op9FM1},
{OpA0X1}, {OpA1M1}, {OpA2X1}, {OpA3M1}, {OpA4X1},
{OpA5M1}, {OpA6X1}, {OpA7M1}, {OpA8X1}, {OpA9M1},
{OpAAX1}, {OpABE1}, {OpACX1}, {OpADM1}, {OpAEX1},
{OpAFM1}, {OpB0}, {OpB1M1}, {OpB2M1}, {OpB3M1},
{OpB4X1}, {OpB5M1}, {OpB6X1}, {OpB7M1}, {OpB8},
{OpB9M1}, {OpBAX1}, {OpBBX1}, {OpBCX1}, {OpBDM1},
{OpBEX1}, {OpBFM1}, {OpC0X1}, {OpC1M1}, {OpC2},
{OpC3M1}, {OpC4X1}, {OpC5M1}, {OpC6M1}, {OpC7M1},
{OpC8X1}, {OpC9M1}, {OpCAX1}, {OpCB}, {OpCCX1},
{OpCDM1}, {OpCEM1}, {OpCFM1}, {OpD0}, {OpD1M1},
{OpD2M1}, {OpD3M1}, {OpD4E1}, {OpD5M1}, {OpD6M1},
{OpD7M1}, {OpD8}, {OpD9M1}, {OpDAE1}, {OpDB},
{OpDC}, {OpDDM1}, {OpDEM1}, {OpDFM1}, {OpE0X1},
{OpE1M1}, {OpE2}, {OpE3M1}, {OpE4X1}, {OpE5M1},
{OpE6M1}, {OpE7M1}, {OpE8X1}, {OpE9M1}, {OpEA},
{OpEB}, {OpECX1}, {OpEDM1}, {OpEEM1}, {OpEFM1},
{OpF0}, {OpF1M1}, {OpF2M1}, {OpF3M1}, {OpF4E1},
{OpF5M1}, {OpF6M1}, {OpF7M1}, {OpF8}, {OpF9M1},
{OpFAE1}, {OpFB}, {OpFCE1}, {OpFDM1}, {OpFEM1},
{OpFFM1}
};
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment