Subversion Repositories pspware

Compare Revisions

Ignore whitespace Rev 38 → Rev 39

/tags/initial/snes9x/65c816.h
New file
0,0 → 1,172
/*******************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
Jerremy Koot (jkoot@snes9x.com)
 
(c) Copyright 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.
*******************************************************************************/
 
#ifndef _65c816_h_
#define _65c816_h_
 
#define AL A.B.l
#define AH A.B.h
#define XL X.B.l
#define XH X.B.h
#define YL Y.B.l
#define YH Y.B.h
#define SL S.B.l
#define SH S.B.h
#define DL D.B.l
#define DH D.B.h
#define PL P.B.l
#define PH P.B.h
 
#define Carry 1
#define Zero 2
#define IRQ 4
#define Decimal 8
#define IndexFlag 16
#define MemoryFlag 32
#define Overflow 64
#define Negative 128
#define Emulation 256
 
#define ClearCarry() (ICPU._Carry = 0)
#define SetCarry() (ICPU._Carry = 1)
#define SetZero() (ICPU._Zero = 0)
#define ClearZero() (ICPU._Zero = 1)
#define SetIRQ() (Registers.PL |= IRQ)
#define ClearIRQ() (Registers.PL &= ~IRQ)
#define SetDecimal() (Registers.PL |= Decimal)
#define ClearDecimal() (Registers.PL &= ~Decimal)
#define SetIndex() (Registers.PL |= IndexFlag)
#define ClearIndex() (Registers.PL &= ~IndexFlag)
#define SetMemory() (Registers.PL |= MemoryFlag)
#define ClearMemory() (Registers.PL &= ~MemoryFlag)
#define SetOverflow() (ICPU._Overflow = 1)
#define ClearOverflow() (ICPU._Overflow = 0)
#define SetNegative() (ICPU._Negative = 0x80)
#define ClearNegative() (ICPU._Negative = 0)
 
#define CheckZero() (ICPU._Zero == 0)
#define CheckCarry() (ICPU._Carry)
#define CheckIRQ() (Registers.PL & IRQ)
#define CheckDecimal() (Registers.PL & Decimal)
#define CheckIndex() (Registers.PL & IndexFlag)
#define CheckMemory() (Registers.PL & MemoryFlag)
#define CheckOverflow() (ICPU._Overflow)
#define CheckNegative() (ICPU._Negative & 0x80)
#define CheckEmulation() (Registers.P.W & Emulation)
 
#define ClearFlags(f) (Registers.P.W &= ~(f))
#define SetFlags(f) (Registers.P.W |= (f))
#define CheckFlag(f) (Registers.PL & (f))
 
typedef union
{
#ifdef LSB_FIRST
struct { uint8 l,h; } B;
#else
struct { uint8 h,l; } B;
#endif
uint16 W;
} pair;
 
struct SRegisters{
uint8 PB;
uint8 DB;
pair P;
pair A;
pair D;
pair S;
pair X;
pair Y;
uint16 PC;
};
 
EXTERN_C struct SRegisters Registers;
 
#endif
 
/tags/initial/snes9x/Makefile.in
New file
0,0 → 1,397
@ZSNESFX@
@ZSNESC4@
@ASMCPU@
@SPC700ASM@
NETPLAY=1
UNZIP=1
@JMA@
@GLIDE@
@OPENGL@
@AIDO@
#GUI=0
@THREAD_SOUND@
@ASMKREED@
@SDD1_DECOMP@
#SDD1_VERIFY=0
@DREAMCAST@
CHEATS=1
2XSAI=1
 
#Fairly good and special-char-safe descriptor of the os being built on.
OS=`uname -s -r -m|sed \"s/ /-/g\"|tr \"[A-Z]\" \"[a-z]\"|tr \"/()\" \"___\"`
BUILDDIR=.
#BUILDDIR=build/$(OS)
VPATH = @srcdir@
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
 
ifdef DREAMCAST
CPU=sh
ASMCPU=1
CHEATS=0
2XSAI=0
else
CPU=i386
endif
 
ifdef ZSNESFX
FXOBJ=$(CPU)/fxemu2b.o $(CPU)/fxemu2.o $(CPU)/fxemu2c.o $(CPU)/fxtable.o $(CPU)/sfxproc.o $(CPU)/ZSNES.O
FXDEFINES=-DZSNES_FX -DEXECUTE_SUPERFX_PER_LINE
FXDEPENDS=zsnes_fx
FXNO_DEPENDS=c_fx
else
FXOBJ=fxinst.o fxemu.o fxdbg.o
FXDEFINES=-DEXECUTE_SUPERFX_PER_LINE
FXDEPENDS=c_fx
FXNO_DEPENDS=zsnes_fx
endif
 
ifdef ZSNESC4
C4OBJ=$(CPU)/C4.O $(CPU)/zsnesc4.o c4.o
C4DEFINES=-DZSNES_C4
C4DEPENDS=zsnes_c4
C4NO_DEPENDS=c_c4
else
C4OBJ=c4.o c4emu.o
C4DEFINES=
C4DEPENDS=c_c4
C4NO_DEPENDS=zsnes_c4
endif
 
ifdef SPC700ASM
SOUNDOBJ=spctool/spc700.o spctool/dsp.o spctool.o spctool/soundmod.o @I386SPC@
SOUNDDEFINES=-DSPCTOOL
else
SOUNDOBJ=spc700.o soundux.o apu.o @I386SPC@
SOUNDDEFINES=-DSPC700_C
endif
 
ifdef ASMCPU
CPUOBJ=$(CPU)/cpuops.o $(CPU)/cpuexec.o $(CPU)/sa1ops.o
else
CPUOBJ=cpuops.o cpuexec.o sa1cpu.o
endif
 
ifdef DREAMCAST
PLATFORMOBJ=dc/input.o dc/display.o dc/sound.o \
dc/dc.o dc/menu.o dc/trace.o dc/lcd.o \
dc/lain_blanker.o dc/td.o dc/md5.o
else
PLATFORMOBJ=unix/unix.o unix/config.o
endif
 
ifdef CHEATS
CHEATOBJ=cheats.o cheats2.o
endif
 
ifndef DREAMCAST
SNAPOBJ = snaporig.o snapshot.o
SCREENSHOTOBJ = screenshot.o
MOVIEOBJ = movie.o
endif
 
ifdef 2XSAI
ifdef ASMKREED
KREEDOBJ=$(CPU)/2XSAIMMX.O $(CPU)/bilinear.o 2xsai.o
KREEDDEFINES=-DMMX
else
KREEDOBJ=2xsai.o
endif
endif
 
ifdef SDD1_DECOMP
SDD1OBJ=sdd1emu.o
ifdef SDD1_VERIFY
SDD1DEFINES=-DSDD1_DECOMP -DSDD1_VERIFY
else
SDD1DEFINES=-DSDD1_DECOMP
endif
endif
 
SPC7110OBJ=spc7110.o
OBC1OBJ=obc1.o
SETAOBJ=seta.o seta010.o seta011.o seta018.o
 
OBJECTS=$(CPUOBJ) $(SOUNDOBJ) apudebug.o $(FXOBJ) $(C4OBJ) \
cpu.o sa1.o debug.o sdd1.o tile.o srtc.o gfx.o memmap.o clip.o \
dsp1.o ppu.o dma.o snes9x.o data.o globals.o \
$(SPC7110OBJ) $(OBC1OBJ) $(SETAOBJ) $(KREEDOBJ) $(SDD1OBJ) \
$(CHEATOBJ) $(PLATFORMOBJ) $(SNAPOBJ) $(SCREENSHOTOBJ) $(MOVIEOBJ)
 
ifdef NETPLAY
OBJECTS += netplay.o server.o
NETPLAYDEFINES=-DNETPLAY_SUPPORT
SERVER_OBJECTS=server.o
endif
 
ifdef UNZIP
OBJECTS += loadzip.o unzip/unzip.o unzip/explode.o unzip/unreduce.o unzip/unshrink.o
UNZIPDEFINES=-DUNZIP_SUPPORT
endif
 
ifdef JMA
OBJECTS += jma/s9x-jma.o jma/7zlzma.o jma/crc32.o jma/iiostrm.o jma/inbyte.o\
jma/jma.o jma/lzma.o jma/lzmadec.o jma/winout.o
JMADEFINES=-DJMA_SUPPORT -fexceptions
endif
 
ifdef THREAD_SOUND
CPUDEFINES += -DUSE_THREADS
EXTRALIBS += -lpthread
endif
 
ifdef GLIDE
GLIDEOBJS = unix/glide.o
GLIDEDEFINES = -DUSE_GLIDE -I/usr/include/glide
GLIDELIBS = -lglide2x
endif
 
ifdef OPENGL
OPENGLOBJS = unix/opengl.o
OPENGLDEFINES = -DUSE_OPENGL
OPENGLLIBS = -lGL -lGLU -ldl
endif
 
ifdef AIDO
AIDOOBJS = unix/aido.o
AIDODEFINES = -DUSE_AIDO
endif
 
JOYDEFINES = @JOYDEFINES@
 
ifdef DREAMCAST
CCC = sh-elf-c++ -fno-rtti
CC = sh-elf-gcc
NASM = fail
GASM = fail
else
CCC = @CXX@ @RTTIFLAG@
CC = @CC@
NASM = @NASM@
GASM = @CXX@
endif
 
ifdef DREAMCAST
INCLUDES = -I$(srcdir)/dc
DEFS = -DDC
else
INCLUDES = @X_INCLUDES@
DEFS = -DMITSHM
endif
 
INCLUDES += -I$(srcdir) -I$(srcdir)/unzip @CPUINC@
 
ifdef DREAMCAST
OPTIMISE=-O4 -ffreestanding -ffast-math -fschedule-insns2 -fomit-frame-pointer -fno-inline-functions -fno-defer-pop -fforce-addr -fstrict-aliasing -funroll-loops -fdelete-null-pointer-checks -fno-exceptions
CPUFLAGS=-ml -m4-single-only
else
OPTIMISE = @OPTIMIZE@
endif
 
DEFS += \
-DVAR_CYCLES \
-DCPU_SHUTDOWN \
-DSPC700_SHUTDOWN \
$(FXDEFINES) \
$(C4DEFINES) \
$(CPUDEFINES) \
$(SOUNDDEFINES) \
$(NETPLAYDEFINES) \
$(UNZIPDEFINES) \
$(JMADEFINES) \
$(GLIDEDEFINES) \
$(OPENGLDEFINES) \
$(AIDODEFINES) \
$(KREEDDEFINES) \
$(SDD1DEFINES) \
$(JOYDEFINES) \
-DNO_INLINE_SET_GET @SYSDEFINES@
 
#-DOLD_COLOUR_BLENDING
#-DSOUND
#-DDEBUGGER
#-DNO_INLINE_SET_GET
#-DVAR_CYCLES
#-DCPU_SHUTDOWN
#-DSPC700_SHUTDOWN
 
CCFLAGS = $(OPTIMISE) $(CPUFLAGS) $(INCLUDES) $(DEFS)
 
CFLAGS=$(CCFLAGS)
 
.SUFFIXES: .o .cpp .c .cc .h .m .i .S .asm .obj .O .CPP .C .ASM
#FIXME: Why is this set statically?
#LDLIBS = -L/usr/X11R6/lib
# -L../zlib
 
ifdef GLIDE
SNES9XBIN=gsnes9x
else
ifdef OPENGL
SNES9XBIN=osnes9x
else
SNES9XBIN=snes9x
endif
endif
 
all: Makefile configure directories offsets $(SNES9XBIN)
 
Makefile: configure Makefile.in
@echo "Makefile is older than configure or in-file. Run configure or touch Makefile."
exit 1
 
configure: configure.in
@echo "configure is older than in-file. Run autoconf or touch configure."
exit 1
 
#ggisnes9x
 
#FIXME: Make this more portable and add install.sh, maybe add strip
install: all
install -D $(SNES9XBIN) "$(exec_prefix)/bin/$(SNES9XBIN)"
 
directories:
@test -d $(CPU) || mkdir $(CPU)
@test -d unix || mkdir unix
@test -d unzip || mkdir unzip
@test -d jma || mkdir jma
 
offsets: offsets.o
$(CCC) $(INCLUDES) -o $@ offsets.o
./offsets >$(srcdir)/$(CPU)/offsets.h #FIXME: Move to builddir
 
snes9x: $(OBJECTS) unix/x11.o $(AIDOOBJS)
$(CCC) $(INCLUDES) -o $@ $(OBJECTS) $(AIDOOBJS) $(GLIDEOBJS) $(OPENGLOBJS) unix/x11.o $(LDLIBS) $(GLIDELIBS) $(OPENGLLIBS) @SYSLIBS@ -lXext -lX11 $(EXTRALIBS) -lm
 
ssnes9x: $(OBJECTS) unix/svga.o
$(CCC) $(INCLUDES) -o $@ $(OBJECTS) $(GLIDEOBJS) unix/svga.o $(LDLIBS) $(GLIDELIBS) @SYSLIBS@ -lvga -lvgagl $(EXTRALIBS) -lm
 
gsnes9x: $(OBJECTS) $(GLIDEOBJS)
$(CCC) $(INCLUDES) -o $@ $(OBJECTS) $(GLIDEOBJS) $(LDLIBS) @SYSLIBS@ -lglide $(EXTRALIBS) -lm
 
ggisnes9x: $(OBJECTS) unix/ggi.o
$(CCC) $(INCLUDES) -o $@ $(OBJECTS) unix/ggi.o $(LDLIBS) @SYSLIBS@ -lggi $(EXTRALIBS) -lm
 
osnes9x: $(OBJECTS) unix/x11.o $(OPENGLOBJS)
$(CCC) $(INCLUDES) -o $@ $(OBJECTS) unix/x11.o $(OPENGLOBJS) $(LDLIBS) $(OPENGLLIBS) @SYSLIBS@ -lXext -lX11 $(EXTRALIBS) -lm
 
s9xserver: $(SERVER_OBJECTS)
$(CCC) $(INCLUDES) -o $@ $(SERVER_OBJECTS)
 
.cpp.o:
$(CCC) $(INCLUDES) -c $(CCFLAGS) $(srcdir)/$*.cpp -o $@
 
.c.o:
$(CC) $(INCLUDES) -c $(CCFLAGS) $(srcdir)/$*.c -o $@
 
.cpp.S:
$(GASM) $(INCLUDES) -S $(CCFLAGS) $(srcdir)/$*.cpp -o $@
 
.cpp.i:
$(GASM) $(INCLUDES) -E $(CCFLAGS) $(srcdir)/$*.cpp -o $@
 
.S.o:
$(GASM) $(INCLUDES) -c $(CCFLAGS) $(srcdir)/$*.S -o $@
 
.S.i:
$(GASM) $(INCLUDES) -c -E $(CCFLAGS) $(srcdir)/$*.S -o $@
 
.s.o:
@echo Compiling $*.s
sh-elf-as -little $(srcdir)/$*.s -o $@
 
.asm.o:
$(NASM) -f elf $(FXDEFINES) -I$(srcdir)/ -I$(srcdir)/$(CPU)/ -o $@ $(srcdir)/$*.asm
 
.obj.o:
cp $*.obj $*.o
 
.CPP.O:
$(CCC) $(INCLUDES) -c $(CCFLAGS) -x c++ $(srcdir)/$*.CPP -o $@
 
.C.O:
$(CC) $(INCLUDES) -c $(CCFLAGS) $(srcdir)/$*.C -o $@
 
.ASM.O:
$(NASM) -f elf $(FXDEFINES) -I$(srcdir)/ -I$(srcdir)/$(CPU)/ $(srcdir)/$*.ASM -o $@
 
unix/moc_snes9x_gui.cpp: unix/snes9x_gui.h
$(MOC) unix/snes9x_gui.h -o $@
 
clean:
rm -f $(OBJECTS) $(CPU)/offsets.h offsets.o unix/svga.o unix/aido.o unix/x11.o unix/ggi.o unix/xf86.o unix/glide.o
 
#release: CCFLAGS += -DNO_DEBUGGER
 
_bin-package:
RELNR=`grep "#define VERSION" snes9x.h | sed -e 's/"//g' | awk '{ print $$3 }'` && \
echo $$RELNR && \
RELNAME=snes9x-$${RELNR} && export RELNAME && \
test \! -f $${RELNAME}.tar.gz && \
DISTDIR=disttmp/$${RELNAME}/ && \
rm -rf disttmp && \
mkdir disttmp && \
mkdir $${DISTDIR} && \
cp snes9x $${DISTDIR} && \
cp config.info hardware.txt problems.txt changes.txt ../faqs.txt ../readme.txt ../readme.unix $${DISTDIR} && \
(cd disttmp && tar cvf - $${RELNAME}) | gzip -c > $${RELNAME}.tar.gz &&\
rm -rf disttmp
 
#FIXME: Should possibly have clean, but not in xenofarm build
bin-release: snes9x _bin-package
 
#FIXME: Intelligent messages when bailing out.
#FIXME: See those ls:s? Don't look to closely at the statements...
_src-package:
RELNR=`grep "#define VERSION" snes9x.h | sed -e 's/"//g' | awk '{ print $$3 }'` && \
echo $$RELNR && \
RELNAME=snes9x-$${RELNR}-src && \
test \! -f $${RELNAME}.tar.gz && \
test \! `ls *~` && \
test \! `ls *.o` && \
test \! -f snes9x && \
export RELNR && export RELNAME && \
(cd .. && PWD=`pwd` && SNESDIR=`basename $$PWD` && cd .. && \
DISTDIR=disttmp/$${RELNAME} && \
rm -rf disttmp && \
mkdir disttmp && \
cp -r $${SNESDIR} $${DISTDIR} && \
rm -f $${DISTDIR}/snes9x/config.* 2>/dev/null && \
rm -f $${DISTDIR}/snes9x/conftezt.out.* 2>/dev/null && \
rm -rf $${DISTDIR}/snes9x/autom4te.cache 2>/dev/null && \
rm $${DISTDIR}/snes9x/Makefile && \
find disttmp -name CVS -type f -exec rm "{}" \; && \
find disttmp -name CVS -type d -exec rm "{}" \; && \
(cd disttmp && tar cvf - $${RELNAME}) | gzip -c > $${RELNAME}.tar.gz && \
mv $${RELNAME}.tar.gz $${SNESDIR}/snes9x/ ) && \
rm -rf disttmp
 
#Requires:
# 1. Prestine checkout
# 2. `autoconf`
# 3. `./configure`
src-release: depend _src-package
 
xenofarm:
./xenofarm.sh
cd build/xenofarm && tar cf - . > ../../../xenofarm_result.tar
gzip -f9 ../xenofarm_result.tar
 
# And now for the impressive testsuite:
verify: snes9x
./snes9x --selftest
 
#FIXME: Make a auto-self-reference.
depend:
$(CC) $(CFLAGS) -MM -MG \
`find . '(' -name '*.c' -o -name '*.cpp' -o -name '*.S' ')' -print -o -name msdos -prune` \
| sed -e 's@^[^ :]*: *\([^ ]*/\)[^ /]*@\1&@' \
>dependencies
 
#NOTE: Not VPATH safe
TAGS: *.c *.h unix/*.c unix/*.h unzip/*.c unzip/*.h jma/*.cpp jma/*.h
-etags *.c *.h unix/*.c unix/*.h unzip/*.c unzip/*.h jma/*.cpp jma/*.h
 
include dependencies
 
/tags/initial/snes9x/snapshot.h
New file
0,0 → 1,118
/*******************************************************************************
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.
*******************************************************************************/
#ifndef _SNAPSHOT_H_
#define _SNAPSHOT_H_
 
#include <stdio.h>
#include "snes9x.h"
 
#define SNAPSHOT_MAGIC "#!snes9x"
#define SNAPSHOT_VERSION 1
 
#define SUCCESS 1
#define WRONG_FORMAT (-1)
#define WRONG_VERSION (-2)
#define FILE_NOT_FOUND (-3)
#define WRONG_MOVIE_SNAPSHOT (-4)
#define NOT_A_MOVIE_SNAPSHOT (-5)
 
START_EXTERN_C
bool8 S9xFreezeGame (const char *filename);
int S9xFreezeGameToBuffer (void *data);
bool8 S9xUnfreezeGame (const char *filename);
bool8 Snapshot (const char *filename);
bool8 S9xLoadSnapshot (const char *filename);
bool8 S9xSPCDump (const char *filename);
void S9xFreezeToStream (STREAM);
int S9xUnfreezeFromStream (STREAM);
int S9xFreezeToBuffer (void* buffer);
END_EXTERN_C
 
#endif
 
/tags/initial/snes9x/2xsaiwin.cpp
New file
0,0 → 1,747
/*******************************************************************************
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.
*******************************************************************************/
 
//#define MMX
 
#include "snes9x/snes9x.h"
#include "snes9x/port.h"
#include "snes9x/gfx.h"
 
#ifdef MMX
EXTERN_C void _2xSaILine (uint8 *srcPtr, uint8 *deltaPtr, uint32 srcPitch, uint32 width,
uint8 *dstPtr, uint32 dstPitch);
EXTERN_C void _2xSaISuperEagleLine (uint8 *srcPtr, uint8 *deltaPtr, uint32 srcPitch, uint32 width,
uint8 *dstPtr, uint32 dstPitch);
EXTERN_C int Init_2xSaIMMX (uint32 BitFormat);
#endif
 
bool mmx_cpu = false;
 
static uint32 colorMask = 0xF7DEF7DE;
static uint32 lowPixelMask = 0x08210821;
static uint32 qcolorMask = 0xE79CE79C;
static uint32 qlowpixelMask = 0x18631863;
 
 
int Init_2xSaI(uint32 BitFormat)
{
if (BitFormat == 565)
{
colorMask = 0xF7DEF7DE;
lowPixelMask = 0x08210821;
qcolorMask = 0xE79CE79C;
qlowpixelMask = 0x18631863;
}
else
if (BitFormat == 555)
{
colorMask = 0x7BDE7BDE;
lowPixelMask = 0x04210421;
qcolorMask = 0x739C739C;
qlowpixelMask = 0x0C630C63;
}
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 HOR
#define VER
void Super2xSaI(uint8 *srcPtr, uint32 srcPitch,
uint8 *deltaPtr,
uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
uint32 *dP;
uint16 *bP;
 
#ifdef MMX_BLA //no MMX version yet
if (cpu_mmx && width != 512)
{
for (height; height; height-=1)
{
bP = (uint16 *) srcPtr;
xP = (uint16 *) deltaPtr;
dP = (uint32 *) dstPtr;
_2xSaISuperEagleLine ((uint8 *) bP, (uint8 *) xP, srcPitch, width, (uint8 *) dP, dstPitch);
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}
}
else
{
#endif
uint32 Nextline = srcPitch >> 1;
 
for (height; height; height-=1)
{
bP = (uint16 *) srcPtr;
dP = (uint32 *) dstPtr;
for (uint32 finish = width; finish; finish -= 1 )
{
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 && color5 != 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
{
 
#ifdef VER
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
#endif
product2b = INTERPOLATE (color2, color3);
 
#ifdef VER
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
#endif
product1b = INTERPOLATE (color5, color6);
}
 
#ifdef HOR
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
#endif
product2a = color2;
 
#ifdef HOR
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
#endif
product1a = color5;
 
 
product1a = product1a | (product1b << 16);
product2a = product2a | (product2b << 16);
 
*(dP) = product1a;
*(dP+(dstPitch>>2)) = product2a;
 
bP += 1;
dP += 1;
}//end of for ( finish= width etc..)
 
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}; //endof: for (height; height; height--)
#ifdef MMX_BLA
}
#endif
}
 
 
 
 
 
 
/*ONLY use with 640x480x16 or higher resolutions*/
/*Only use this if 2*width * 2*height fits on the current screen*/
void SuperEagle(uint8 *srcPtr, uint32 srcPitch,
uint8 *deltaPtr,
uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
uint32 *dP;
uint16 *bP;
uint16 *xP;
 
#ifdef MMX
if (mmx_cpu && width != 512)
{
for (height; height; height-=1)
{
bP = (uint16 *) srcPtr;
xP = (uint16 *) deltaPtr;
dP = (uint32 *) dstPtr;
_2xSaISuperEagleLine ((uint8 *) bP, (uint8 *) xP, srcPitch, width, (uint8 *)dP, dstPitch);
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}
}
else
{
#endif
uint32 Nextline = srcPitch >> 1;
 
for (height; height; height-=1)
{
bP = (uint16 *) srcPtr;
dP = (uint32 *) dstPtr;
for (uint32 finish = width; finish; finish -= 1 )
{
 
uint32 color4, color5, color6;
uint32 color1, color2, color3;
uint32 colorA0, colorA1, colorA2, colorA3,
colorB0, colorB1, colorB2, colorB3,
colorS1, colorS2;
uint32 product1a, product1b,
product2a, product2b;
 
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)
{
product1b = product2a = color2;
if ((color1 == color2 && color6 == colorS2) ||
(color2 == colorA1 && color6 == colorB2))
{
product1a = INTERPOLATE (color2, color5);
product1a = INTERPOLATE (color2, product1a);
product2b = INTERPOLATE (color2, color3);
product2b = INTERPOLATE (color2, product2b);
// product1a = color2;
// product2b = color2;
}
else
{
product1a = INTERPOLATE (color5, color6);
product2b = INTERPOLATE (color2, color3);
}
}
else
if (color5 == color3 && color2 != color6)
{
product2b = product1a = color5;
if ((colorB1 == color5 && color3 == colorA2) ||
(color4 == color5 && color3 == colorS1))
{
product1b = INTERPOLATE (color5, color6);
product1b = INTERPOLATE (color5, product1b);
product2a = INTERPOLATE (color5, color2);
product2a = INTERPOLATE (color5, product2a);
// product1b = color5;
// product2a = color5;
}
else
{
product1b = INTERPOLATE (color5, color6);
product2a = INTERPOLATE (color2, color3);
}
}
else
if (color5 == color3 && color2 == color6 && color5 != 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
{
 
if ((color2 == color5) || (color3 == color6))
{
product1a = color5;
product2a = color2;
product1b = color6;
product2b = color3;
 
}
else
{
product1b = product1a = INTERPOLATE (color5, color6);
product1a = INTERPOLATE (color5, product1a);
product1b = INTERPOLATE (color6, product1b);
 
product2a = product2b = INTERPOLATE (color2, color3);
product2a = INTERPOLATE (color2, product2a);
product2b = INTERPOLATE (color3, product2b);
}
}
 
 
product1a = product1a | (product1b << 16);
product2a = product2a | (product2b << 16);
 
*(dP) = product1a;
*(dP+(dstPitch>>2)) = product2a;
 
bP += 1;
dP += 1;
}//end of for ( finish= width etc..)
 
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}; //endof: for (height; height; height--)
#ifdef MMX
}
#endif
}
 
 
 
/*ONLY use with 640x480x16 or higher resolutions*/
/*Only use this if 2*width * 2*height fits on the current screen*/
void _2xSaI(uint8 *srcPtr, uint32 srcPitch,
uint8 *deltaPtr,
uint8 *dstPtr, uint32 dstPitch, int width, int height)
{
uint32 *dP;
uint16 *bP;
uint16 *xP;
 
#ifdef MMX
if (mmx_cpu && width != 512)
{
for (height; height; height-=1)
{
 
bP = (uint16 *) srcPtr;
xP = (uint16 *) deltaPtr;
dP = (uint32 *) dstPtr;
_2xSaILine ((uint8 *) bP, (uint8 *) xP, srcPitch, width, (uint8 *)dP, dstPitch);
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}
}
else
{
#endif
uint32 Nextline = srcPitch >> 1;
 
for (height; height; height-=1)
{
bP = (uint16 *) srcPtr;
dP = (uint32 *) dstPtr;
for (uint32 finish = width; finish; finish -= 1 )
{
 
 
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);
*(dP) = product;
*(dP+(dstPitch>>2)) = product1;
 
bP += 1;
dP += 1;
}//end of for ( finish= width etc..)
 
dstPtr += dstPitch << 1;
srcPtr += srcPitch;
deltaPtr += srcPitch;
}; //endof: for (height; height; height--)
#ifdef MMX
}
#endif
}
 
/tags/initial/snes9x/changes.txt
New file
0,0 → 1,2166
Snes9x 1.43
- Win32: Disabled Netplay (funkyass)
- Win32: Various fixes, including ROM dialog (funkyass)
- Win32: New Input Config Dialog (funkyass)
- Win32: added .avi output feature (blip)
- Win32: fixed frame timings >100ms, added frame advance (blip)
- Rewrote Unfreeze, renamed it S9xUnfreezeFromStream,
failing to load a freeze file no longer resets emulation (blip)
- Fixed Unfreeze to restore IPPU.HDMA properly (blip)
- Rewrote OBC1 code to match the real chip (Overload)
- More updates the to DSP-1 code, fixes to projection (Overload, Andreas Naive)
- Unix/X11: Rewrote keyboard setup code (Bisqwit)
- Added movie recording+rerecording support (blip, Bisqwit)
- Added -hidemenu CLI switch (funkyass)
- fixed broken Win32 filters (lantus)
- Added internal support for emulating the new-style SNES (MKendora)
- Cleaned up many quirks of the cheat search engine (MKendora, Don Vincenzo)
- Fix mosaic in hires SNES modes (Tokimeki Memorial) (MKendora, zones)
- Rewrote Legend's hack, added another game to it (MKendora)
- Optimized the Open ROM dialog (MKendora)
- Rewrote the Seta DSP map (The Dumper, MKendora)
- Began string isolation for the UI, eases translation (funkyass)
- added -nopatch -nocheat, and -cheat CLI items (MKendora)
- fixed a UI typo (funkyass)
- fixed several C core stack ops in emulation mode (MKendora)
- split emulation mode ops from native mode ops (MKendora)
- Seta special chip emulation enhancements (Feather, The Dumper, Overload, MKendora)
- code tweaks to the ST010 (Nach, pagefault)
- fix some C/asm quirks and HDMA quirks (all my fault) (MKendora)
- several timing hacks to fix games (lantus)
- improved checksumming for odd mirrorings (MKendora)
- Snes9x uses a standard zlib instead of a packaged one (PBortas)
- Exhaust Heat 2 and regional ports are playable (Feather, The Dumper, Overload, MKendora)
- Game Doctor dumps that are 24 Mbit are now supported by
a force option (MKendora, Nach)
- SuperFx interleave format is now considered deprecated.
Support will be removed in future versions (Team decision)
- made SuperFx interleave detection a compile option (MKendora)
- added memory maps for slotted games (MKendora)
- fixed a typo in the usage messages (MKendora)
- fixed the bug that had nuked optimizations (The Dumper)
- restored full speed optimizations in release builds (funkyass)
- Added non-speed-hack version of color subtraction. (zones)
- OpenGL info message font fix (zones)
- APU timer fix (zones, Nach)
- Fixed mouse offset in resized X11 window. (PhaethonH)
- Fixed a (presumably) long-standing bug: Mode 6's BG is
depth 4, not depth 8! (anomie)
- Unix: unmap all joystick buttons before applying -joymapX (anomie)
- Win32: added a define to disable pausing when focus is lost, NOPAUSE (funkyass)
- Win32: Changed the default for Auto-save SRAM to 15 sec (funkyass)
- Dreamcast: Added SH4 assembler (PBortas, Marcus Comstedt, Per Hedbor)
- C90 and aclocal 1.8 warning fixes (thanks Ville Skytt� (PBortas)
- Unix: AMD64 compilation fixes. (PBortas)
- Added support for NSRT Team's JMA format (Nach, NSRT Team, funkyass)
- Unix: Loading a zip file on binaries without zip support
will give an appropriate error message (Nach)
- Unix: Added install target with proper --prefix handling. (PBortas)
 
 
Snes9x 1.42
- Added 8-bit rendering filters (funkyass)
- Added Sanity Checks for the Display Dialog (funkyass)
- New Layout for the Joypad Dialog, (funkyass)
- Fixed that anoying Joypad dialog bug. Now check to see
if the axis exists before asking for the info form it (funkyass)
- Added full POV support. (funkyass)
- Fixed sram sizes for SuperFx games (Nach, MKendora)
- Stopped saving sram for games with no battery (Nach, Mkendora)
- Killed the gray line and slightly optimized Win32 GL (MKendora)
- stack wrapping fix in C core (MKendora)
- removed some dead hacks (Oda Nobunaga and Dezaemon) (MKendora)
- fixed some DMA and HDMA modes (anomie, MKendora)
- improved HDMA timing (anomie)
- cleaned up load and deinterleave code (MKendora)
- removed old UI DLL (MKendora)
- new cheat dialogs (MKendora)
- started Unicode preparation in Win32 UI (MKendora)
- Implement odd sprite sizes, sprite priority rotation. (anomie)
- RTO code that hopefully works. MK's #define is
"MK_DEBUG_RTO" to try to debug the RTO code. (anomie)
- SDD1 decompression support for Linux. Also added a new
command line option -sdd1-pack. (anomie)
- Added correct VRAM read logic. #define CORRECT_VRAM_READS
if you want it. (anomie)
- removed the non-VAR_CYCLES path (MKendora)
- changed access timing map to be address-based. (MKendora, anomie)
- DSP-1 updates (Overload, Andreas Naive)
- S-DD1 decompression support (Andreas Naive)
- optimized S-DD1 code (anomie)
- S-DD1 can use packs or decompression (MKendora)
- More work on Exhaust Heat 2 (MKendora, Overload, The Dumper)
- separated ROM detection from file reading (lantus)
- fixed a mirroring bug in LoROMs (MKendora)
- cleaned up some mapping issues (MKendora)
- ST018 games now boot before locking up (Mkendora, Overload)
- SA-1 state was not completely reset, crashed Marvelous (zones)
- Removed sample caching. It caused problems, and was not
noticably faster. (MKendora)
- Fixed interlace without breaking the displays for MK (anomie)
- Fixed a PPU OpenBus hack (anomie)
- Moved SPC7110 and S-DD1 regs to speed up the general case
of reading the $4xxx registers (MKendora)
- altered Hi/Lo ROM detection to fix a few misdetects. (MKendora)
- Implemented RTO flags. With MK's implementation of $213F's
interlace bit, we now pass the SNES Test Cart's
Electronics Test (anomie)
- Fix sprite windowing bug (anomie)
- Way back in 1.40 MK changed the Windows port to default
to a plain old joypad instead of the MP5. And then we
removed the hacks for games that dislike the MP5. So
we need to change the defaults elsewhere too... (anomie)
- cleaned up the hacks section somewhat (MKendora)
- removed some interleave hacks (MKendora)
- fixed a bug in KartContents (MKendora)
- transparency fix for Jurassic Park (lantus)
- A hidden Win32 feature (MKendora)
- Kludged Mark Davis until I get stable APU timing (MKendora)
- Win32 renders overscan always, fixes some jumpy games (MKendora, lantus)
- Fixed an FMOD bug (MKendora)
- cosmetic tweaks (Everyone)
- Fixed 2 special chip bugs in the C core (zones)
- Added some sanity fixes to the C core, fixes MLBPA
Baseball for C core users (zones)
- updated zlib source (includes 1.1.4-1 patch) (MKendora)
- compiler warning fixes (PBortas)
- Updated the SuperFx asm core (pagefault)
- Kludged Unix compilation to produce working SuperFx (PBortas)
with the asm core.
- Kludged VC to deal with optimization weirdness (MKendora)
- Hacked Robocop vs. Terminator using Daffy Duck hack. Stops
flashing. (MKendora)
- Added some defines to the asm core (MKendora)
- Added possibility to take screenshots on Unix (PBortas)
- Initialize the C SuperFx core better (PBortas)
- Kludge a Japanese golf game until the APU timing is fixed (MKendora)
 
 
Snes9x 1.41-1
 
- Oops, in the asm CPU core i was stomping on %eax too
early, so register $4210 wasn't getting set properly. (anomie)
 
Snes9x 1.41
 
- Win32 controllers now stay the same between games (MKendora)
- Win 32 Open ROM dialog fixes (MKendora)
- Win32 Display dialog fixes (funkyass)
- Win32 OpenGL ratio tweaking. (Reduces the gray line) (kode54)
- Fixed Win32 superscope for those having issues (MKendora)
- Generic accuracy fix in main SUperscope emulation (MKendora)
- sprite bug fixed (gah! How'd we miss that) (anomie)
- SPC saving compatibility fix (Caz and zones)
- Window clipping update (anomie)
- Mode 7 clipping fix (TRAC)
- latching fix (anomie)
- BS BIOS checksum and mapping fix (MKendora)
- Working Uniracers hack (dma.cpp) (anomie)
- HDMA Indirect Address fix for Romancing Saga 2 (anomie)
- Better savestate hack, does it break anything? (anomie)
- C4 C core fixes. Mostly Trapezoid (thanks Nach),
some s/short/int16/, some indentation. (anomie)
- Damn, but the indentation in ppu.cpp was screwed up.
Killed some dead code too (twas commented forevermore). (anomie)
- fixed a potential crash in S-DD1 logging (MKendora)
- Improved accuracy of Hi/LoROM detection (~500 ROM test) (MKendora)
- Hack for Moryou Senki Madara 2, don't call
SelectTileRenderer from DrawOBJS if BGMode is 5 or 6. A
real fix requires at least rewriting SelectTileRenderer,
or inlining a special version in DrawOBJS. (anomie)
- DMA traces: add additional address info to reads too. (anomie)
- Killed the old Borland Joypad dialog (funkyass)
- Fixed issues with Dezaemon and CT, maybe others (anomie, MKendora)
- Changed the internal snapshot key from \ to VK_F12 (funkyass)
Fixes issues with non-US keyboard layouts.
- Fixed OAM reset to not occur during forced blank. (anomie)
- Killed some dead OAM reset code that doesn't need saving. (anomie)
- Unix/X11: Fixed screen jumping. CT enables overscan mid-
frame for only one frame, and we now update the rendered
screen height accordingly. Other ports are still broken. (anomie)
- Unix/X11: Fixed possible TV mode crash. (anomie)
- Fixed OAM reset timing (beginning of V-Blank rather than
end) for R-TYPE 3 (J). (anomie)
- Unix/X11: Fixed OpenGL target (PBortas)
- Unix/OSS: Fixed big endian sound (PBortas/ernstp)
- Tweaked the About Dialog so its read-only and no scroll (funkyass)
 
 
Snes9x 1.40
 
- cleaned up a sound skipping code issue. Same as the
RTC issue (lantus)
- re-fixed the invalid BRR header behavior twice (Lord Nightmare, FatlXception, Mkendora)
- More BS mapping fixes. (The Dumper, MKendora)
- Fixed Ranma Bun no 1 - Chonai Gekitou Hen (J) and
Street Combat (U). Interlace is not supported in the
non-Hi-res modes, as far as I can tell. (MKendora)
- Also fixes Maka Maka (J). Frank Yang's report, and
anomie's code both provided clues to this one.
- Removed special casing on setting 5c77 version to one.
This seems to be true for U and J units always. I need
it checked out on PAL... (neviksti)
- Using SNEeSe's values for 5c78 and 5A22. Note we know
that the 5c78 version can also be 1 or 2, instead of 3. (TRAC, neviksti)
- Added turbo buttons. Credit/blame for the design goes
to slack, Nave, Gogo, and myself. (MKendora)
- fixed a bug in turbo (slack, MKendora)
- Tried merging the behavior of Old $4200 with new $4200 (MKendora)
- Made $4200's return value match what VSMC Explorer
showed on Fancia's SNES (MKendora)
- Fixed a matrix multiplcation bug in ZSNES state loads (MKendora)
- Fixed Dezaemon and Ys3 mode 7 (lantus)
- Fixed H-DMA modes 5-7. Thanks to The Dumper for the
extra motivation needed. GunForce and Genocide 2 work. (The Dumper, MKendora)
- Fixed BG3 Priority. I'm stupid. anomie had fixed it,
but lantus fixed it again, because I didn't use it. (anomie, lantus)
- Added a Star Fox 2 hack, and an interleave skip (The Dumper, lantus, MKendora)
- Cleared BS setting on load (lantus)
- Fix for Mode 7 priorities. fixes F-1 Grand Prix (all 3) (anomie)
- JANJYU GAKUEN 2 needs Multi-tap 5 off. (Frank Yang, MKendora)
- HONKAKUHA IGO GOSEI: No multi-tap 5, allow mouse (lantus, MKendora)
- Added a few missed conditional compiles (Nach)
- disabled multitap 5 by default, added menu to enable (MKendora)
- special thanks to anomie and lantus. One of them is
responsible for a bug fix I forgot already. (anomie, lantus)
- Removed several Multitap5 disable hacks. (MKendora)
- Added an SPC dumping upgrade from kode54 (kode54)
- cleaned up some resource leaks (MKendora)
- I forgot this since 1.39mk, but SPC700 flag fixes (anomie)
- Mode 7 interpolation screen flip fix (anomie)
- Updated SPC7110 code a bit, for compatibility (Daniel, anomie)
- Changed RTC saving. (Byte exact to old format on Win32)
The submitted patch for "safety" doubled the file size,
so I had to write it in explicitly little-endian. (MKendora)
- Removed the old hidden cursor (MKendora)
- Applied a WAI correction from anomie. (anomie)
- Added a patch for Pseudo hi-res (anomie)
- Hacked around Word writes to $7F:FFFF. Thanks to lantus
and The Dumper for verification. (MKendora)
- PPC compile fix? and debugger reversion (anomie)
- Set defaults differently to improve sound quality. (MKendora)
- Clear Force load settings after Init (lantus)
- Made menu reset a soft reset. Fixed BL Sound Test & more (CaitSith2)
- Fixed word writes to block bounds in asm core. (MKendora)
- redone version of my bounds fix, only this one WORKS! (TRAC)
- Thanks to TRAC for the AT&T syntax refresher! (TRAC)
- Fixed screen saver disable (kode54)
- Fixed OAM and sprite priority in the asm core (anomie)
- Proper Interlace fix for mid-frame changes (anomie)
- Fixed OpenGL to accomodate previous patch (MKendora)
- Ported the "Settings" dialog to VC (MKendora)
- Fixed ROM Info bugs (_pentium_five, MKendora)
- Fixed non-stretched interlacing, but it's s.l.o.w. (anomie)
- Superscope and Mouse need to be enabled by the menu. (MKendora)
- Fixed HiROM sram reads in asm and C cores (anomie, MKendora)
- Added Company 48 to the list. Thanks to _pentium_five_ (StatMat)
- Set Super Drift Out's S-ram correctly. (Snes9xppSE Team)
- Fixed NTSC timing. Helps ToP Intro greatly (kode54)
- Added several entries to the company list, from uCON64 (Nach)
- Lots more companies (StatMat, Nach)
- Fixed Win32 Superscope support (NT kernel only?) (MKendora)
- Added ZSNES OBC1 code ported from asm to C (sanmaiwashi)
- Implemented Justifier emulation (neviksti, MKendora)
- Fixed Rudora no Hihou's clip window bug (anomie)
- Fixed Flintstones sprite issue (lantus)
- Fixed sram mappings for Big Sky Troopers and
Taikyoku - IGO Goliath. Both map in bank F0 (MKendora)
- Fixed a possible crash when switching audio settings (MKendora)
- Added per-pack gfx pack configuration (MKendora)
- Fixed glitches in DSP-1 games (Flintstones fix) (lantus)
- Added delay to Superscope latching. Fixes X-Zone. (neviksti, MKendora, zones)
- Added DSP-2 support (Overload, The Dumper, Lord Nightmare,
MKendora, neviksti)
- Fixed Super Bases Loaded 2 (and J/K ports) DSP-1 seems
to ignore the A15 line in LoROM maps (MKendora)
- Corrected $4200 again (The Dumper)
- Corrected $2100, $2102, and $2102 read behavior (anomie)
- Fixed Cancel on the Sound Options dialog. (MKendora)
- Fixed the sound options dialog (Thanks, Quattro) (MKendora)
- updated DSP-1 support to match chip better (Overload, neviksti, The Dumper)
- added a few Ops to the DSP-4 routine (Nothing plays yet) (neviksti, The Dumper, Overload, MKendora)
- added screenshot support (anomie, sanmaiwashi)
- stubbed the ST010 chip in Exhaust Heat 2 (Overload, MKendora)
- hacked around War 2410's lockup (pagefault, _Demo_, MKendora)
- updated tests for type 1 ROMs (based on reset vector) (MKendora)
- Emulation mode CPU fix (The Dumper)
- Open Bus fixes (anomie)
- Better Expansion port emulation (anomie)
- More Open Bus fixes (Overload, anomie)
- HDMA fixes (fix colors only in Full Throttle Racing) (anomie)
- Migrated DKJM2 onto the Tales map (MKendora)
- Tried to remove Dragon Knight 4 hack (LoROM sram fix) (MKendora)
- Fixed ROM Mirroring for LoROMs (<= 32 Mbit) (MKendora, TRAC)
- blocked wram to wram DMAs (neviksti)
- fixed HiROM mirroring, too. Thanks TRAC! (MKendora, TRAC)
- fixed C core RMW and Push ops to write in the correct
order, fixes Michael Jordan gfx. (anomie, Overload, MKendora)
- set RDIO to start as 0xFF, fixes SuperFx games. (anomie, Overload)
- New connect dialog (funkyass)
- better conditional compile of FMOD (funkyass)
- fixed screenshot code when libpng is not used (funkyass)
- added portability fixes (zones)
- fixed asm Pushes (anomie)
- fixed asm LoROM s-ram decode (MKendora)
- migrated DEZAEMON to standard LoROM map (MKendora)
- fixed the Madara 2 OpenGL bug (key found in Rudra) (MKendora)
- fixed asm RMW instructions (MKendora)
- fixed ADC opcode (The Dumper)
- added DSP-2 Op09 (The Dumper)
- updated C4 C code (anomie)
- updated C4 asm code (Nach)
- Keep OpenGL in ratio (kode54)
- Replaced many more Borland dialogs (funkyass, MKendora, Nach)
- Added CRC32 to displayed ROM Info (Nach, MKendora)
- Fix cheat support (The Dumper)
- improved DMA timing (MKendora, Overload, The Dumper)
- Fixed Mode 7 math, removed Dezaemon, Gaia, Ys 3 hacks (TRAC, MKendora)
- Mode 7 flip fix (TRAC)
- Multiple safety and initialization fixes (zones)
- Platform safety fixes (PBortas)
- Memmap cleanups (MKendora)
- More preliminary work on special chips (The Dumper, Overload, MKendora)
- Added color coding (MKendora)
- Another HDMA fix (anomie)
- added another known hack to the hacked games list (Nach)
- ToP memmap changes (MKendora)
- Checksum calculation changes (MKendora)
- Special cased a few games for OAM issues (MKendora)
- Reverted OAM reset to 1.39 timing (MKendora)
- Reworked vram wrapping (zones, Mkendora)
- Fixed $4210 and Super Professional Baseball 2 (Overload, MKendora)
- Fixed APU RAM init (Overload, MKendora)
- More support for Exhaust Heat 2 (not playable) (The Dumper, Overload, neviksti)
- removed some debris from save states (MKendora)
- fixed? Doom's save state bug (MKendora)
- simple overdump detection warning (MKendora)
 
 
1.39mk3b
 
- Fixed the RTC detection. FINALLY done correctly (lantus, MKendora)
 
 
1.39mk3a
 
- neatened up the company table. (MKendora)
- fixed a mistake in the ROM Info box (MKendora)
- Added a Calulcated Size field to ROM INfo. (MKendora)
- Added 3 more companies to the ROM Info table (MKendora)
- Fixed BS detection (The Dumper)
- Added a Legend-specific hack to get sound. I remembered
it being mentioned in the changelog. (Gary Henderson)
- Unbroke the Star Ocean special cases (Trigger of Time, MKendora)
- Company 255 is not Hudson-ZFE detects all Hudson games
without it, except a corrupt dump (StatMat, MKendora)
- fixed a bug in the redone detection for the SPC7110 (CaitSith2)
- 44Khz sound should be 44.1Kz. Changed, though you'll
need to re-set 44.1Khz to make it take effect. Not sure
if this affects non-Windows ports. (MKendora)
- Added 32Khz playback (MKendora)
- Inproved BS ROM mapping (_Demo_, The Dumper, MKendora)
 
 
1.39mk3
 
- Honkaku Syogi Fuunji Ryuou (J) fixed (force no multitap) (Frank Yang)
Also Fixed Super Castles (j).
Also fixed a bunch more. This dude e-mailed like 100 bugs
to my hosts, some already fixed in Snes9x1.39mk2, but
about 7 were clearly multi-tap5.
- also fixed Dekitate High School. Error was in Japanese (Frank Yang, Tomato)
- fixed 2 memory leaks (Aaron)
- Dai Kaiju Monogotari 2 works as a 40 Mbit ROM. (MKendora, The Dumper)
- Fixed the Flashback bug. Lots of info led to this. (neviksti, MKendora)
Thanks neviksti, The Dumper, TRAC, and FatlXception
for clarifying the behavior.
- Fixed Sailor Moon Fuwa Fuwa Panic 2 to work with (neviksti, MKendora)
previous fix. It's a total hack, but it should sound
just like the old Snes9x did. neviksti strikes again!
- Dirty hack to make 3 games deinterleave properly: (MKendora)
Wizardry 4, Mark Davis, and Honkakuha Igo Gosei(FX)
all work as well as the deinterleaved counterparts.
(The last is a hacked game, and you should get the
non-FX version)
- Fixed Seima Jyuden Beasts and Blades. Another Multitap, (Frank Yang)
but for some reason, the hack requires the C cpu core.
Thanks to Tomato for taking a stab at the error message,
as well. It was too vague to be of use, he said. I
just tried it because it worked on other games.
- Res Arcana fixed. Another Frank Yang report, another J (Frank Yang, MKendora)
error, but I can read kana well enough with a table!
- Removed a Terranigma specific hack. Not sure, but the (anomie)
new behavior might have fixed Tin-Tin in Tibet's colors.
- Dirty hack to work around a dirty hack. Both Yoshi's (MKendora)
Island (E) dumps should work now
- Added the JumboLoROM memory map, Extends LoROM support (The Dumper, neviksti, MKendora)
to 48+ Megabits.
- added an EXTBG fix, since iirc, TRAC is using it as well (anomie)
Does it actually fix anything?
- Fixed crash in DSP Op06 (The Dumper)
- Fixed a GUI error on my part (Trigger of Time)
- Cleaned up some of the SPC7110 detection/size code. (MKendora)
- Merged in XBox port changes to SPC7110 code (lantus)
- Added a call to Memory.Deinit when exiting. (lantus, MKendora)
- Many memory leaks fixed while chatting with lantus (lantus, MKendora)
- Fixed that stubborn open/close leak (lantus)
 
 
1.39mk2
 
- hacked in Shien's Revenge (anomie)
- fixed Orge Battle's green lines. (CPU source for DMA) (anomie)
- Looks interesting, and might apply to other DMA cases?
- maybe "fixed" DKC's barrels? by treating $2001
as unmapped. The game worked before with a hack. (MKendora)
- optimized SPC7110 slightly by removing extra setup work (MKendora)
- Fixed DBZ 3 (Korean). S. Korea is, in fact, NTSC. (MKendora)
- Fixed a hard-coded value in the SPC7110 (MKendora)
- Added a Win port ROM Info dialog (MKendora)
- some companies aren't in the table I used.
If you encounter an Unimplemented company,
report it the the Snes9x development forum, with
the correct company and the number.
 
 
1.39mk
- SPC7110 support based on Dark Force's docs. (Dark Force, zsKnight,
The Dumper, MKendora)
Trust me when I say those guys deserve the credit more
than me. From what I'm told, Dark Force is the man
behind most of the reverse engineering, but they all
did a much harder bunch of work than I did following
their specs. It's plain and simple that these three
are the masterminds behind all SPC7110 support.
Dark Force for reverse engineering the chip (Extremely tough work!)
zsKnight for the original core, and probably other things
The Dumper for dumping the packs and doing hardware tests.
 
Also thanks to CaitSith2 for numerous bug reports
and a lot of bug fixes.
 
- Theme Park hack removed, fixed via PPU latching (anomie, MKendora, TRAC)
- WWF Wrestlemania hack removed (anomie, TRAC)
- Strike Gunner hack fixed (anomie, MKendora, TRAC)
- FF:MQ text fixed. May help other sprite issues. (TRAC)
- Umi Hara Kawa Se timing corrected. (anomie)
- S-DD1 packs load by the same rules as ZSNES (MKendora)
- SPC7110 code builds in linux (Lord Nightmare, zinx)
- Added The Dumper's DSP-1 updates (The Dumper)
- SPC7110 is correctly displayed on load, RTC also noted. (MKendora)
- Fixed a potential graphics problem (TRAC)
no known games fixed, but who knows?
- Fixed Ballz3D (pagefault)
- Re-fixed Ballz3D, via DSP op 0F (The Dumper)
- included some of anomie's fixes. Many caused me grief,
so only Marko's Magic Football is intentionally fixed. (anomie)
- finished zsnes save support, though I don't know how
well it will work with SPC7110 games (MKendora)
- Added a new soundux.cpp again to fix some noise.
(Fixes the GW "fart track") (Lord Nightmare, info from Anti-Res)
- Added 3 cache modes for SPC7110 games (MKendora)
- Added new BRR decoder. Requires sample caching
and the Anti-Res decoder be disabled. (FatlXception, port by Lord Nightmare)
- Added CaitSith2's RTC debugger. define RTC_DEBUGGER in
project settings to enable it. (CaitSith2)
- SPC7110 per-game cumulative logging (MKendora)
- other fixes that I've forgotten (sanma iwashi, TRAC, anomie, ????)
 
- "I'm not worthy" thanks to the original SPC7110 crew (DF, zsKnight, and the Dumper)
- Thanks again to the same people, because they deserve it!
- thanks to The Dumper, Dejap, TRAC, and all the ZSNES crew for technical assistance
- Thanks to most of the Snes9x mods for testing (no thanks to you, Raptor ;)
- and thanks to TRAC and #mkendora for letting me vent at you.
 
1.39
- Added SDD-1 unknown graphics data logging at the dumper's request. A bit late
but might help with Street Fighter 2 Alpha's data dumping. Creates a
romname.dat file in the freeze file folder.
- Implemented 16-bit texture support for OpenGL modes in Windows and Linux.
Had to support a new pixel format type to do it - RGB5551 (one bit of alpha)
which caused me some major problems - black was no longer always pixel value
zero!
- Removed the Bump map OpenGL mode from the Windows port (didn't look so good
anyway and was slow).
- Added a hidden novelty OpenGL mode (clue: a keyboard shortcut activates it)
- Reverted back to FMod version 3.20 after reports that version 3.33 broke
AD3 support.
- Implemented a better work-around for the broken select system call in the
Linux kernel - the original work-around was long-winded and stopped working
when I implemented OpenGL support under Linux.
- Added the same speed-up hack to the OpenGL code that the Glide code already
supported. Basically, if your OpenGL implementation supports 16-bit textures
then OpenGL mode should be as fast, or faster than the 3dfx Glide mode.
- Hopefully fixed Glide support.
- Reverted back to the original colour blending code. The newer code, although
more accurate in most cases, had too many glitches and was slower.
- Included multiple Japanese games fixes from Iswashi San.
- Fixed a timing problem caused by a speed up hack that was affecting Top Gear
300. No the game still isn't playable yet, but I noticed the problem while
investigating the DSP-4 chip used by the game.
1.38
- Added support for Star Ocean and Street Fighter 2 Alpha decompressed graphics
packs from dejap. Used a binary chop search rather than a linear search to
locate correct decompressed graphics more quickly - should help emulation
speed during later stages of the game.
- Included OpenGL support into the Linux port and speeded up the Windows OpenGL
implementation slightly. The real speed up would occur if I could figure out
how/if 16-bit textures are supported in OpenGL because at the moment the
16-bit software rendered SNES image must be converted to 24-bit before being
uploaded as a texture...
- Included the latest ZSNES DSP-1 code. Now Pilotwings, SD Racer and Suzuka 8
Hours are playable. Aim For The Ace, Super Air Diver 1 & 2 and Syutoko Battle 94
are also playable, but with bugs. Thanks to zsKnight, _demo_, et al for all
their hard work.
- Another Daffy Duck: Marvin Missions screen flicker problem worked around -
writing to the IRQ enable register shouldn't clear any pending IRQs, but
Sieken 3 seems to require this or else the game hangs. Special-cased Daffy
Duck for now.
- An NMI emulation bug was triggering a Panic Bomberman World game bug,
crashing it. Basically, if a game enables NMIs after the normal trigger
point, the NMI should not trigger if the game has already read the NMI clear
register.
- Panic Bomberman World requires SPC700 memory to be initialised to zero on
reset otherwise the game hangs when a tune finishes and another one should
start.
- Added mouse pointer auto-hide to the Windows port. Much better than the turn
the mouse pointer into a black dot method I was using before.
- Included the latest ZSNES Super FX code. Not sure if it fixes actually fixes
any games.
- Added an offset hack for Strike Gunner to get the scrolling ground layer
to line up correctly - another offset-per-tile bug hacked around for now.
- Arrr! Left in some debugging code in the last release that prevented all
games that need the slower SPC700 timing from working. Removed it.
- Hmm. The broken cut-scenes in Deep Space 9 seem to indicate that I haven't
got the emulated clock speed of the 65c816 CPU correct yet. And not by a
little bit - a 9% too slow error. Hacked special timing for the game for now.
- Added triple-buffering to Windows port - enabling double-buffering actually
enables triple-buffering if you have enough free video RAM, defaulting to
double-buffering if you don't.
- Fixed another crash bug in the interpolated mode 7 code - if no scaling
was being used (either up or down) and screen repeat was enabled and the
screen was flipped horizontally, the routine would crash Snes9x. Was causing
Snes9x to crash during rock monster boss stage of Castlevania 4.
- Oops. Got the initialisation of the default SNES screen width and height
round the wrong way - could cause a X Windows System error message on the
UNIX port after loading a ZSNES freeze file.
- Included the unofficial Windows port emulation fixes for several games including
Kentouou World championship and TKO Super Championship.
- Included Iwashi San's improved Anti Res. sound sample decoding routine and
updated the C version to match.
- Included Anti Res. improved sample decompression code he sent me ages ago,
but for some reason I didn't include. Sorry. This version seems good enough
to leave enabled all the time.
1.37
- Added fix for Captain America's corrupt graphics - a ROM bug causes it to
read from what I thought should be an unmapped memory area, but it expects
the value returned to be zero.
- Added code to support games that switch to the hi-res. SNES screen mode part
way down the screen while using the 3dfx bi-linear filter mode. The code
basically has to back out of the speed up hack it was using when the game
switches resolutions.
- Fixed support for games that have mixed lo-res. (256x224), medium res.
(512x224) and hi-res. (512x448) all on the same screen - corrects the display
of Majin Tensei 2.
- Added support for games that use sub-screen addition to the back-drop layer
while displaying hi-res. graphics - something I thought the SNES couldn't do
but the game Marvelous uses this.
- Reworked the UNIX/Linux output image handling code: the image doesn't always
have to be scaled when hi-res. support is enabled, the PutImage operation
only updates the area of the screen it has to, the SNES image is now always
centred in the window/full-screen area and if the SNES image changes size
between frames, the old screen areas are now correctly cleared.
- Fixed the corrupt graphics problem during the battle scene of Last Bible 3 -
it requires that previously unknown DMA mode 5 should just act the same as
DMA mode 1.
- Fixed a nasty bug when H-IRQs were being reused on the same scanline - a logic
bug could cause H-DMA processing for that line to be skipped. Was causing
the bridge and the start banners to be the wrong colours in Top Gear 2.
- Added Kreed's display processing modes to the Linux port, including his new
asm version of the Super2xSaI mode and the new software bi-linear filtering
mode.
- Think I might have figured out the odd Mode 7 glitch problems the games
Illusion and Gaia and Chase HQ were having. My original fix was to mod the
centre X & Y values with 1024, but looks like the true fix is to mod
X + horizontal offset and Y + vertical offset with 1024 when screen wrapping
is enabled.
- Disabled H-DMA'ing into V-RAM via registers 2118/2119. The game Hook
deliberately does this causing graphic corruption while dialog boxes are
displayed. Maybe the real SNES disallowed this and it was left in the game by
mistake? Not sure what effect the game was trying to produce because
disabling the emulation of this feature doesn't seem to affect the game at
all, other than stopping the corruption.
+ Also fixes graphics junk problem on first screen of Bugs Bunny.
- Added a 'region-free' timing hack for Power Rangers Fight - without it the
NTSC version was displaying badly glitching graphics; I'd already fixed the
PAL version.
- Added true priority-per-pixel mode 7 support (the previous support was just
a hack to get the colours correct) - level 2 of Contra 3 used this feature.
- The Japanese, German, French and Spanish version of Illusion of Gaia needs the
slow SPC700 timing.
- Deleted the Breath of Fire 2 S-RAM hack for the hacker intro version -
according to reports it was causing problems for the non-hacked version.
- Legend, the PAL version, never sets the sound master volume control - Snes9x
was defaulting this to off, I guess the real SNES must default it to full
volume; changed Snes9x. The NTSC version of Legend does set the master
volume level, but sets it to off just after the title screen. Hmm. The -nmv
command-line switch allows you to hear sound in this version.
- Panic Bomber World was tripping an SA-1 emulation bug - the WAI instruction
emulation code was setting the 'waiting for interrupt' flag on the wrong CPU
causing the main SNES to skip an instruction when the next interrupt occurred.
- Panic Bomber World, Bomberman 4 and UFO Kamen Yakisoban all need the slower
SPC700 timing.
- Oops! The Super Formation Soccer 95 fix was causing Aero 2 to lock up. This
means I have no no idea what value the DMA in progress register should
represent. I've hacked it and made it toggle between 0 and $ff on each read
which gets both games working, for now...
- The ROM de-interleaving code always assumed the blocks were rearranged based
on a power of two, but Francois found a copy of Soldiers of Fortune where
this was not the case. Corrected the code.
1.36
- Finally worked out why the menu items weren't being highlighted in several
ROMs, including Battletoads, U.N. Squadron and All Japan Pro Wrestling.
Two problems: its seems the SNES does halve the colour value result when
blending colours when only the fixed colour addition/subtraction is enabled,
but doesn't halve the result when sub-screen is being blended and its a clear
part of the sub-screen. The second problem was that I had an optimisation
that prevented the time consuming colour blending code from being called if
the colour being added/subtracted was black - adding zero to a number doesn't
affect the result, but not performing the side-effect of halving the result
does affect the final value...
- Super Formation Soccer 95 requires that the DMA enabled register doesn't
always return zero, otherwise the game locks up.
- Thanks to several people reporting a screen flickering problem in the
pseudo 3-d section of Jurassic Park 2 I've fixed a nasty problem in H-IRQ
handling code which could cause double-triggers or skip IRQs altogether.
With this fix I can now remove the special hacks for Ninja Warriors Again,
Chuck Rock and F-1 Grand Prix.
- More games needing the slow SPC700 timing:
Zennihon Puroresu 2, Soulblazer and Robotrek.
- The CPU idle time skipping code was skipping cycles during a software delay
loop in Itchy and Scratchy, causing screen flicker.
- Looks like reading the value of register $2137 shouldn't clear a pending
IRQ - was causing screen flicker on Yoshi's Island.
- Actraiser 1 & 2 both need the slow SPC700 timing.
- Terranigma reads a sound channel's current sample output value and waits for
it to be zero before preceeding. I forgot to always return zero when a
channel was silent. This mistake was causing the game to lock up.
+ Itchy and Scratchy and was causing the music to stop and samples to be cut
short in the Mario Early Years series.
- Added a hack for Secret of the Evermore - at several points in the game, just
as the plane is about to land, it reads from unknown registers $4000 and
$4001 and, if it doesn't get the value its looking for, the game hangs or
displays corrupt graphics.
- Silva Saga 2 was accidentally triggering a colour blending hack I put in
place Kirby Dreamland 3 and Kirby Superstar.
- The ZSNES freeze-file loading code could leave a file open if the file wasn't
a valid ZSNES freeze file.
- Super Punch-out requires certain DMA registers to be updated after the DMA
completes. Snes9x used to do that, but I must have accidentally left the code
commented out whilst investigating a different problem in another game.
1.35
- Added a recently played game list to the Windows port File menu so you can
quickly load up your favourite games.
- Included IPS patching support based on code from Neill Corlett - just rename
the patch file to match your ROM image name but with a .ips extension and
copy it into your ROM or freeze-file folder.
- Added John Weidman's and Darkforce's S-RTC, (Real Time Clock) emulation code.
The only game that seems to use it is Dai Kaijyu Monogatari II.
- Included code from Nose000 for games with 128Kbytes of S-RAM. Now
Sound Novel-Tcool, Thoroughbred Breeder 3, RPG-Tcool 2 and Dezaemon are
supported.
- The Windows port now has an option to make the 'turbo speed' button a toggle
button.
- The optimised fixed colour addition/subtraction code was ignoring the colour
window. Thanks to John Weidman for pointing this out.
- Added mode 7 and hi-res. hack for Dezaemon from Nose000 - the mode 7 hack
looks interesting (to me); I wonder if some other games would benefit?
- Both Tales of Phantasia and Star Ocean need custom sound CPU timing. Hmm.
That's 4 ROMs now, there will be more... That means I still haven't
discovered all the major SNES timing quirks. :-(
- Windows port now has an option to save the S-RAM data at any time.
- Windows port saving SPC dumps now auto-increments the filename.
- Added work-around for a Super Robot Wars Ex ROM bug - the game was checking
the wrong PPU register for end of h-blank. The game must have only worked by
chance rather than by design on a real SNES.
1.34
- Corrected the colour addition/subtraction and halve the result code not to
halve the result when only the fixed colour is used, i.e. the sub-screen is
clear. Discovered and fixed this awhile ago, but I accidentally reintroduced
the bug when adding some optimisations a few versions back.
- Finally cleared the last of the offset per tile background mode bugs. There
was something odd about the tile at the left-hand edge of the screen that I
couldn't figure out - well now I have. Yoshi's Island level 6 boss screen,
Mario RPG mine cart screen and Jim Power title screen now all display
correctly.
- Made reading blank areas of the SNES memory map return the middle byte of
the address - fixes Home Alone which tries to execute code in an empty part
of its memory map but only works because the real SNES seems to return the
middle byte of the address - $60 in this case, which corresponds to the
ReTurn from Subroutine instruction.
- Added auto-cycle skipping disable for Earth Worm Jim 2 and several other
games that spool sample data using H-DMA as the sample is being played.
Improves some sound effects in these games.
- Fixed joy-pad routines to only report up or left if down or right are also
pressed respectively. Works around a game bug in Empire Strikes Back in the
asteroid stage where the game crashes if both left and right are pressed -
something impossible to do on the original SNES game-pad.
- Added custom SPC700 timing for Rendering Ranger R2 - the game now works with
full sound. No idea why it needs custom SPC700 timing.
- The ROM type detection was broken for Treasure Hunter G and Test Drive 2 -
fixed the code so type 2 ROMs can be LoROM.
- Adjusted the main CPU cycles per scan-line from 341 to 342 to give an exact
match for the timing required for Earth Worm Jim 2. All EWJ2 needs now
for perfect sound emulation is a method of synchronising the emulation
speed to the host hardware's sound card playback rate, oh, and a fast CPU!
The Linux port already has this but seems to be broken because games
play at double-speed when this option is enabled.
- Some SPC700 code in Earth Worm Jim 2 seemed to prove that I had guessed the
clock speed of the SPC700 sound CPU incorrectly - out by almost a factor of
two, in fact. Changed the relative emulated clock speed of SPC700. Now
Chrono Trigger doesn't lock up at certain points anymore, the special SPC700
timing for games written by the Human Software company isn't required and
you can hear some more of the sound samples in Earth Worm Jim 2, etc.
- H-IRQ triggering code was broken - if a ROM turned on H-IRQ but later turned
it off, Snes9x could continued to generate H-IRQs, crashing some games.
- Added a generic test for Human Entertainment games - they need special
sound CPU timing to work. Gets Taekwon-Do working.
- Disabled offset-per-tile mode for Theme Park; the world map screen is corrupt
with it enabled.
- Yet more changes to the offset-per-tile backgrounds modes 2 and 4. Added
64 tile wide screen support for Mario RPG's mine cart ride and fixed multiple
bugs with the handling of horizontal offset-per-tile used in Chrono Trigger's
fade in of the space ship.
- New feature: Snes9x can now load ZSNES freeze state files! Just copy them
into the freeze file folder and Snes9x will load them when you load a freeze
file, but only if the corresponding native format Snes9x freeze file doesn't
exist.
- Added memory map hack for Batman - Revenge of the Joker: its ROM header block
is in the wrong location and Snes9x incorrectly detected its ROM type.
- Fixed an off-by-one-pixel clip window 2 bug when the window was set to clip
outside the window area; clip window 1 was already correct. Removed the bright
line bug at the left edge when the combat screen is appearing in Starfox and
the clip problem when text boxes zoom-out in Yoshi's Island.
- Jim Power's title screen seems to prove that the per-tile offset data on
mode 2 isn't ignored for the left most tile as I originally thought.
Modified the code.
- The recent timing changes highlighted another problem with Daffy Duck -
changed IRQ enable register to only clear pending IRQs if one has been pending
for several microseconds.
- Speeded up the sprite data register handling slightly.
- Finally got Aero the AcroBat 2 working, after many hours of investigation,
spread over several years - literally! Two problems. The SNES doesn't seem
to consider scan-line line zero to be part of the v-blank period even though
the line is never drawn and V-IRQs at the start of the scan-line have to be
delayed until a few microseconds into the line - Traverse: Starlight & Prairie
required this as well, so I removed the original, Traverse specific hack.
There's a problem with the in-game music that I'll investigate at a later
date.
- The in-game music problem just required ENVX emulation to be switched on,
off by default on the Linux port, on by default on the Windows port.
- Fixed the mode 7 corruption problem on the title screen of Chase HQ using the
same trick as Illusion of Gaia - i.e. mod the mode 7 centre X & Y values with
1024.
- Fixed another crash bug in the interpolated mode 7 code - a portion of
the code was ignoring the screen flip value and the fact that X render
direction reversed if the screen was flipped horizontally. Was causing a
crash on the whale boss screen of Kirby Superstar.
- Mortal Kombat 3 now auto-adjusts emulated cycles per scan-line work-around
a speech sample being cut short.
- Added sample data register reading support to the sound DSP - somehow I
seem to have missed implementing this. Not sure if any ROM actually reads
the value.
- Followed Sumire Kinoshita's suggestion and stopped clearing the ENDX flags
when the value is read, against my better judgement, and it does actually
improve speech samples in several games. Ooops! The Mortal Kombat series,
Magical Drop 2 and Metal Combat are the ones I've discovered so far.
- WWF Arcade now auto-adjusts the cycles per scan-line value to work-around
a sound sample repeat problem.
- Hmm. There's something about offset-per-tile mode I don't understand - WWF
Wrestlemania Arcade is getting corrupt graphics; not sure what effect the
ROM is trying to produce. Disabled offset-per-tile mode for the game for now.
- Fixed Street Racer player 1 wobble problem during the soccer game by auto-
adjusting the cycles per scan-line value slightly.
- Made Power Rangers Fight auto-adjust emulated cycles per scan-line to work
around a slight timing problem that causes an NMI to corrupt register
values that an IRQ handler is trying to update. Without it the scrolling
back-drop and fighter graphics are corrupt.
- Illusion of Gaia seems to need the mode 7 centre X & Y values to be mod 1024
if the screen repeat flag is set. Fixes the island fly-over bug right at
the end of the intro but breaks a few other games. Hmm. Made it auto-switch
on for this game only.
- Added memory map support for Radical Dreamers. Thanks to satellite hut master
for the information.
- Made updates to the top bit of the sprite write address register be ignored
unless the low byte had been written to first. A ROM coding bug in
James Pond II requires this, otherwise it writes a junk byte value into the
main character's X position and Robocod wobbles around all over the place.
- Reverted back to pre 1.31 way of initialising unknown register values -
Rock and Roll Racing was reading a junk register value and using the value
to set up DMA, which in turn was causing corruption on the player select
screen.
- Added Star Ocean memory map - thanks zsKnight! The original ROM I was testing
was corrupt, no wonder I couldn't figure out the memory map myself! The game
still isn't playable, though, due to missing S-DD1 graphics decompression
(+ encryption?) emulation.
- Started to dump some compressed data values from Street Fighter 2 Alpha in
the hope that one day someone will be able to crack the S-DD1's compression
algorithm.
1.33a
- C4 emulation wasn't being automatically enabled for Rockman X2 / X3 - the
Japanese versions of Megaman X2 / X3.
- Fixed the Super FX plot table pointer that I accidentally broke while saving
1Mb of workspace RAM - it was stopping all Super FX games from working.
1.33
- Noticed another problem with the CPU_SHUTDOWN code - Chrono Trigger locked
up during the intro but only when using the asm code CPU core. Found the
algorithm difference between the code and made the CPU match what the C
version was doing. Still not sure why it caused a problem in the first place.
- Changed colour subtraction code to use Lindsey Dubb's newer version he sent
me some time ago but I 'forgot' to include. I say forgot, but I really put
off including it because, although it improves most games that use the
effect, it does result in one or two slight visual glitches.
- Hacked in zsKnight's C4 emulation asm code - now both Megaman X2 and X3 are
playable. Still got to complete the reverse engineering of the i386 asm code
to C so other, non-Intel ports can have C4 emulation.
- Shuffled the keyboard mapping a bit on the Linux port so now Tab key acts as
an emulation speed turbo button, `, # and ~ act as superscope turbo and
/ acts as the superscope pause button.
- Fixed asm CPU_SHUTDOWN code that I accidentally broke while trying to
optimise it! Thanks to all the people who noticed Snes9x's frame skipping
had changed between releases. Frames rates should be improved again for more
than 50% of games.
- Re-enabled in-lining of the C SNES memory access routines, improves frame
rate by one or two on slower machines.
- Optimised the asm 65c816 addressing mode emulation code a little.
- Included some code changes making life easier for the Mac porter, John Stiles.
- Added memory map support for Sufami Turbo using information supplied by
Nose0000. No idea if it works because I don't have the ROM.
- Spent a few minutes trying to figure out the Star Ocean memory map so at
least the sound effects could be heard. But gave up after a couple of hours
due to laziness. If anyone knows the memory map details, let me know please!
1.32a
- The delay loading of the OpenGL DLLs on the Windows port was causing the
OpenGL initialisation code to fail. Reverted back to normal DDL loading but
with the side effect that Windows 95 users must visit the Microsoft web site
and download the OpenGL add-on before Snes9x will work for them.
- Corrected the OpenGL bump-map display option - my attempt to get the
bi-linear OpenGL display option to work with Voodoo card's limited texture
size had broken the bump-map mode.
1.32
- Changed the Windows port to delay load the two OpenGL DLLs, so now they're
only loaded if you switch to OpenGL mode. The original version of Windows 95
didn't include the OpenGL DDLs, so Snes9x wouldn't even start on that
platform; now it should.
- Added yet another sound buffer option to the Windows port - this time the
block size of sound data to mix. Some DirectSound sound card drivers only
report the play position moving in steps rather than continuous amounts and
Snes9x's default mix block size turned out to be smaller than this step
value on several cards.
Snes9x couldn't work out out where the true play position was accurately
enough resulting in broken, noisy sound output.
- Modified the Windows frame timer code to use semaphores rather than events -
they should make Snes9x more reliable at not missing frame sync pulses when
Windows is busy doing background tasks.
- Added SA-1 shutdown code - basically, Snes9x now stops emulating SA-1 CPU
instructions when the SA-1 enters an idle loop waiting for the main SNES
CPU to give it something to do. All SA-1 run much faster and smoother now.
- Added multi-axis joystick/game controller support to the Windows port and
tweaked the dead-zone threshold position a little.
- It looks like the SNES PPU was designed to support 128K of V-RAM but only
64K was fitted; Snes9x wasn't wrapping all V-RAM address to stay within the
64K limit causing a corrupt title screen on ReX Ronan - there will be others.
- Added amend functionality to the Windows Cheat Entry dialog and added extra
text boxes for direct address and cheat value input rather than only being
able to type in a Game Genie or Pro-Action Reply code.
- BS Suttehakkun2 was crashing just before start of play - the ROM was
performing a junk DMA that was corrupting RAM, crashing the game when it
went searching for a particular value.
- F-1 Grand Prix requires IRQ triggering when IRQ scan-line register set to
current scan line, but Chuck Rock objects. Hmm. Chuck Rock seems to indicate
the CPU emulation is running too fast, but I can't see where the mistake is.
Special-cased Chuck Rock for now.
- Optimised SNES DMA handling slightly - copying data to SNES V-RAM is now
significantly faster.
- Windows Cheat search dialog was ignoring data type parameter in various
places which was causing problems when larger numbers were being searched
for.
- Forced unknown PPU register reads to always return 0 - a coding bug in
Equinox shows that this is required. An earlier fix didn't work.
- Puya Puya 2 & remix were objecting to an NMI being triggered when enabling
NMIs after scan-line 226, but Ys 5 seems to require this. Hmm. Added a hack
to support both games.
1.31
- Snes9x DirectSound code modified - the mixing block size is now always 10ms
for Windows 95/98/2000 and 20ms for NT 4.x, now there should be no need to
enable Sync Sound when a large sound buffer is required (helps emulation
speed). The maximum sound buffer length values have been updated to reflect
the smaller mixing block size.
- Changed the DirectSound code back to use an offset from the play position
as the place to write new sample data into the sound buffer - on NT 4.x the
write position seems to vary randomly rather than being a fixed distance
in front of the play position as documented. Now I know why I used the play
position originally!
- Changed the DirectSound code to fill the sound buffer at the write position
supplied by DirectSound, rather than just before the current play position -
should help reduce latency.
- Added an auto-detect method for interleaved mode 2 Super FX ROM images -
well, not really auto-detect: if the game crashes and its a Super FX game,
Snes9x assumes its in interleaved mode 2, de-mangles the ROM image and tries
to run the game again.
- Had to update the Snes9x Windows registry version number as the additional
diagonal settings make old registry settings incompatible.
- Added diagonal keyboard controls to the Windows port, as requested by
several users.
- Changed PPU code to return zero when reading non-existent registers - the
game Equinox relies on this due to an original game coding bug.
- Included FMOD sound driver support to Windows port - people experiencing
broken sound or delayed sound, etc, might want to give it a try.
- Tales of Phantasia - un-interleaved format ROM memory map changes to match
odd ZSNES format, now the hacked ROM works.
- Changed NMI again. Made reading or writing to PPU register 0x4210
clear NMI pending flag again, without this Super Tennis does not work.
- Changed NMI timing back to be the same as several versions ago and just
special cased Cacoma Knight instead - although kept the code to prevent
the re-triggering of an NNI more than once in the same frame.
1.30
- Forgot to force GUI surface to be displayed when some dialogs where popped
up - problem only happened on full-screen mode with triple or double
buffering enabled, or when using 3dfx mode. It appeared as if Snes9x had
locked up, but pressing Esc would pop down the hidden dialog.
- Added a couple of options to the Settings dialog. Now its possible to
disable S-RAM auto-save which was causing Snes9x to write to the hard disk
every 30 seconds on some games, causing the occasional skipped frame.
- Fixed Reset option which was accidentally broken when Netplay support was
added.
- Added support for Dirt Racer - it leaves the Super FX chip running all the
time, so the default CPU emulation method never allocated any time to other
CPUs and the emulation seemed to lock up.
- NMI timing changed again. Now an NMI can only be triggered once per
frame and enabling an NMI after the normal trigger scan line triggers
an NMI immediately. This fixes display glitches in Ys 5, Stargate and
Daffy Duck.
- Fixed the WAI instruction to only 'wake up' once an actual NMI has
triggered, rather than just waking up when it should have triggered.
This fixes Battletoads, broken since version 1.29(ish).
- Changed NMI again. Made reading or writing to PPU register 0x4210 not
clear NMI pending flag. Seems to allow all the NMI timing sensitive ROMs
I had on my list to now work without any special hacks. Illusion of
Gaia now works again.
- Another NMI fix - cleared the CPU pending NMI flag at start of frame;
Battletoads intro was crashing without this. A long DMA was stopping the
SNES CPU so it couldn't and shouldn't respond to the NMI signal from the PPU.
- Fixed Netplay problem when game didn't have any S-RAM and Sync Using Reset
was being used. An error dialog was displayed and the client would disconnect
from the server.
1.30b#1
- The Windows auto-frame skip code was broken - badly. It didn't re-sync a
timer value with timer events being generated, causing Snes9x to deliberately
stop and wait for an event when it didn't need to, slowing down the overall
emulation speed and increasing the number of frames skipped.
- Improved the Windows cheat search dialog - its now possible to compare
against a value and more comparison functions are available.
- Finally worked out why Voodoo 3 support was so buggy in Snes9x - the Voodoo 3
card generates a WM_DISPLAYCHANGE message when switching to Voodoo mode (the
Voodoo 1 and 2 cards don't); Snes9x thought that some other application had
changed the screen depth or resolution and tried to adjust its window to
match - triggering another WM_DISPLAYCHANGE message. No idea how the code
worked at all; it must have been only by chance and very dependant on the
driver version you were using!
- Implemented Netplay on the Windows port - but its buggy as hell. I seem to
be having major Windows multi-threading problems. Comments I've seen seem to
suggest that Windows 95/98 don't implement true multi-threading; hmm...
- Not happy with the current Netplay, so I scrapped it and tried again;
the protocol is much improved and not using select to control game timing
seems to have removed lots of the threading-type problems I was having.
- Attempted to switch to just using Borland's C++ Builder to build the Windows
port - and failed, again. Although C++ Builder can build Snes9x from sources,
it can't then link in the asm CPU cores. I had hoped Borland might have
fixed this with their latest release - they haven't.
- Several attempts to get Anti Resonance's super-fast sound CPU and sound DSP
code working in Snes9x, but all failed. Part of the problem was his code was
written using TASM and the object files it generated would only work under
Windows - but all my SNES debugging code was in the Linux port. Anti' fixed
that, and I then had some success getting his code working, but its just too
unstable at the moment for a main-stream release.
- Included an option to use Anti Resonance's alternate sample decoding routine;
it can approximate the wind and noise sound effects heard in several Square
Soft games.
- Thanks to Lindsey Dubb for the mode 7 bi-linear filtering code - it
generates a nice smooth image when a game scales the screen using the SNES'
mode 7, but you'll a fast machine if you don't want the frame rate to drop.
- Thanks again to Lindsey Dubb, he improved the colour addition/subtraction
subtraction routines - they are just a little slower but now mostly perform
full 15-bit precision addition and subtraction rather than the previous
13-bits of precision. Many more colour shades can be seen - look at the
improved shading on the Mario Kart or F-Zero track for example.
- Added a reverse stereo option, for people with sound cards that swap the two
channels.
- Added a sound config dialog to the Windows port - now you can access extra
sound options that have always been there, but just no GUI interface to
access them.
- Fixed the 32-bit windowed support on the Windows port.
- Adjusted the NMI timing by a few microseconds to get Metal Warriors working
again.
- Added a few more sound playback rate choices. Most modern sound cards allow
any value to be used from a large range, rather than just a select few, may
be I ought to add text field so you could just type a value in?
- Used Factory Setup 4 to build a new installer package for the Windows port -
just shipping a zip file was confusing novice users and many (mostly AOL
users) seemed to have an odd program mapped to .zip files, further confusing
the issue.
1.29
- Disabled the SPC700 noise feature simulation used by Chrono Trigger and
Final Fantasy 3 until I work out why its being triggered by sound effects
that don't use it.
- Rewrote/reorganised the DirectX and 3D/fx handling code, now both are never
enabled at the same time in Snes9X. It might fix the crashing problems some
Window port users are seeing. Changing between DirectX and Voodoo 3D/fx
modes now requires Snes9X to be restarted.
- Tracked down and fixed the Chrono Trigger black screen problem on the Windows
port: a rogue asm instruction was left in by mistake after some code edits -
it was only by chance that the code worked on the Linux port.
- Added some SNES debug options to the Windows port, but disabled by default,
on the shipped version.
- Clicking on the column headings in the OpenROM dialog in the Windows port
now sorts by that column; plus added some slight screen update optimisations.
- Added an optimisation to graphics rendering: don't add or subtract
sub-screen from background layers, or clear the sub-screen, if SNES fixed
colour is black and no background layers are enabled on sub-screen, even if
ROM tries to enable translucency effects for every background layer.
Discovered Sonic was doing this, there will be others.
- Forgot to enable auto S-RAM save on Windows port, oops!
1.28
- Warning dialog added to the Windows port - if a ROM is loaded from a
read-only directory, e.g. a CD, and the freeze file folder is set to be the
same as the ROM image folder, then a warning is displayed when the game first
starts.
- The Windows port now supports 5 joy-pads - Snes9x always did support 5 but
the Windows port lacked the GUI option to enable and configure it.
- Added an about dialog to the Windows port.
- The Windows port now has a simple settings dialog, only one option so far -
changing the freeze file and S-RAM save directory; much better than having to
use regedit at least.
- Added a new cheat search dialog, you can use it to find where games are
storing life counters, health levels, etc. and then add cheats that stop the
values from changing.
- Added a cheat code entry dialog to the Windows port; now Game Genie,
Pro-Action Replay and Gold Finger codes can be graphically entered and
edited.
- Added a master cheat codes on/off toggle, available from the Cheats menu
on the Windows port.
- Extended the number of cheats per game from 10 to 75.
- Changed cheat code to reapply cheat every emulated frame so if RAM is being
patched the cheat value is continuously applied.
- Wrote some new cheat search code, the code won't be useful until I get around
to writing a cheat search dialog.
- Added automatic cheat code loading and saving using the same file format as
ZSNES.
- Rewrote large parts of the Snes9x cheat handling code ready for adding
cheat dialogs to the Windows port.
1.27
- Added a flag to only enable SPC700 noise 'feature' when Chrono Trigger or
Final Fantasy 3 are loaded - the conditions that I thought were necessary to
trigger the feature where sometimes being met by other games.
- Added a simulation of the SPC700 noise 'feature' where some games, notably
Chrono Trigger and Final Fantasy 3, play samples that deliberately overrun
outside a 16-bit value, the SPC700 sound DSP then for some reason starts to
generate a type of noise sound which the games use to generate wind and
swish type sound effects. Thanks to ZSNES for some of the information.
- Fixed another sound interpolation problem, thanks to Mikael Bouillot -
the initial value of the sample byte being played was not being set correctly
when processing fractional offsets.
- Added auto S-RAM save option; S-RAM is automatically written to a .srm file
a few seconds (30 by default) after a ROM writes to it - useful for people
who were playing games long into to night, only to lose their progress
after a power cut or machine crash.
- NMI delay code changed again - the fix for Cacoma Knight was breaking
Tuff E Nuff; it would seem delaying NMI until the start of h-blank to too
long, added a cycle counter instead.
- Fixed yet another clip window bug - clip window was being incorrectly set
at no range if colour window was enabled but background layer clip window
was disabled (meaning layer should not be clipped).
Fixes the sunken ship level on FF5.
- Worked out (by example) how to add keyboard accelerators to the Windows port,
now toggling full screen using ALT+Return works.
- Added mouse-warp to the Windows port so the the cursor doesn't wonder off the
Window while SNES mouse emulation is enabled.
- Improved 3dfx support on Windows port - load dialog doesn't drop out of
bi-linear mode and underlying window zooms to full-screen so its easy to find
and click on the menu bar with the mouse.
- Added Mouse and Superscope SNES emulation support to the Windows port, use
'7' on the keyboard to select.
- Windows cursor now hidden unless super scope emulation is enabled.
- Windows port now has command line parsing - cheapo way of adding Game Genie,
Pro Action Replay cheat codes, disabling sound CPU emulation for the
corrupt copy of Star Fox 2, etc. Also allows ROM images to be dropped onto
the Snes9x icon.
- Cacoma Knight seems to provide proof that Snes9x triggers the SNES
non-maskable interrupt (NMI) too early. Changed interrupt to trigger at the
start of the next horizontal blank period. Will have to watch for it
causing problems for other ROMs.
- Added a translucency hack - when a ROM tries to create a stipple background
pattern by enabling pseudo hi-res. and not enabling a background layer on
one of the screens, Snes9x changes the effect to use transparency effects
instead (the real SNES can't do transparency effects with pseudo hi-res.
enabled). Now the water in Kirby 3 is translucent.
- SA-1 CPU reset bug fixed, now Jumpin' Derby boots and plays but with major
graphics problems.
- Fixed nasty asm SA-1 custom hardware read/write bug that was causing the
course map not to be displayed on Augusta Masters and Pebble Beach.
- Added SA-1 character conversion DMA support for all SNES depths, now
Augusta Masters and Pebble Beach work.
- Merged in minor code changes for Linux running on the Alpha processor. Thanks
to Sadruddin Rejeb for the changes.
- Added four more auto-multi-player-adaptor-emulation-off presets based on
code from Mystagogus.
- Added DirectX3D output image processing support to the Windows port... and
removed it again because it causes my desktop machine to lock up. Back to
the drawing board...
1.26
- Fixed memory leak that crept in when SA-1 support was added when loading a
game freeze file.
- Added SPC dumping option based on code from Cyber Warrior X that he sent me
ages ago but I've just found again while looking for something else!
- Merged in most of the Amiga PPC port source code changes into the main
source code tree.
- Keying on a sound channel seems to clear its last-sound-sample-block-just-
played flag. Chaos Engine/Soldiers of Fortune needs this.
- Add multi-thread support to the UNIX ports for sound playing - required in
the Linux port to work around a Sound Blaster Live driver bug and useful if
you have multiple CPUs in your machine to help spread the emulation workload.
1.25
- Added BS 24Mbit ROM memory map, for Derby Stallion 96 and Sound Novel-TCool.
No idea if it works. Thanks to Nose0000 for the info and code.
- Corrected unzip code not to loop forever if an encrypted zip file is loaded -
an error is generated instead.
- Changed relative SPC700 cycle length for Mortal Kombat 3 to fix sample
repeat problems - I wish I knew exactly how fast the SPC700 is clocked.
Maybe I should write a test ROM and run it on a real SNES?
1.24
- 3dfx speed hack back again, only disabled when Seiken 3 is loaded.
- Some minor SA-1 speed ups added - the SA-1 instruction skipping code will
have to wait until I have more time.
1.23
- Corrected a SA-1 reset bug that reset the SA-1 RAM bank pointer back to block
zero but didn't clear the RAM bank register. Was causing Kirby 3 to crash.
- Fixed a wave clipping problem with interpolated sound that was causing noise
on sound output when certain sound samples were played.
- Fixed a bug in the sync-sound code that could overrun the sound buffer by a
few bytes causing clicks on the sound output.
- The sound sample repeat bug that has plagued Snes9x ever since is was called
Snes96 finally bit the dust - Snes9x continued to play sample loops
even if the game dynamically updated the sample not to loop. Fixes the
stutter in the Mortal Kombat series and improves the sound from several games
that download sound samples in real-time as they are played.
- Rewrote the code the handled the SPC700's 64 byte shadow RAM area to fix a
possible sample corruption problem with ROMs that stored samples that
cross the 64 byte start area.
- Added code to allow ROMs to change the sample being played the next time the
channel loops or is keyed on - not sure if it fixes anything but seems more
correct.
- Added a zero-frequency fix to the stereo sound mixing code that I'd already
added to the mono code some time ago.
- Changed the code to set the end-of-sample flag just before the last block is
played, rather than just after. Seems to help improve the sound on some
games.
- Sound sample start code now doesn't reset the channel's envelope volume level
to zero before starting the sample - helps reduce the clicks being heard when
a channel envelope volume level hadn't reached zero before being keyed on
again.
- Changed initialisation of sample-end-register to 0 rather than 255 - seems
more logical now I've thought about it. Not sure if it helps anything.
1.22
- Finally fixed the corrupt copy of Donkey Kong Country not working problem -
Snes9x thought the ROM used the same memory map as Street Fighter Alpha 2.
- Added explode, un-shrink and un-reduce decompression modes support to the
unzip code.
- Fixed offset per tile bug that crept in after me trying to fix the Starfox
on-tilt bug.
- Made some fixes to the C Super FX emulation code, enough to get most 'FX
games playable on the Mac port.
1.21
- Finally worked out how character DMA worked on the SA-1 and implemented a
hacky, slow version, but its enough to get the level up screens displaying
correctly on Mario RPG.
- Incorporated ZSNES' new optimised Super FX asm code - had to track down and
fix a nasty memory overwrite bug in the code first to get it to work.
- Changed sample mixing code to not automatically wrap offsets to
keep inside the sound buffer, external port code is now expected to do that.
Helped me fix a problem in the Windows port that prevented very large sound
buffers from working, which are required for some badly written sound card
drivers.
- Corrected a bug in the SA-1 C code where incorrect processor emulation
functions where called if the code was compiled with in-lining turned off.
- Fixed crash bug in Super Mario RPG on the level up screen - forgot to mask
the enable bit from the RAM bank register. Thanks to Christian Wolf for
sending me a freeze file which made it easy to find the problem.
- Fixed a lockup bug in the window clipping code, if the ROM ever turned off
the sub-screen completely the clipping code would enter an infinite loop.
Fixes The Cartoon Addams.
- Made the Daffy Duck NMI fix only enable when Daffy Duck is loaded - fix was
causing problems for Breath Of Fire 1 and 2.
1.20
- Windows port no longer sets DirectSound to exclusive mode, so its now
possible to hear sound output from Windows apps while Snes9x has focus.
- Fixed the freeze file loading and saving on the Windows port.
- More GUI settings are saved in the registry on the Windows port now.
- Added 3D/FX image scaling/filtering support to the Windows port.
- Added the TV mode from the Mac/Linux ports to the Windows port.
- Incorporated Kreed's new output image routines into the Windows port that
fixes RGB555 display colour problems. Many thanks to Kreed.
- New auto-frame rate timing code on the Windows port, stops the silly speed
up problems when the old code tried to 'catch up' after the emulator had
been paused.
- Increased the DirectSound secondary buffer length on the Windows port to
hopefully fix all the static/broken sound output problems some people were
experiencing.
- Altered the ZSNES Super FX asm code so the Windows port could use it - all
previous versions of the Windows port were shipped using the C Super FX
emulation code which is a lot slower.
- Implemented interpolated and sync-sound options on the Windows port.
- Added an image stretch option to the Windows port - stretches the SNES image
to fill the whole screen or the Window. Looks really good on my TNT card
since that chips seems to filter the image as it scales it.
- Implemented Windowed mode on the Windows port.
- Added special SPC700 cycle timing for Empire Strikes Back.
- Fixed the missing polygon problem for Super FX games - thanks to zsknight
for the information.
- Implemented SA-1 support required for Mario RPG, Kirby Superstar,
Paradius 3, etc. but since only a good image of Mario RPG exists, I could
only test that game.
- Fixed a graphics clip window bug: inverting the area of a clip area that
only consisted of empty bands should become the full width of the screen;
Mario Kart's rear-view mirror display needs it.
- Fixed mode 7 render code to use correct z-buffer when rendering onto the
sub-screen. Fixes Final Fantasy V title screen.
- Added horizontal offset per tile support in the offset per tile modes 2
and 6, and switchable horizontal/vertical offset in mode 4. Fixes Chrono
Trigger in several places and Mario All Stars title screens.
- Changed SPC700 relative cycle length to 14, needed for Stunt Car Racer.
- Enabled immediate triggering of NMI if NMI enable flag set while scan-line
was on first line of v-blank. Needed to fix a background jitter bug in
Daffy Duck: The Marvin Missions.
- Altered ROM load code to ignore corrupt ROM map type byte in ROM header,
preventing the code erroneously detecting what it thinks are interleaved
ROMs. Fixes EEK! The cat, Formation Soccer, the corrupt copy of Donkey
Kong Country, ...
- Disabled IRQ re-triggering if V-IRQ registers set to the current line. Fixes
Chuck Rock.
- Fixed missing sprites in Andre Agassi Tennis - writing to low byte only of
the sprite write address register seems to also clear the hi-byte.
1.19
- Games written by the Japanese software company Human seem to need special
SPC700 sound CPU timing, so the ROM load and reset routines now check the
software author company and adjust the CPU cycle length accordingly.
It gets Clock Tower, Super Fire Pro-wrestling Premium, etc working.
- Added ROM check sum calculation and testing code - Snes9x can now detect
pure, corrupt or hacked ROMs.
- Noticed a fast way to implement the SNES 4096 colour mode, so I implemented
it. Now the colours in ActRaiser 2 look correct.
- Corrected a noise frequency error thanks to information from Takehiro.
- Added a 'start in full screen mode' flag to the Linux port.
- While debugging the new graphics code I thought of a fast way to implement
the SNES direct colour mode, tried it out and now the colours in Actraiser 2
are correct.
- Blast, forgot about the colour window and fixed colour effects. The separate
sub-screen is back again, but all the other graphics speed ups are there.
- Now I've got a z-buffer I keep finding other ways to optimise the SNES
graphics rendering - no need for a separate sub-screen, no need to clear
the sub-screen to the fixed colour, no need to waste CPU time on translucency
effects on hidden pixels, no need to completely clear the main-screen to the
back drop colour, etc., etc.
- Implemented a software z-buffer and changed the SNES graphics rendering to
use it (required change for future 3D card support). Finally fixes the
sprite-to-sprite priority bug that some games suffer from. Also a big speed
increasing for some games (10 fps+), others are slight losers.
- Added code to skip the rendering of completely transparent graphic tiles
rather than comparing each pixel to see if it is transparent; helps the
frame rate a bit on some games.
- Added a fixed for Tetris & Dr. Mario - the game didn't like a multi-player 5
adaptor plugged in to the real SNES when being played, so turned off the
adaptor emulation for this game.
- Added hack for Final Fantasy II - if sync sound isn't on, make attack rate of
1ms actually 0ms (old v1.16 behaviour). Causes a slight click but its better
than samples being cut short.
- Fixed a clip window area invert bug if the colour window was enabled on
on one window and the other window was being used to clip a background layer.
Fixes the finial (I hope) display problem with Gun Hazard.
- Added code to intersect the clip window areas if both a colour window and
a background layer clip window were enabled at the same time. Required by
Gun Hazard.
- Forgot to mark graphic clip windows as needing recomputing when the master
colour window inside/outside/on/off/main-screen/sub-screen PPU register was
updated. Was causing display problems for Gun Hazard.
- Internal H-DMA execution accelerator pointer variables where not always
being recomputed when started H-DMA part way into a frame. Was causing
display problems for Gun Hazard.
- Made H-DMA continue for one extra scan-line to fix a disappearing monster
problem in Dragon Quest 5. Thanks to Alex Jackson for the bug report.
- Zoop seems to require volume envelope height reading by the sound CPU to
always return 0 when the channel is in gain mode.
- The sound code was ignoring updates to the ADSR volume envelope rates while
one was in progress. Fixed that and now the bird song at the start of
Chrono Trigger sounds correct.
- Had to disable the CPU shutdown code for loops reading the horizontal beam
position, it was causing problems for Star Fox. Still no polygons though.
- Oops, sound DSP noise output was broken - accidentally deleted an important
line while removing debug code ready for the last release.
- Added initial 3Dfx support to the Linux port - basically using the Voodoo
card as a bi-linear filtering, scaling blitter. Actually slightly slower than
TV mode, for non-scrolling images due to poor texture upload speeds to the
card, but the full-screen feature is nice and the speed doesn't drop as more
of the screen changes.
1.18
- Implemented a sync-sound mode where sound data gets generated in sync with
SPC700 instructions being executed. Finally the sound Williams Arcade
classics can be heard. Also helps slight sound timing problems in many other
games but doesn't fix Mortal Kombat 2 like I thought it would - its
sound routine programmers must have been on drugs or something!
- Added interpolated sound - gives low frequency sounds much more bass similar
to a real SNES especially with the playback rate ramped up to 44KHz.
- Added on-screen messages as various emulation options are toggled on and off
using the in-game keys.
- Fixed a PPU register read bug with the sprite register write position. Thanks
to Takehiro TOMINAGA for the bug report.
- Altered the auto-frame skip timing code to only wait and re-sync to the end
of frame when frames haven't been skipped. Again thanks to Takehiro.
- Speeded up the colour addition and subtraction code using ideas from
Takehiro.
1.17
- Linux and UNIX sound code now driven directly from signal timer handler
rather than the timer handler just setting a flag which had to be polled in
the main emulation code. Slightly faster execution.
- Fixed the crash bug in the ZSNES Super FX asm code with Vortex - the game's
polygons still aren't visible though.
- Implemented bent-line increase and exponential decay and sustain volume
envelopes - they should match, or at least be very similar to the real SNES
sound DSP chip now.
- It would seem ROMs can key on sound channels even if the channel hasn't
been keyed-off, Pac-In-Time requires it. Changed code to allow it.
- Quick mod to ZSNES Super FX code to get Winter Gold working - it was already
working with the C Super FX code.
- Added emulation of the extra 1/2 scan-line per frame on PAL and NTSC -
should help improve music speed emulation.
- Worked around the click sound heard when ROMs use 0 volume envelope attack
rate.
- Removed the 'check for IRQ already happened' H-IRQ position register setting
code - it was causing problems for Ninja Warriors and was not required by
F1 Grand Prix.
- Fixed a bug in the new sound code - the sustain part of the
attack-decay-sustain-release volume envelope was being skipped if the
sustain level wasn't at 100%. The fix has helped some music notes from
being cut off early in a few games.
- Added fix to Pro Action Reply support (again). Thanks to Paul Shoener III for
the original fix and Gil Pedersen for reminding me to apply it!
- Finally fixed the Tales of Phantasia 'bum note' problem! The ROM set its
sample directory to the upper-most page and I forget to code for the hidden
64 bytes of RAM, that appear when the boot ROM is switched off, when fetching
sample addresses.
- Adjusted the relative cycle length between the 65c816 and the SPC700 slightly
to get Terranigma working again.
- Oops, the emulated joypads 3 and 4 via the emulated Multi-player 5 interface
weren't working. Thanks to Steffen Schwenke for the bug report.
- Optimised the echo sound code - by-passed the the FIR filter code if only
a pass-through FIR filter was defined by the ROM.
- Modified V and H-IRQ register changing code to trigger an IRQ immediately if
V-IRQ is enabled and the scan-lines match and either H-IRQ is not enabled or
the electron beam position has already gone past the trigger point. Fixes
the screen flicker in F1 Grand Prix.
- Modified the priority-per-pixel mode 7 code to use BG#1's clipping data if
the top bit of the mode 7 pixel is set. Fixes initial track drive-through
display in F1 Grand Prix.
- Modified the sprite priority levels for the priority-per-pixel mode 7
display. Now the car can be seen in F1 Grand Prix.
- Wrote a sound DSP register recording scheme which 'plays back' the register
changes in sync with the sound generation code. I'm bit disappointed, it
only improves the sound in a very few games... Scrapped the code, it actually
causes more problems than it fixes. Oh, well, another 3 weeks work wasted...
- Fixed a SPC700 wake up problem for Lufia I - made the SPC700 also wake up
when the 65c816 read from one of the four comm ports.
- Included lots of sound code speed ups and sound quality improvements
from Takehiro TOMINAGA - many thanks go to him.
1.16
- Fixed a case where the -forcelorom option didn't work - the case was
required for Formation Soccer which claims in its ROM header to use the
same memory map as Super FX ROM, it doesn't.
- Pulled apart a real SNES using a crowbar (great fun), just to look at what
speed the SPC700 is actually clocked at for more accurate relative emulation
speed.
- Implemented SPC700 cycle counting in the hope the improved timing would fix
Tales'; no such luck but at least the -ratio option is obsolete now.
- Implemented executing SPC700 instructions during DMA, fixes BSZelda and
Goal lock up at start and music pausing briefly when ROMs do lots of DMA,
usually between game screens.
- Scrapped the i386 asm SPC700 code - it was the cause of the music not
restarting after a battle in Chrono Trigger and FF3 and I didn't realise
because the bug had already occurred in the test freeze-file I had.
Thanks to John Stiles for pointing out that the Mac port didn't have the
missing music problem.
- Fixed RGB subtraction bug on displays with only 5 bits for green, e.g. RGB555
displays. The GREEN_HI_BIT variable was always set to a value for 6 bit
green displays.
- Added the SA-1 memory map, still a long way to go before any SA-1 game will
run.
1.15
- Jumped versions to keep in sync with the DOS port release.
1.14
- Improved 8-bit sound generation slightly, but it still sounds very poor
compared to 16-bit sound.
1.13
- Implemented the Tales of Phantasia memory map using the information supplied
by zsKnight. Had to also implement a de-interleave routine to work around
a ROM feature and Snes9x CPU instruction fetching implementation detail.
- Added a frames-per-second on-screen display option.
- Fixed the final glitch bug with the Mario Kart track display - the byte code
for the termination of the DSP1 raster command wasn't been recognised.
- Disabled a NMI/DMA hack for Rise of the Robots, was causing problems for
Mario Kart and 'Robots wasn't working correctly anyway.
- Optimised the mode 7 rendering a little.
- Changed tile rendering code to use offsets into screen buffer rather than
direct pointers ready for z-buffer implementation.
1.12
- Changed V-blank NMI to occur immediately after a WAI instruction, Toy Story
required this.
- Fixed reading of H-DMA line counter register, Top Gear 3000 needed this.
- Ripped off large parts of ZSNES's DSP1 code (with _Demo_'s and zsKnight's
approval). Now Mario Kart works almost 100%.
- Added a check to see if a vertical scan-line IRQ register change will cause
a H-IRQ later on the current scan-line. Pilot Wings needed this.
- Fixed possible crash bug in clip window code when both windows had two
spans. Could actually cause Chrono Trigger to crash the emulator.
- Fixed a lock-up problem with the C Super FX code, Star Fox and executing
a few 'FX instructions per scan-line (required for Winter Gold).
1.11
- Partially fixed the DOS netplay server - the server timer is running too
slowly and it doesn't deal with disconnects correctly yet.
- Corrected the sound echo delay - it was varying with the sound playback
rate chosen by the user - it shouldn't have been.
- Implemented DOS netplay code - DOS server code still not working though.
- Removed all floating point calculations from the sound generation code.
- Fiddled with the pitch modulation code - my guess is the output of a
channel that is used to modulate the frequency of another channel is
automatically muted by the SPC700 chip. Just a guess, but the wind from
FF3 sounds 'better' but far from perfect.
- Optimised the tile palette index calculation.
- Optimised the planar to chunky tile conversion code.
- Fixed X11 port to always scale SNES image if hi-res. only (no interpolation)
support is enabled.
- Added zipped ROM image support using Gilles Vollant unzip code and
some code that Ivar (Lestat) sent me a long time ago.
- 65c816 asm RTI instruction was destroying the program bank in emulation mode,
the C code was already correct. Caused C64E to break.
1.10
- Finished NetPlay v1 - allows up to five networked machines to play
multi-player SNES games, one player on each machine.
- Switchable full-screen mode added to Linux X11 port, some code and ideas
nicked from Maciej Babinski's original Snes9x XFree86 DGA Linux port, the
UAE Amiga emulator, plus lots of my own code.
1.08
- Bug fixes to C Super FX emulation - now Winter Gold works correctly again.
1.07
- More DSP1 work. Mario Kart is now playable! The character projection code
is still broken so the opponents and obstacles aren't always positioned
correctly on screen and you keep bumping into them, but I can still keep
coming first!
- Started work on NetPlay support.
- Decreased sound card DMA buffer size on DOS port to improve sound generation
and sound CPU synchronisation in some games.
- Included Linux joystick driver patches from Vojtech Pavlik so the port can
use the new v1.x joystick drivers, again written by Vojtech Pavlik. Allows
use of Micro$oft Sidewinder pads, NES and SNES pads, PlayStation pads,
Gamepad Pros, etc.
- Added halve-the-result colour subtraction.
1.06
- Extended code to allow support for multiple 16-bit screen formats,
switchable at run-time, rather just supporting one, selectable at compile
time.
- Added XFree86 DGA Linux port - code from Maciej Babinski.
- More fixes to the X11 image format conversion and setup code.
- The asm SetByte routine wasn't wrapping writes to S-RAM correctly, allowing
some ROMs to think they were running on a copier and put up an error
screen. Thanks to Nu of #rom for the report.
- Added 'TV-Mode' support (interpolation and scan-lines) to the DOS and
UNIX ports from code based on John Stiles work.
- Added v-sync option to the DOS port.
- Added fix to Pro Action Reply support, thanks to Paul Shoener III.
- Added ggi support (untested) to Linux port using patches from
Alexander Larsson (alla@lysator.liu.se).
- Added 16 to 24/32 bit image conversion routines to the UNIX X11 code.
- The SPC700 OR1 instruction was broken. Thanks to Pyrgopolinices for the
report.
- DOS port was having trouble splitting and joining path names - caused
problems when specifying the full path name of a ROM when the ROM image
was on another drive.
- If a ROM reset the sound DSP and then turned on echo effects but kept
the same echo delay setting, then the echo effects could not be heard.
Thanks to madec@mclink.it for the bug report and freeze file that made it
easy to find the problem.
- DOS port was always using stereo sound setting, if sound card
supported it, regardless of the user preference.
- Linux port X11 port could crash if window was resized while transparency
effects were enabled.
- The colour subtraction accelerator look-up table was slightly wrong, causing
one bit of red, green blue values to 'spill' into the next field.
- Allowed colour window to cut a hole in the main-screen and show the sub-
screen underneath. The effect is used by Illusion of Gaia.
- Added support for colour subtraction, with the halve-the-result flag
set.
- Included DSP1 code from _Demo_. Now you can see the track in Mario Kart and
the ground in Pilot Wings - still can't play the games though due to other
missing commands.
- Added an NMI hack to work around a code bug in Battle Toads: BATTLEMANIACS,
its only by chance that the game works on a real SNES - And disabled it
again because it causes problems for Chrono Trigger.
- A frame skip of zero was actually still skipping one frame. Thanks to
Marius Fodor for the info.
- And yet more X-OR window bug fixes - now the effects during some of the more
'posh' spells look correct in Chrono Trigger.
- Yet another window area inversion bug - off by one pixel on right-hand edge.
- Forgot to put dummy start and end points for XOR window combination modes -
now Uniracers looks correct and Sailor Moon looks like it does on a real
SNES.
- Window clip code was using wrong index into a 2-dimensional array when
the whole of the main or sub-screens were clipped.
1.05
- The master volume disable code was looking that the wrong variable!
- Fixed crash bug in newer sound code if a ROM tried to start a sample
playing who's data went past the end of SPC700 memory. (Cannon Fodder)
1.04
- Fixed DSP1 ROM header detection bug.
- More DSP1 work; still nothing works, although I know the multiply command
is correct because I've compared the results against a real DSP1.
1.03
- Oops, the multi-player 5 disable code change broke the multi-player 5 being
the default controller.
- Implemented the colour window on the main screen - now Zelda's oval zoom
window displays correctly and Krusty's Super Fun House clips the left-most
8 pixels as it does on the real SNES.
- TERRANIGMA didn't like me returning a random value when it attempted to
read a channel's the current sample byte.
- Hacked in initial support for mode 7 priority-per-pixel - the priority bit
doesn't actually change the priority of the pixel but the two games that I
know of that use the feature look OK. (Winter Extreme Skiing and the
intro of Tiny Toons Adventures).
- Colour addition/subtraction code now uses RGB565 rather than RGB555
calculations - helps a little with the loss of the bottom bit of SNES
colour data.
- DSP1 emulation started - nothing works yet.
1.02
- Switched to adding back drop colour rather than fixed colour when
sub-screen addition is enabled but there's nothing on the sub-screen.
Uniracers seems to need it. - DISABLED it again. Causes problems for
other ROMs and Uniracers itself on later screens.
- Fixed XOR window logic combination mode and area inversion code, now
Uniracers works correctly.
- Oops, if colour window and half colour addition/subtraction were both
switched on, area outside colour window was still being halved, it shouldn't.
Hacky fix at the moment until I implement the correct fix.
- Fixed several bugs with the mosaic effect and 16x16 tiles and a few
possible background scroll offset bugs and the mosaic effect.
- Optimised the sound sample generation code for cases when the SNES
sample playback frequency was higher than the sound card playback rate.
- Fixed possible click sound when a sample was first started to be played.
1.01
- Corrected scan-line count for PAL games - should be 312 lines verses 262 for
NTSC. Was causing slow music on PAL games.
- Added error correction code to the SPC700 timer update code - the
SPC700 timers are updated using the emulated h-blank handler which is
called every emulated 63.6 microseconds (15.720KHz) but the SPC700 timers
need to be updated at multiples of 8KHz, hence the error. Was causing
music to be played slightly too fast.
- Switched back to using C SPC700 code - the old SPC700 asm code was lacking
several optimisations that the C version had. It also had multiple
speed hack cycle skipping bugs. Plus I hadn't even finished optimising
all the code from the last time I converted the C compiler output.
- Optimised SPC700 memory access routines a little.
- Disabled code that prevented ROMs updating SPC700 timer values while the
timer was running - it seems like it is allowed, even though docs on the
'net I've seen say its not.
1.0
- Fixed SuperScope support.
- Added hi-res. option to my DOS port.
- Fixed 4, 6, and 8 button standard PC joystick support.
- Changed some types the source code was using BYTE -> uint8, WORD -> uint16,
DWORD -> uint32 and BOOL -> bool8, types were clashing Windows typedefs
but sizes didn't always match.
0.99
- 8-bit double height and/or width tile rendering was missing every other
group of 4 pixels - screen pointer advance count was wrong.
- Asm SPC700 emulation was ignoring the Shutdown flag - the result is its
not possible to turn off cycle skipping for the SPC700 emulation.
0.98
- CPU to ROM address decoding code rewritten - used by Game Genie cheat codes,
orginal code might have been the cause of some Game Genie codes not working.
- Started to remove printf calls and replace them with calls to S9xMessage,
port code can then dicide what to do with message.
0.97
- Re-enabled decompressed sample caching, still has a possible click problem
but the sound code is a lot faster with it enabled. Added command line option
to disable it if required.
- Added '7' key support to rotate through available controller options, in
the order multi-player5, mouse on #1, mouse on #2, superscope,
standard controller and then back to multi-player5.
- Hi-res. (512x448) support fixed.
- Mouse support completed - Lemmings 2 and Mario Paint working a treat.
- More colour window fixes.
- Fixed freeze game problem when ZSNES SuperFX code is being used -
ZSNES 'FX state was not being saved and restored.
- ZSNES SuperFX asm emulation code plugged in to Snes9x.
0.96
- Looks like if the colour window is not enabled at all and the colour
window selector is defined to only allow colour effects inside the colour
window, then no effects should be visible.
- Offset-per-tile rendering code didn't support width 64 screen size, which
Chrono Trigger used on its title screen.
- Contra 3 seems to prove that defining the clip window area to be 'outside'
a window that covers the whole screen is not an area with no range.
- No it doesn't. It proves that I shouldn't have initialised the right
window edges to 255! Contra 3 enables clipping windows without first
defining their range.
- Debug frame advance feature was being prevented from forcing the next
frame to be rendered by SyncSpeed which was being called after the
debugger returned to the main loop.
- H-DMA code was allowing ROMs to manually start H-DMA during the v-blank
period, ROMs shouldn't be allowed to do this.
- Asm code would not push the correct CPU status onto the emulated stack if
returning from an NMI immediately triggered an IRQ - fixes Mortal Kombat 1
and War of the Gems.
- 'd' dump memory debug command was not preserving the CYCLES count.
- C versions of SNES memory access code had same problem as asm code on the DOS
port except it didn't cause a crash just ROMs failed to work correctly.
- Asm i386 code was using signed compares to check for special case memory
areas - it was causing crash problems on the DOS port which was sometimes
returning valid address values with the top bit set - i.e. they seemed
like negative values!
- Changed event reschedule code to always allow h-blank start events, used to
disable them during v-blank period.
- Added code to HDMA when end of visible lines reached.
- Changed register 4212 code not to always return h-blank when in v-blank.
- Clipping fixed colour addition to background area was off by one pixel on
the right-hand edge.
- HDMA: Finally worked out how the real SNES operates when ROMs manual
start H-DMA during the frame - ROMs must set up the H-DMA line count
and address values before H-DMA is started.
- Fixed the asm code to remove all hard-wired structure offsets - one offset
into the IPPU structure was wrong in the code because the structure had
changed size.
- Added colour window support and allowed graphic window settings to be
different on the main screen and sub screen, just like a real SNES.
- SuperFX LJMP instruction had bank and address values swapped.
- Fixed possible memory overwrite problem because OBJList array was one
element too short.
- Added AND multi-graphic window combo support.
- ROM image memory allocation allocates an extra 32K of RAM, then moves the
pointer forward by that amount - stops the SuperFX emulation from accessing
unallocated memory, possibly causing a crash.
- SuperFX emulation now stores sign and zero flags in separate variables so
the MERGE instruction can set flags correctly.
- Added 65c816 instruction skipping to i386 asm code when 65c816 waiting in
a simple loop for some 'event' to happen e.g. end of frame NMI.
- Finally fixed the APU instruction skipping problem with the i386 asm
code when the WAI instruction is used - caused slow music on some ROMs.
- Offset-per-tile modes don't seem to support screen size - Mario All Stars
Super Mario 2 requires this on title screen. Doesn't seem to effect
Tetris Attack or Puzzle Bobble.
- Changed SNES select and start keys from shift and control to space and
enter - allows shift-fn key to save game positions without the SNES ROM
also getting a select joypad button press.
- Multiplayer5 support for controllers 3+ was broken for ROMs that used
automatic hardware joypad reading rather than reading joypads serially.
- ResetPPU was not clearing tile caches and marking OBJ as need recomputing.
- Cached OBJ positions and sizes were not being recomputed if ROM changed
global OBJ sizes during frame.
- Fixed brightness multiplication problem on 16-bit code for green.
- SPC700 emulation now uses one variable to store ZERO and NEGATIVE flags.
- SPC700 emulation now only increments PC once at end of instruction.
- New ROM type and interleaved detection code.
- Reading sound DSP register ENDX also clears the value. The docs on the
'net said that only writing to the register cleared its value. Fixes
sound in Zoop.
- Fixed mode 4 colour palette problem on background #2 in tile-based graphics
code.
- Fixed graphics mode 4, offset-per-tile support. Only one set of offset data
that is switchable between horizontal and vertical, unlike modes 2 and 6
which allow separate horizontal and vertical offsets per tile.
- Modified the APU timer code again, if the timer is enabled, a write to the
timer target register is only allowed if a value hasn't been written yet.
Fixed Donkey Kong Country 1 and Earth Worm Jim 1 & 2.
- Attack rate of 0ms changed from 1ms back to 0ms because of a group of ROMs
that change from attack mode to decay mode in real-time. Will change back
when I've added better SPC700 CPU and sound generation sync code.
- Added support for ROMs set a new sound timer value while the timer is
enabled (EWJ 1 & 2).
- Added support for ROMs that read the sound envelope height (MK1, MK2, etc).
- ROMs writing to the H-DMA enable register during visible scan-lines were
restarting H-DMA for that frame causing random screen effect corruption.
- Echo feedback seems to be after the FIR filter, not before as a diagram I've
seen suggests.
- Sound pitch modulation added.
- Memory access routines changed to pass a single 24-bit address rather than
the previous separate 8-bit bank and 16-bit address parameters.
0.3
- Updates to A-Bus address during a frame must not update H-DMA address.
Fixes Actraiser 2 and Pacman 2.
- Removed sound volume mangling - with echo support enabled it doesn't seem to
be required.
- Attack rate of 0ms changed to 1ms to help prevent click sound with sudden
start of a sample playing.
- Sample caching of samples that looped using part of the original sample
created a click on the sound output. Caching disabled for the moment. Would
require 512K of cache RAM to fix sample caching.
- Colour addition/subtraction support added - but still a little buggy in
places and very slow.
- 16-bit colour support added.
- Sustain sound volume was not being set if a sample using ADSR was started
with both the attack rate and decay rate set to zero - resulted in missing
sound samples on with some games.
- Sound echo support added.
- Sound channel mixing code was not completely clearing a channel's sound
buffer when a channel finished playing a sample.
- Sound mixing code rewritten to use one buffer, rather than writing each
channel into a separate buffer then combining them into one buffer.
- Memory access routines rewritten to use an 8K block lookup table rather than
dedicated code for each ROM memory map - it was getting difficult to support
the new types of SNES ROM memory maps becoming apparent.
- Sound sample decoding wasn't decoding sound samples correctly if a
previously cached sample was only partially overwritten by the ROM as
opposed to being completely replaced.
- Sound sample decoding wasn't clipping generated sample values correctly.
- Changed H-DMA to start in the current frame only if enable register is
written to during v-blank, h-blank or while the screen is blanked.
- The SPC700 seems to start executing instructions before the 65c816 -
shorter reset pulse? (NO - forgot the SPC700 executes instructions while DMA
is taking place).
- ROMs that reset the H-IRQ position so another IRQ would be triggered on the
same scan-line where not supported - Super Off-Road: The Baj needs it.
- $4212 bit 7 needs to go high at the end of h-blank at line 224 not at the
start of h-blank - Bubsy needs it.
- Sample decoding routine could write to memory outside sample cache area if
address of block to decode was greater than $0x10000 - 9.
- Walking mario can be seen on map screen of MarioWorld - needed sprite
priority rotation working. ROM sets bit 7 of $2103 then sets rotation in
$2102. Reset rotation at start of v-blank not at end.
0.24
- Fixed reading of DMA register values - now Ms Pacman works.
- Saved sprite memory address being restored on the wrong scan-line - caused
corrupt sprites on at least one game (GANBARE GOEMON 2).
- Screen colour palette not being updated if ROM only wrote to low byte of
palette register.
- Possible memory corruption fixed if a ROM tried to write to an invalid
sprite address via PPU registers.
- X11 port support quick load and save by pressing function keys to load or
shift + function keys to save.
0.23
- Added option to disable graphic window effects - T2: The Arcade Game doesn't
seem to like them.
- Mode 7 "outside screen area" register interpretation fixed - now the
Actraiser map screen looks a lot better.
- Old DMA code hack for Battle Toads: Double Dragon removed as it was no
longer required and it was causing problems for Ys III.
- Lowered max volume level of 16-bit sound mixing code to help with sound
clipping problems is lots of SNES sound channels are playing.
0.22
- Crash bug fixed in mode 7 graphics windows code
0.21
- Fixed a noise channel volume bug - noise waveform was getting clipped.
- Fixed 24bit X Window System server support on the Solaris port.
- Sprites in priority level 1 on mode 7 were being drawn incorrectly behind
graphics screen.
- BG 3 priority 1 tiles sometimes not drawn dependent on the $2105 bit 3
setting.
- Added graphic window support the tile redraw code.
- Added mosaic support to tile redraw code.
- Tile redraw code was drawing one line too many on screen-splits.
- Tile-based redraw code made more intelligent about when a background should
be displayed or not.
- Added wrap within bank support to large DMAs just to support Rock 'n' Roll
racing.
0.20
- DMA routines added lots of special cases and removed most calls to GetByte,
using a pointer instead.
- Multiple using PPU registers is now only computed when first byte of result
is actually read.
- Sound enabled by default if compiled without DEBUGGER defined.
- Tile redraw method made the default.
- Fixed CPU_SHUTDOWN so SPC700 continues to execute even if main CPU is
"skipping" cycles waiting for an event to happen.
- More command line options added.
- Default cycles-per-scan-line to execute lowered to 90% from 100%.
- +/- keys now work even if auto-frame rate adjust was enabled.
- SPC700 emulation partially rewritten in assembler.
- Asm 65c816 code change to use same speed up techniques as the C++ code.
- Minor speed tweaks to the sound decoding and mixing code.
- C++ SPC700 emulation changed to use same method as 65c816 emulation for
computing and storing emulated CPU flags.
- Mode 7 code rewritten and several scrolling offset bugs fixed.
- Lo-ROM S-RAM memory map bug fixed - now Uniracers works.
- Multiple speed ups and changes to the tile and line-based redraw code.
- Tile and line redraw code changed to cache converted tiles between frames.
- Variable cycle length timing made compile-tile switchable.
- C++ 65c816 emulation changed to use several opcode jump tables to avoid
a register size comparison test on most emulated instructions.
- C++ 65c816 emulation changed how is computes and stores emulated CPU flags.
- Fixed high frequency sound playback bug - the sample rate calculation was
blowing the range of an unsigned long.
- Fixed V-RAM reading so DKC3, Addams Family, Aladdin and Pacman all work.
- Fixed sound code so ROMs can change from ADSR mode to decrease mode - fixes
lots of ROMs.
0.12 released
- Added dynamic speed regulation.
- TCALL vector calculation change from n to 15 - n.
- Fixed crash bug if ROM writes to sound DSP register numbers greater than
127.
- Fixed DOS memory locked for interrupt code.
- Added long name versions of command line switches.
- Added command line switch for SPC700_SHUTDOWN code and WAI cycle skipping
code.
0.1 released
- All DOS memory is now locked from being swapped.
- Fixed DOS port keyboard polling code - could get confused if a keyboard
interrupt happened while keys were being checked.
- SPC700 ADC instruction never cleared Overflow or Carry flags!
- Changed selection of playback speeds for Solaris port.
- Sample caching code was broken - cached samples were never used.
- Added code speed ups for ROMs that use a lot of DMA to VRAM.
- More cpu code asm speed up.
- Fixed 16x16 size tiles on tile-based redraw code.
- Fixed sound gain-mode increase and decrease volume envelopes.
- Added code to support ROMs that reuse sprites in the same frame.
- Fixed processing of negative volume levels.
- Fixed SPC700 EOR1 instruction.
- Added SPC700 shutdown code to stop executing SPC700 instructions if in
a tight loop waiting for a timer or for the 65C816 to respond.
- DOS playback rate was being forced to 16KHz by Allegro - fixed.
- Fixed bug in SPC700 MOV1 C,bit, address.
- Fixed a off-by-one loop sample pointer bug in MixSamples.
- Added command line flags for cached-tile based drawing and sub-screen
background layers priority swapping.
- NOPE, got encoding of the OR1/EOR1,AND1 range of correct originally -
got duff information from an "SPC700" programmer.
- More SPC700 fixes: got the encoding of the OR1/EOR1,AND1 range of
instructions wrong - I guessed wrong originally.
- Sample looping bug fix on mono sound mixing code.
- Sound pitch value no-longer clipped to 14 bits - apparently FF3 needs this.
- Followed Paradox's suggestion and changed graphics code to place sub-screen
background layers below main-screen background layers. Helps lots of games
that use sub-screen addition/subtraction - now you don't have to toggle
background layers on and off so often just to see hidden text, characters,
or maps, etc. Made it switchable.
Acts as a good intermediate solution until sub-screen addition/subtraction
is actually implemented.
- Modified sound skipper code to return random values when ROM is stuck
waiting for the SPC700 CPU to respond - helps several ROMs that previously
don't work with the currently selection of APU skippers.
- Improved sound mixing code so volume is not attenuated so much, giving
better results on 8bit sound cards.
- Changed the frequency at which the joystick polling routine is called - now
called every-other frame rather than every 3rd frame.
- Recompiled Linux and DOS ports with the Pentium optimising version of gcc -
gives a few percent speed increase.
- Changed V-RAM increment count from 64 to 128 - apparently Final Fantasy 3
needs this as well.
- Fixed sprite priority bug with Mode 7 - apparently Final Fantasy 3 needs
this.
- Fixed a screen clipping problem with the S-VGA mode.
- Fixed bug that had crept in with -m 2 S-VGA mode (Linux version).
- Fixed S-VGA Linux version with sound enabled.
- The SPC700 ADC (X),(Y) instruction was broken - with all these SPC700 fixes
now many more ROMs work with sound enabled.
- The SPC700 Pop PSW instruction was not resetting the direct page location.
- The SPC700 instruction MOV A,[DP+X] was incorrectly doing a MOV A,DP+X.
- Got the SPC700 SETx and CLRx instruction encoding swapped around.
- Fixed #define problem that was stopping DOS snapshot saving from working.
0.72 released
- Fixed the DOS filename handling - old Unix code was screwing up with ROM
filenames that contained backslashes (\) - the ROM would load but S-RAM
loading and saving would fail and the default filename for snapshots
wouldn't work.
- This time really fixed Allegro library keyboard handling (DOS port); it
was missing key some presses/releases (was stopping Chrono Trigger
Left + Right + A button combo from working).
- Added code to automatically remove headers off S-RAM save files with
512 byte headers.
- 32Mbit ROMs in interleaved format are now automatically detected and
converted.
- Added -ss 3 sound skip method support to the asm version - now NBA Live '96
works again.
- Added support for multi-part ROM images.
0.71 released
- Made libgz.so statically linked (again) on Linux port - sorry.
- Made writing to $4200 also clear any pending IRQs. This finally allows
Battle Toads: Double Dragon, Spawn and Sieken 3 all the work with the same
IRQ logic (but Sieken 3 still gets stuck in sound download code).
- Fixed a H-DMA wobble bug - some frames could randomly miss a line of
H-DMA causing the F-Zero screen to wobble, and slight text character
corruption on games like DKC3.
- Interleaved format ROM images are now swapped in-place, without the need
for a temp 4Mb buffer (saves lots of disk swapping on a 16Mb Windows 95
machine).
0.7 released
- Fixed Allegro library keyboard handling (DOS port); it was missing key
some presses/releases.
- DOS port had a different MAX_PATH value which moved the location of the
SRAM size variable when using the asm CPU emulation core. This, in turn,
caused the SRAM emulation to fail on the DOS port. Donkey Kong County 2 & 3
were reporting a ROM copier was connected to the SNES and refused to run.
- Fixed assembler version of XCE - it was always leaving the carry flag
clear - caused Killer Instinct and Super Punchout to think a ROM
copier was fitted to the SNES and they all refused to run.
- Fixed assembler versions of MVN/MVP - they weren't setting the data bank
register to the destination bank of the instruction.
- Fixed joystick detection on MS-DOS port - a single 2 or 4 button joystick in
port 1 was being ignored if a second joystick was not present in port 2.
- Fixed an uninitialised variable in graphics code - was causing random
missing scan lines on Mode 7 screens.
- Joysticks now scanned every 3rd frame (joystick scanning is slow in the PC).
- Double-whoops, Metriod 3 had stopped working in v0.6 - fixed it
(memory map bug).
- Made bit 6 of $4211 set if v-counter == v-timer-position.
- Made reading of $4200 read $4212 instead.
- Adjusted DMA timing to always access ROM memory at slow speed - this seems
to fix Battle Toads.
- Added code to automatically clear pending IRQs when the horizontal line
is no longer equal to the horizontal timer line - this fixes Seiken 3, it
now just gets stuck in the sound CPU wait code - oh well.
- Moved NMI back to its original pre-0.65 behaviour, now Puzzle Bobble works.
- More graphics speed ups - the code to render background tiles with their
priority bits set is only called if there are actual priority-bit tiles.
- Changed default frame skip rate from 1 to 2 - its seems most people don't
bother to read the docs, so I thought I'll help them out a bit!
- Speeded up Mode 7 graphics on games like F-Zero that rewrite the matrix
registers on each scan line using H-DMA.
- Reorganised the graphics code and did a slight speed up - graphics code
will be the next thing to rewrite in assembler.
- Rewrote CPU core in assembler for Intel platforms - gives a very noticeable
speed increase.
- Fixed several problems with the APU sound CPU emulation - its now getting
stable enough to try and implement sound.
- Fixed bug that caused 1 byte of S-RAM to be emulated when ROM didn't
expect any - it was enough to stop Street Fighter 2 and others from
working - thanks Lord ESNES.
- The TXS and TCS instructions shouldn't set the Z and N flags.
- Looks like MVP/MVN instructions should ignore accumulator size - change
code to always use all 16 bits and exit with accumulator set to 0xffff.
- Whoops, accidently left some test code in which was causing the V-BLANK
flag, bit 8 in register $4212, to be miss-calculated.
- Fixed palette in mode 0.
- Speeded up graphics drawing a little by skipping groups of 4 pixels that
were all transparent.
0.65 released
- S-VGA and MS-DOS ports now have a VGA mode command line flag.
- Improved the fading code - should be much more smooth now.
- Fixed second joy-pad support and re-mapped keys and joysticks to actually
make a match between what my docs said and a real SNES (SNES docs I'd
seen were wrong!).
- Fixed a bug in Relative Long CPU addressing mode.
- Ported Snes96 to MS-DOS.
- Snapshot loading and saving no longer uses external gzip binary.
- Added support for registers at $21c2 and $21c3.
- Made reading the software latch for the horizontal and vertical counters also
clear any pending IRQ.
- Added sprite priority rotation.
- Rewrote parts of the graphics routines to fix a sprite-to-sprite priority
bug.
- NMI flag changed again - now back to being reset by reading $4210 but
actual NMI is delayed.
- Made mode 7 background colour 0 transparent - this fixed several sprite
priority problems a few games where having.
- Finally worked out how sprite "Object Name Select" works and emulated it -
this fixes many (if not all) of the corrupted sprites some games
experienced.
- Delayed NMI activation for one instruction to give time for loops that
wait for bit 7 of $4210 to go high.
- Special-cased line count of 128 on H-DMA to mean repeat previous data with
a line count of 128 and not just terminate H-DMA on that channel.
- APU sound CPU emulation added - just need to debug the thing.
- Fixed Overflow flag setting in ADC and SBC instructions - it was never
being set.
- Rewrote how CPU instructions are fetched and how values are pushed and pulled
from the stack - it gave a very large increase in emulation speed.
- H-DMA was being started one scan-line too late.
- Added CG-RAM reading support.
- Added "Full Graphic" V-RAM reading.
- Speeded up C version of CPU emulation quite a bit - could speed it up a
little more before rewriting in assembler.
- Fixed bugs in 16x16 tile drawing on 2bit and 8bit deep screens.
0.6 released
- Speeded up 16x16 tile background rendering by removing a temp tile buffer
it was using. The speed up also fixed a vertical scroll bug.
- Fixed slight window clipping on 16x16 tile backgrounds.
- Added automatic PAL/NTSC mode switching.
- Fixed background and sprites so only visible if on main-screen or
on sub-screen under correct circumstance.
- Fixed lockup bug in DMA.
- Stopped NMI flag from being reset by reading $4210 - was causing a couple
of games to get stuck.
- Whoops, got horizontal and vertical Mode 7 flip bits around the wrong way!
- Fixed MIT shared memory pixmap support for X11 version (it was always turned
off).
- Fixed minor bug - first sprite in priority group was drawn twice. Didn't
cause any visual bugs, it just slowed down redrawing a little.
- Fixed DMA bug - transfer byte count should be 0 after DMA has finished.
- Fixed a scaling bug if width < height.
- Interleaved ROM image support added.
- 16bit and 24bit X11 server support added - with scaling.
- Added window scaling on X11 version.
- Partial clip windows added - the only window overlap option implemented at
the moment is OR, it seems it good enough for all the ROMs I've tested
it with.
- Partial Mosaic effect added (pixels only growing vertically).
- Missing Mode 7 "outside screen area" option added.
- Fixed mode 7 screen wrap "outside screen area" option.
- Used new event processing to finally fix H-IRQ so it triggers at the
correct position on the scan line.
- New event processing added.
- Linux version now statically links libgz.so (sorry).
0.5 released
- Linux S-VGA version changed from using a 320x240 ModeX screen (slow) to a
256x256 chunky screen (faster) - thanks to Phillip Ezolt (pe28+@andrew.cmu.edu)
for information on how to do this.
- Mode 7 screen flipping added.
- Included Snes97's CPU emulation code into Snes96. Didn't fix any bugs but
slowed down the emulation some what and I couldn't compile it optimised
because it was so large - so I removed it again.
- Added a few extra features available via the keyboard.
- Fixed a H-DMA transfer mode - bad documentation.
- Fixed H-DMA indirect addressing (it was using the wrong CPU memory bank).
- The Linux slow down bug is my crappy laptop enabling battery saving features !
- Changed graphics code to perform true line-by-line screen updates.
- Fixed sprite drawing bugs.
- Ported Snes97's graphics code to Snes96.
- Fixed memory map for HiROM save RAM area.
- Fixed HiROM memory map - now Killer Instinct and Donkey Kong County work !
- OK the slow down bug is just actually my laptop trying to save battery
power by slowing the CPU clock!
- The Linux slow down bug shows itself on DOS emulators running under DOSEMU
so it must be a kernel problem (or feature).
- Fixed H-DMA (again) to be complete emulation - all I need now is line-by-line
screen update...
- Fixed DMA to not copy too many bytes if byte count was not a multiple of
the transfer mode quantity (caused corruption on Super Mario World map screen).
- Changed mapping of keyboard to joy-pad buttons and added additional
direction keys for joy-pad one so player one's right hand doesn't have to
obscure player two's keyboard joy-pad buttons.
- Changed joystick button layout to match SNES if using a 6 button joy-pad.
- Changed snapshot format so I can easily use libgz on Linux.
- Added few speed up tweaks that will be lost again when I add line-by-line
screen update.
- First visible scan-line changed from 8 to 1 to match with new docs.
- New SNES information source found; fixed partial H-DMA emulation to include
indirect addressing support.
- Snapshot files are now compressed.
- Compressed ROM images now supported on Linux.
- Snapshot loading and saving added.
- Joystick support for Linux added. One 2, 4 or 6 button joystick, or two 2
button joysticks supported (PC hardware limitation).
- SVGA full screen support added for Linux. Still has the X11 slow down bug so
can't blame the X11 server any more! Must be a kernel bug or a very odd
emulator bug.
- Added emulation of two joy-pads on the PC/Sun keyboard.
- Removed -i command line flag as it is no longer used. -h value range has also
changed: now 1 - 100 (percentage).
- Actuate cycle counting rather than instruction counting now added including
fast and slow ROM timing - should give much better timing information when
line-by-line screen update added.
- Bug fixed old-style joy-pad access used by some ROMs - Mario All Stars still
gives problems if enabled and I don't know why; but at least Super Bomberman
now works !
- Looks like if both horizontal and vertical IRQ are enabled then IRQ should
only be triggered once per frame and not once per scan line - looking at the
IRQ handler of a couple of ROMs seems to confirm this.
- Added initial cycle counting - not accurate enough for some ROMs though.
- Finally worked out how the odd VRAM address increments should work but only
found one ROM, so far, that actually uses it.
- Debugged the odd slow down problem with the Linux port - it seems to be a
bug in the X Window System server - starve the X server of keyboard presses
or mouse clicks or movement and the X server slows down, slowing down the
emulator with it !
0.4 released
- Fixed sprite vertical clipping at top of screen.
- No need to invert the Mode 7 transformation matrix before use - the
ROM coder already had to!
- Fixed Mode 7 scrolling offset when using special effects.
- Added Mode 7 rotation, enlargement and reduction emulation.
- DMA shouldn't zero the byte count value after a DMA has completed.
- Added DMA reading (Addams Family was using it)
- Fixed V-RAM read function - returned data should lag behind the V-RAM
address by one byte/word.
- Added mode 7 graphics only.
0.3 released
- Speeded up the main CPU loop a bit.
- Add more command line options:
-f <frame skip> (default 1)
-i <no instructions between polling X> (default 32768)
-h <number instructions per scan line> (default 45, some games allow a lower
setting resulting in a increased
emulated frame rate)
-t enable CPU tracing
-ss <sound CPU skip wait method> (default 0, more methods to be added)
-H disable H-DMA emulation
-F Force Hi-ROM memory map
- Modified planar to chunky conversion to use look up tables.
- But now Mario All Stars won't start. Made emulation of $4016 optional with
-o command line switch.
- Thanks to Carlos (calb) of ESNES fame, I've added correct $4016 & $4017
joy-pad register processing - now several more ROMs will start once a
button is pressed and can be controlled.
- DMA wasn't updating DMA registers with the final CPU address used after the
DMA had completed (caused sprite and background corruption with some ROMs).
Still suspect another DMA side effect isn't being emulated correctly though.
- Fixed setting of CPU overflow flag in ADC and SBC instructions in decimal
mode.
- Fixed MVP/MVN CPU instructions to leave X and Y values correct at end of
loop - several more ROMs now work. Still don't know if MVP/MVN instructions
should ignore the accumulator size flag or not.
- Rewrote background drawing code - gives a large increase in speed.
- Flag to only update X Windows colour palette when necessary was missing a
case - caused some ROMs to start with a black screen.
- Code to only update background tiles when changed wasn't working so I
disabled it.
- CPU WAI instruction needed to trigger on hardware IRQ even when interrupt
enable flag was false.
- DMA was not transferring 65536 bytes when byte count was 0.
- Fixed matrix 16bit x 8bit multiplication (old debug code was causing junk
value to be returned).
- Fixed Makefile so version.h header file change recompiles file that shows
version number in window title.
- Added more reporting of used but unimplemented missing hardware features to
debug command.
- New ROM loading code from Jerremy included, can now cope with ROM images
with no 512 byte header.
- Speeded up emulated memory access a little bit.
0.2 released
- Added matrix 16bit x 8bit multiplication for Super Off-Road Racer.
- Added initial H-DMA emulation - visual effects using it will not be seen
correctly until screen is updated line-by-line rather than the whole screen
at end-of-frame.
- Fixed horizontal sprite clipping (vertical clipping still has a problem).
- Integrated large sprite bug fixes and new background drawing code from
Jerremy.
- Fixed large size per-sprite flag; always stayed true after sprite size was
changed to large.
- Rewrote the planar to chunky pixel conversion routines (still need more
work).
- Made registers $4016 & $4017 always return $ff - lots of ROMs that previously
wouldn't go beyond the title screen thought old-style joy-pads were
connected and were waiting for the user to press a button on them.
- Frame skip rate now set to 1 instead of 5 on my P166 laptop!
- Fixed NMI v-blank flag being incorrect set, caused some ROMs to lock.
- X keyboard autorepeat now switched off when emulator has keyboard focus.
- Added number key options to toggle backgrounds 1 to 4 and objs (sprites) on
and off.
- Fixed sprite clipping problems at edge of left hand side of screen.
- Corrected Hi-ROM memory map (I think) (no I didn't)
- Fixed most of the sprite-to-sprite priority problems.
- Added sprite debug command, 'S'.
- Added a debug command to show what missing hardware features a ROM was using.
- Added horizontal and vertical beam position IRQ - horizontal always triggers
at start of line at the moment.
- Fixed SBC instruction to set carry flag the correct way around.
Initial release 0.1
- Ported Windows 95 version of Snes96 to Linux on a PC and Solaris on a
SparcStation.
- Corrected work RAM memory map.
/tags/initial/snes9x/soundux.cpp
New file
0,0 → 1,2642
/*******************************************************************************
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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
 
#ifdef PSP
extern "C" {
void debug_log( const char* message );
void debug_int( const char* message, int value );
};
static int s_iSoundMulRate = 0;
 
#define PSP_PLAYBACK_RATE 44100
#endif // PSP
 
#define CLIP16(v) \
if ((v) < -32768) \
(v) = -32768; \
else \
if ((v) > 32767) \
(v) = 32767
 
#define CLIP16_latch(v,l) \
if ((v) < -32768) \
{ (v) = -32768; (l)++; }\
else \
if ((v) > 32767) \
{ (v) = 32767; (l)++; }
 
#define CLIP24(v) \
if ((v) < -8388608) \
(v) = -8388608; \
else \
if ((v) > 8388607) \
(v) = 8388607
 
#define CLIP8(v) \
if ((v) < -128) \
(v) = -128; \
else \
if ((v) > 127) \
(v) = 127
 
#include "snes9x.h"
#include "soundux.h"
#include "apu.h"
#include "memmap.h"
#include "cpuexec.h"
 
extern int Echo [24000];
extern int DummyEchoBuffer [SOUND_BUFFER_SIZE];
extern int MixBuffer [SOUND_BUFFER_SIZE];
extern int EchoBuffer [SOUND_BUFFER_SIZE];
extern int FilterTaps [8];
extern unsigned long Z;
extern int Loop [16];
 
extern long FilterValues[4][2];
extern int NoiseFreq [32];
 
#undef ABS
#define ABS(a) ((a) < 0 ? -(a) : (a))
 
#define FIXED_POINT 0x10000UL
#define FIXED_POINT_REMAINDER 0xffffUL
#define FIXED_POINT_SHIFT 16
 
#define VOL_DIV8 0x8000
#define VOL_DIV16 0x0080
#define ENVX_SHIFT 24
 
extern "C" void DecodeBlockAsm (int8 *, int16 *, int32 *, int32 *);
extern "C" void DecodeBlockAsm2 (int8 *, int16 *, int32 *, int32 *);
 
// F is channel's current frequency and M is the 16-bit modulation waveform
// from the previous channel multiplied by the current envelope volume level.
#define PITCH_MOD(F,M) ((F) * ((((unsigned long) (M)) + 0x800000) >> 16) >> 7)
//#define PITCH_MOD(F,M) ((F) * ((((M) & 0x7fffff) >> 14) + 1) >> 8)
 
#define LAST_SAMPLE 0xffffff
#define JUST_PLAYED_LAST_SAMPLE(c) ((c)->sample_pointer >= LAST_SAMPLE)
 
STATIC inline uint8 *S9xGetSampleAddress (int sample_number)
{
uint32 addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff);
return (IAPU.RAM + addr);
}
 
void S9xAPUSetEndOfSample (int i, Channel *ch)
{
ch->state = SOUND_SILENT;
ch->mode = MODE_NONE;
APU.DSP [APU_ENDX] |= 1 << i;
APU.DSP [APU_KON] &= ~(1 << i);
APU.DSP [APU_KOFF] &= ~(1 << i);
APU.KeyedChannels &= ~(1 << i);
}
#ifdef __DJGPP
END_OF_FUNCTION (S9xAPUSetEndOfSample)
#endif
 
#ifndef OPTI
void S9xAPUSetEndX (int ch)
{
APU.DSP [APU_ENDX] |= 1 << ch;
}
#ifdef __DJGPP
END_OF_FUNCTION (S9xAPUSetEndX)
#endif
#endif // OPTI
 
#ifdef OPTI
inline void S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target)
#else
void S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target)
#endif // OPTI
{
ch->envx_target = target;
if (rate == ~0UL)
{
ch->direction = 0;
rate = 0;
}
else
ch->direction = direction;
static int steps [] =
{
// 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238
0, 64, 619, 619, 128, 1, 64, 55, 64, 619
};
#ifdef PSP
if (rate == 0) {
ch->erate = 0;
} else {
ch->erate = (unsigned long)
((((int) FIXED_POINT * steps [ch->state]) << s_iSoundMulRate ) / (rate * (PSP_PLAYBACK_RATE / 1000)));
}
#else
if (rate == 0 || so.playback_rate == 0)
ch->erate = 0;
else
{
ch->erate = (unsigned long)
(((int64) FIXED_POINT * 1000 * steps [ch->state]) /
(rate * so.playback_rate));
}
#endif // PSP
}
 
#ifdef __DJGPP
END_OF_FUNCTION(S9xSetEnvRate);
#endif
 
void S9xSetEnvelopeRate (int channel, unsigned long rate, int direction,
int target)
{
S9xSetEnvRate (&SoundData.channels [channel], rate, direction, target);
}
 
#ifdef __DJGPP
END_OF_FUNCTION(S9xSetEnvelopeRate);
#endif
 
void S9xSetSoundVolume (int channel, short volume_left, short volume_right)
{
Channel *ch = &SoundData.channels[channel];
#ifndef OPTI
if (!so.stereo)
volume_left = (ABS(volume_right) + ABS(volume_left)) / 2;
#endif // OPTI
ch->volume_left = volume_left;
ch->volume_right = volume_right;
//ch-> left_vol_level = (ch->envx * volume_left) / 128;
//ch->right_vol_level = (ch->envx * volume_right) / 128;
ch-> left_vol_level = ((ch->envx * volume_left) >> 7);
ch->right_vol_level = ((ch->envx * volume_right) >> 7);
}
 
void S9xSetMasterVolume (short volume_left, short volume_right)
{
if (Settings.DisableMasterVolume || SNESGameFixes.EchoOnlyOutput)
{
SoundData.master_volume_left = 127;
SoundData.master_volume_right = 127;
SoundData.master_volume [0] = SoundData.master_volume [1] = 127;
}
else
{
#ifndef OPTI
if (!so.stereo)
volume_left = (ABS (volume_right) + ABS (volume_left)) / 2;
#endif // OPTI
SoundData.master_volume_left = volume_left;
SoundData.master_volume_right = volume_right;
#ifdef OPTI
SoundData.master_volume [0] = volume_left;
SoundData.master_volume [1] = volume_right;
#else
SoundData.master_volume [Settings.ReverseStereo] = volume_left;
SoundData.master_volume [1 ^ Settings.ReverseStereo] = volume_right;
#endif // OPTI
}
}
 
void S9xSetEchoVolume (short volume_left, short volume_right)
{
#ifndef OPTI
if (!so.stereo)
volume_left = (ABS (volume_right) + ABS (volume_left)) / 2;
#endif // OPTI
SoundData.echo_volume_left = volume_left;
SoundData.echo_volume_right = volume_right;
#ifdef OPTI
SoundData.echo_volume [0] = volume_left;
SoundData.echo_volume [1] = volume_right;
#else
SoundData.echo_volume [Settings.ReverseStereo] = volume_left;
SoundData.echo_volume [1 ^ Settings.ReverseStereo] = volume_right;
#endif // OPTI
}
 
void S9xSetEchoEnable (uint8 byte)
{
SoundData.echo_channel_enable = byte;
if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho)
byte = 0;
if (byte && !SoundData.echo_enable)
{
memset (Echo, 0, sizeof (Echo));
memset (Loop, 0, sizeof (Loop));
}
SoundData.echo_enable = byte;
for (int i = 0; i < 8; i++)
{
if (byte & (1 << i))
SoundData.channels [i].echo_buf_ptr = EchoBuffer;
else
SoundData.channels [i].echo_buf_ptr = DummyEchoBuffer;
}
}
 
void S9xSetEchoFeedback (int feedback)
{
CLIP8(feedback);
SoundData.echo_feedback = feedback;
}
 
void S9xSetEchoDelay (int delay)
{
#ifdef PSP
// SoundData.echo_buffer_size = (((delay << 9 )* PSP_PLAYBACK_RATE) >> 15) ;
SoundData.echo_buffer_size = ((512 * delay * PSP_PLAYBACK_RATE) / 32000) ;
SoundData.echo_buffer_size >>= s_iSoundMulRate;
#else
SoundData.echo_buffer_size = (512 * delay * so.playback_rate) / 32000;
#endif // PSP
#ifndef OPTI
if (so.stereo)
#endif // OPTI
SoundData.echo_buffer_size <<= 1;
if (SoundData.echo_buffer_size)
SoundData.echo_ptr %= SoundData.echo_buffer_size;
else
SoundData.echo_ptr = 0;
S9xSetEchoEnable (APU.DSP [APU_EON]);
}
 
void S9xSetEchoWriteEnable (uint8 byte)
{
SoundData.echo_write_enabled = byte;
S9xSetEchoDelay (APU.DSP [APU_EDL] & 15);
}
 
void S9xSetFrequencyModulationEnable (uint8 byte)
{
SoundData.pitch_mod = byte & ~1;
}
 
void S9xSetSoundKeyOff (int channel)
{
Channel *ch = &SoundData.channels[channel];
if (ch->state != SOUND_SILENT)
{
ch->state = SOUND_RELEASE;
ch->mode = MODE_RELEASE;
S9xSetEnvRate (ch, 8, -1, 0);
}
}
 
void S9xFixSoundAfterSnapshotLoad ()
{
SoundData.echo_write_enabled = !(APU.DSP [APU_FLG] & 0x20);
SoundData.echo_channel_enable = APU.DSP [APU_EON];
S9xSetEchoDelay (APU.DSP [APU_EDL] & 0xf);
S9xSetEchoFeedback ((signed char) APU.DSP [APU_EFB]);
S9xSetFilterCoefficient (0, (signed char) APU.DSP [APU_C0]);
S9xSetFilterCoefficient (1, (signed char) APU.DSP [APU_C1]);
S9xSetFilterCoefficient (2, (signed char) APU.DSP [APU_C2]);
S9xSetFilterCoefficient (3, (signed char) APU.DSP [APU_C3]);
S9xSetFilterCoefficient (4, (signed char) APU.DSP [APU_C4]);
S9xSetFilterCoefficient (5, (signed char) APU.DSP [APU_C5]);
S9xSetFilterCoefficient (6, (signed char) APU.DSP [APU_C6]);
S9xSetFilterCoefficient (7, (signed char) APU.DSP [APU_C7]);
for (int i = 0; i < 8; i++)
{
SoundData.channels[i].needs_decode = TRUE;
S9xSetSoundFrequency (i, SoundData.channels[i].hertz);
SoundData.channels [i].envxx = SoundData.channels [i].envx << ENVX_SHIFT;
SoundData.channels [i].next_sample = 0;
#ifndef OPTI
SoundData.channels [i].interpolate = 0;
#endif // OPTI
SoundData.channels [i].previous [0] = (int32) SoundData.channels [i].previous16 [0];
SoundData.channels [i].previous [1] = (int32) SoundData.channels [i].previous16 [1];
}
#ifdef OPTI
SoundData.master_volume [0] = SoundData.master_volume_left;
SoundData.master_volume [1] = SoundData.master_volume_right;
SoundData.echo_volume [0] = SoundData.echo_volume_left;
SoundData.echo_volume [1] = SoundData.echo_volume_right;
#else
SoundData.master_volume [Settings.ReverseStereo] = SoundData.master_volume_left;
SoundData.master_volume [1 ^ Settings.ReverseStereo] = SoundData.master_volume_right;
SoundData.echo_volume [Settings.ReverseStereo] = SoundData.echo_volume_left;
SoundData.echo_volume [1 ^ Settings.ReverseStereo] = SoundData.echo_volume_right;
#endif // OPTI
IAPU.Scanline = 0;
}
 
void S9xSetFilterCoefficient (int tap, int value)
{
FilterTaps [tap & 7] = value;
SoundData.no_filter = (FilterTaps [0] == 127 || FilterTaps [0] == 0) &&
FilterTaps [1] == 0 &&
FilterTaps [2] == 0 &&
FilterTaps [3] == 0 &&
FilterTaps [4] == 0 &&
FilterTaps [5] == 0 &&
FilterTaps [6] == 0 &&
FilterTaps [7] == 0;
}
 
void S9xSetSoundADSR (int channel, int attack_rate, int decay_rate,
int sustain_rate, int sustain_level, int release_rate)
{
SoundData.channels[channel].attack_rate = attack_rate;
SoundData.channels[channel].decay_rate = decay_rate;
SoundData.channels[channel].sustain_rate = sustain_rate;
SoundData.channels[channel].release_rate = release_rate;
SoundData.channels[channel].sustain_level = sustain_level + 1;
switch (SoundData.channels[channel].state)
{
case SOUND_ATTACK:
S9xSetEnvelopeRate (channel, attack_rate, 1, 127);
break;
case SOUND_DECAY:
S9xSetEnvelopeRate (channel, decay_rate, -1,
(MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3);
break;
case SOUND_SUSTAIN:
S9xSetEnvelopeRate (channel, sustain_rate, -1, 0);
break;
}
}
 
void S9xSetEnvelopeHeight (int channel, int level)
{
Channel *ch = &SoundData.channels[channel];
ch->envx = level;
ch->envxx = level << ENVX_SHIFT;
//ch->left_vol_level = (level * ch->volume_left) / 128;
//ch->right_vol_level = (level * ch->volume_right) / 128;
ch->left_vol_level = ((level * ch->volume_left) >> 7);
ch->right_vol_level = ((level * ch->volume_right) >> 7);
if (ch->envx == 0 && ch->state != SOUND_SILENT && ch->state != SOUND_GAIN)
{
S9xAPUSetEndOfSample (channel, ch);
}
}
 
int S9xGetEnvelopeHeight (int channel)
{
if ((Settings.SoundEnvelopeHeightReading ||
SNESGameFixes.SoundEnvelopeHeightReading2) &&
SoundData.channels[channel].state != SOUND_SILENT &&
SoundData.channels[channel].state != SOUND_GAIN)
{
return (SoundData.channels[channel].envx);
}
//siren fix from XPP
if (SNESGameFixes.SoundEnvelopeHeightReading2 &&
SoundData.channels[channel].state != SOUND_SILENT)
{
return (SoundData.channels[channel].envx);
}
return (0);
}
 
#if 1
void S9xSetSoundSample (int, uint16)
{
}
#else
void S9xSetSoundSample (int channel, uint16 sample_number)
{
register Channel *ch = &SoundData.channels[channel];
if (ch->state != SOUND_SILENT &&
sample_number != ch->sample_number)
{
int keep = ch->state;
ch->state = SOUND_SILENT;
ch->sample_number = sample_number;
ch->loop = FALSE;
ch->needs_decode = TRUE;
ch->last_block = FALSE;
ch->previous [0] = ch->previous[1] = 0;
uint8 *dir = S9xGetSampleAddress (sample_number);
ch->block_pointer = READ_WORD (dir);
ch->sample_pointer = 0;
ch->state = keep;
}
}
#endif
 
void S9xSetSoundFrequency (int channel, int hertz)
{
#ifdef PSP
if (SoundData.channels[channel].type == SOUND_NOISE)
hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f];
SoundData.channels[channel].frequency = (int)
((((int) hertz * (FIXED_POINT / 1000)) << s_iSoundMulRate ) / ((PSP_PLAYBACK_RATE / 980)));
/*
SoundData.channels[channel].frequency = (int)
(((int64) hertz * FIXED_POINT) / PSP_PLAYBACK_RATE);
*/
/*
if (Settings.FixFrequency)
{
SoundData.channels[channel].frequency =
(unsigned long) ((double) SoundData.channels[channel].frequency * 0.980);
}
*/
#else
if (so.playback_rate)
{
if (SoundData.channels[channel].type == SOUND_NOISE)
hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f];
SoundData.channels[channel].frequency = (int)
(((int64) hertz * FIXED_POINT) / so.playback_rate);
if (Settings.FixFrequency)
{
SoundData.channels[channel].frequency =
(unsigned long) ((double) SoundData.channels[channel].frequency * 0.980);
}
}
#endif // PSP
}
 
void S9xSetSoundHertz (int channel, int hertz)
{
SoundData.channels[channel].hertz = hertz;
S9xSetSoundFrequency (channel, hertz);
}
 
void S9xSetSoundType (int channel, int type_of_sound)
{
SoundData.channels[channel].type = type_of_sound;
}
 
bool8 S9xSetSoundMute (bool8 mute)
{
bool8 old = so.mute_sound;
so.mute_sound = mute;
return (old);
}
 
void AltDecodeBlock (Channel *ch)
{
if (ch->block_pointer >= 0x10000 - 9)
{
ch->last_block = TRUE;
ch->loop = FALSE;
ch->block = ch->decoded;
memset ((void *) ch->decoded, 0, sizeof (int16) * 16);
return;
}
signed char *compressed = (signed char *) &IAPU.RAM [ch->block_pointer];
unsigned char filter = *compressed;
if ((ch->last_block = filter & 1))
ch->loop = (filter & 2) != 0;
#if (defined (USE_X86_ASM) && (defined (__i386__) || defined (__i486__) ||\
defined (__i586__) || defined (__WIN32__) || defined (__DJGPP)))
int16 *raw = ch->block = ch->decoded;
if (Settings.AltSampleDecode == 1)
DecodeBlockAsm (compressed, raw, &ch->previous [0], &ch->previous [1]);
else
DecodeBlockAsm2 (compressed, raw, &ch->previous [0], &ch->previous [1]);
#else
int32 out;
unsigned char shift;
signed char sample1, sample2;
unsigned int i;
compressed++;
signed short *raw = ch->block = ch->decoded;
int32 prev0 = ch->previous [0];
int32 prev1 = ch->previous [1];
shift = filter >> 4;
switch ((filter >> 2) & 3)
{
case 0:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
sample2 >>= 4;
sample1 >>= 4;
*raw++ = ((int32) sample1 << shift);
*raw++ = ((int32) sample2 << shift);
}
prev1 = *(raw - 2);
prev0 = *(raw - 1);
break;
case 1:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
sample2 >>= 4;
sample1 >>= 4;
prev0 = (int16) prev0;
*raw++ = prev1 = ((int32) sample1 << shift) + prev0 - (prev0 >> 4);
prev1 = (int16) prev1;
*raw++ = prev0 = ((int32) sample2 << shift) + prev1 - (prev1 >> 4);
}
break;
case 2:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
sample2 >>= 4;
sample1 >>= 4;
out = (sample1 << shift) - prev1 + (prev1 >> 4);
prev1 = (int16) prev0;
prev0 &= ~3;
*raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) -
(prev0 >> 4);
out = (sample2 << shift) - prev1 + (prev1 >> 4);
prev1 = (int16) prev0;
prev0 &= ~3;
*raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) -
(prev0 >> 4);
}
break;
case 3:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
sample2 >>= 4;
sample1 >>= 4;
out = (sample1 << shift);
out = out - prev1 + (prev1 >> 3) + (prev1 >> 4);
prev1 = (int16) prev0;
prev0 &= ~3;
*raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) -
(prev0 >> 4) - (prev1 >> 6);
out = (sample2 << shift);
out = out - prev1 + (prev1 >> 3) + (prev1 >> 4);
prev1 = (int16) prev0;
prev0 &= ~3;
*raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) -
(prev0 >> 4) - (prev1 >> 6);
}
break;
}
ch->previous [0] = prev0;
ch->previous [1] = prev1;
#endif
ch->block_pointer += 9;
}
 
void AltDecodeBlock2 (Channel *ch)
{
#ifndef PSP
int32 out;
unsigned char filter;
unsigned char shift;
signed char sample1, sample2;
unsigned char i;
if (ch->block_pointer > 0x10000 - 9)
{
ch->last_block = TRUE;
ch->loop = FALSE;
ch->block = ch->decoded;
memset ((void *) ch->decoded, 0, sizeof (int16) * 16);
return;
}
signed char *compressed = (signed char *) &IAPU.RAM [ch->block_pointer];
filter = *compressed;
if ((ch->last_block = filter & 1))
ch->loop = (filter & 2) != 0;
compressed++;
signed short *raw = ch->block = ch->decoded;
shift = filter >> 4;
int32 prev0 = ch->previous [0];
int32 prev1 = ch->previous [1];
if(shift > 12)
shift -= 4;
switch ((filter >> 2) & 3)
{
case 0:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
//Sample 2 = Bottom Nibble, Sign Extended.
sample2 >>= 4;
//Sample 1 = Top Nibble, shifted down and Sign Extended.
sample1 >>= 4;
out = (int32)(sample1 << shift);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
out = (int32)(sample2 << shift);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
}
break;
case 1:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
//Sample 2 = Bottom Nibble, Sign Extended.
sample2 >>= 4;
//Sample 1 = Top Nibble, shifted down and Sign Extended.
sample1 >>= 4;
out = (int32)(sample1 << shift);
out += (int32)((double)prev0 * 15/16);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
out = (int32)(sample2 << shift);
out += (int32)((double)prev0 * 15/16);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
}
break;
case 2:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
//Sample 2 = Bottom Nibble, Sign Extended.
sample2 >>= 4;
//Sample 1 = Top Nibble, shifted down and Sign Extended.
sample1 >>= 4;
out = ((sample1 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8;
prev1 = prev0;
prev0 = (int16)out;
*raw++ = (int16)out;
out = ((sample2 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8;
prev1 = prev0;
prev0 = (int16)out;
*raw++ = (int16)out;
}
break;
case 3:
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
//Sample 2 = Bottom Nibble, Sign Extended.
sample2 >>= 4;
//Sample 1 = Top Nibble, shifted down and Sign Extended.
sample1 >>= 4;
out = (int32)(sample1 << shift);
out += (int32)((double)prev0 * 115/64 - (double)prev1 * 13/16);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
out = (int32)(sample2 << shift);
out += (int32)((double)prev0 * 115/64 - (double)prev1 * 13/16);
prev1 = prev0;
prev0 = out;
CLIP16(out);
*raw++ = (int16)out;
}
break;
}
ch->previous [0] = prev0;
ch->previous [1] = prev1;
ch->block_pointer += 9;
#endif // PSP
}
 
void DecodeBlock (Channel *ch)
{
int32 out;
unsigned char filter;
unsigned char shift;
signed char sample1, sample2;
unsigned char i;
bool invalid_header;
if (Settings.AltSampleDecode)
{
if (Settings.AltSampleDecode < 3)
AltDecodeBlock (ch);
else
AltDecodeBlock2 (ch);
return;
}
if (ch->block_pointer > 0x10000 - 9)
{
ch->last_block = TRUE;
ch->loop = FALSE;
ch->block = ch->decoded;
return;
}
signed char *compressed = (signed char *) &IAPU.RAM [ch->block_pointer];
filter = *compressed;
if ((ch->last_block = filter & 1))
ch->loop = (filter & 2) != 0;
compressed++;
signed short *raw = ch->block = ch->decoded;
// Seperate out the header parts used for decoding
 
shift = filter >> 4;
// Header validity check: if range(shift) is over 12, ignore
// all bits of the data for that block except for the sign bit of each
invalid_header = !(shift < 0xD);
 
filter = filter&0x0c;
 
int32 prev0 = ch->previous [0];
int32 prev1 = ch->previous [1];
for (i = 8; i != 0; i--)
{
sample1 = *compressed++;
sample2 = sample1 << 4;
//Sample 2 = Bottom Nibble, Sign Extended.
sample2 >>= 4;
//Sample 1 = Top Nibble, shifted down and Sign Extended.
sample1 >>= 4;
if (invalid_header) { sample1>>=3; sample2>>=3; }
for (int nybblesmp = 0; nybblesmp<2; nybblesmp++){
out=(((nybblesmp) ? sample2 : sample1) << shift);
out >>= 1;
switch(filter)
{
case 0x00:
// Method0 - [Smp]
break;
case 0x04:
// Method1 - [Delta]+[Smp-1](15/16)
out+=(prev0>>1)+((-prev0)>>5);
break;
case 0x08:
// Method2 - [Delta]+[Smp-1](61/32)-[Smp-2](15/16)
out+=(prev0)+((-(prev0 +(prev0>>1)))>>5)-(prev1>>1)+(prev1>>5);
break;
default:
// Method3 - [Delta]+[Smp-1](115/64)-[Smp-2](13/16)
out+=(prev0)+((-(prev0 + (prev0<<2) + (prev0<<3)))>>7)-(prev1>>1)+((prev1+(prev1>>1))>>4);
break;
}
CLIP16(out);
*raw++ = (signed short)(out<<1);
prev1=(signed short)prev0;
prev0=(signed short)(out<<1);
}
}
ch->previous [0] = prev0;
ch->previous [1] = prev1;
ch->block_pointer += 9;
}
 
 
#ifdef OPTI
// 89248
// 89232
// 90268
// 88860
// 88240
// 87888
inline void MixStereo (int sample_count)
{
static int wave[SOUND_BUFFER_SIZE];
static int steps [] = {
// 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238
0, 64, 619, 619, 128, 1, 64, 55, 64, 619
};
int pitch_mod = SoundData.pitch_mod & ~APU.DSP[APU_NON];
for (uint32 J = 0; J < NUM_CHANNELS; J++)
{
int32 VL, VR;
Channel *ch = &SoundData.channels[J];
unsigned long freq0 = ch->frequency;
if (ch->state == SOUND_SILENT)
continue;
bool8 mod = pitch_mod & (1 << J);
if (ch->needs_decode)
{
DecodeBlock(ch);
ch->needs_decode = FALSE;
ch->sample = ch->block[0];
ch->sample_pointer = freq0 >> FIXED_POINT_SHIFT;
if (ch->sample_pointer == 0)
ch->sample_pointer = 1;
if (ch->sample_pointer > SOUND_DECODE_LENGTH)
ch->sample_pointer = SOUND_DECODE_LENGTH - 1;
 
ch->next_sample=ch->block[ch->sample_pointer];
}
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
 
int envx = ch->envx;
int32 envxx = ch->envxx;
for (uint32 I = 0; I < (uint32) sample_count; I += 2)
{
unsigned long freq = freq0;
if (mod)
//freq = PITCH_MOD(freq, wave [I / 2]);
freq = PITCH_MOD(freq, wave [I >> 1]);
ch->env_error += ch->erate;
if (ch->env_error >= FIXED_POINT){
uint32 step = ch->env_error >> FIXED_POINT_SHIFT;
unsigned long rate;
 
switch (ch->state){
case SOUND_ATTACK:
ch->env_error &= FIXED_POINT_REMAINDER;
envx += step << 1;
envxx = envx << ENVX_SHIFT;
if (envx >= 126){
envx = 127;
envxx = 127 << ENVX_SHIFT;
if (ch->sustain_level != 8){
ch->state = SOUND_DECAY;
rate = ch->decay_rate;
ch->envx_target = (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3;
/*
S9xSetEnvRate (ch, ch->decay_rate, -1,
(MAX_ENVELOPE_HEIGHT * ch->sustain_level)
>> 3);
*/
} else {
ch->state = SOUND_SUSTAIN;
rate = ch->sustain_rate;
ch->envx_target = 0;
}
if (rate == ~0UL){
ch->direction = 0;
rate = 0;
} else ch->direction = -1;
if ( rate == 0 ){
ch->erate = 0;
} else {
ch->erate = (unsigned long)
#ifdef PSP
((((int) FIXED_POINT * steps [ch->state]) << s_iSoundMulRate ) / (rate * (PSP_PLAYBACK_RATE / 1000)));
#else
(((int) FIXED_POINT * steps [ch->state]) / (rate * (PSP_PLAYBACK_RATE / 1000)));
#endif // PSP
}
}
break;
case SOUND_DECAY:
while (ch->env_error >= FIXED_POINT){
envxx = (envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
envx = envxx >> ENVX_SHIFT;
if (envx <= ch->envx_target){
if (envx <= 0){
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
ch->state = SOUND_SUSTAIN;
rate = ch->sustain_rate;
ch->envx_target = 0;
if (rate == ~0UL){
ch->direction = 0;
rate = 0;
} else ch->direction = -1;
if ( rate == 0 ){
ch->erate = 0;
} else {
ch->erate = (unsigned long)
#ifdef PSP
((((int) FIXED_POINT * 619) << s_iSoundMulRate ) / (rate * (PSP_PLAYBACK_RATE / 1000)));
#else
(((int) FIXED_POINT * steps [SOUND_SUSTAIN]) / (rate * (PSP_PLAYBACK_RATE / 1000)));
#endif // PSP
}
/*
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
*/
}
break;
case SOUND_SUSTAIN:
while (ch->env_error >= FIXED_POINT){
envxx = (envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
envx = envxx >> ENVX_SHIFT;
if (envx <= 0){
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_RELEASE:
while (ch->env_error >= FIXED_POINT){
//envxx -= (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
envxx -= ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
envx = envxx >> ENVX_SHIFT;
if (envx <= 0){
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_INCREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
envx += step << 1;
envxx = envx << ENVX_SHIFT;
if (envx >= 126){
goto _SOUND_GAIN;
/*
S9xSetEnvRate (ch, 0, -1, 0);
*/
}
break;
case SOUND_INCREASE_BENT_LINE:
//if (envx >= (MAX_ENVELOPE_HEIGHT * 3) / 4){
if (envx >= (MAX_ENVELOPE_HEIGHT * 3) >> 2){
while (ch->env_error >= FIXED_POINT){
//envxx += (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
envxx += ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
envx = envxx >> ENVX_SHIFT;
} else {
ch->env_error &= FIXED_POINT_REMAINDER;
envx += step << 1;
envxx = envx << ENVX_SHIFT;
}
if (envx >= 126){
goto _SOUND_GAIN;
/*
S9xSetEnvRate (ch, 0, -1, 0);
*/
}
break;
case SOUND_DECREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
envx -= step << 1;
envxx = envx << ENVX_SHIFT;
if (envx <= 0){
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_DECREASE_EXPONENTIAL:
while (ch->env_error >= FIXED_POINT){
envxx = (envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
envx = envxx >> ENVX_SHIFT;
if (envx <= 0){
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
_SOUND_GAIN:
envx = 127;
envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_GAIN;
ch->mode = MODE_GAIN;
 
case SOUND_GAIN:
ch->envx_target = 0;
ch->direction = -1;
ch->erate = 0;
/*
S9xSetEnvRate (ch, 0, -1, 0);
*/
break;
}
//ch-> left_vol_level = (envx * ch->volume_left) / 128;
//ch->right_vol_level = (envx * ch->volume_right) / 128;
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
ch-> left_vol_level = ((envx * ch->volume_left) >> 7);
ch->right_vol_level = ((envx * ch->volume_right) >> 7);
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
}
 
ch->count += freq;
if (ch->count >= FIXED_POINT)
{
VL = ch->count >> FIXED_POINT_SHIFT;
ch->sample_pointer += VL;
ch->count &= FIXED_POINT_REMAINDER;
 
ch->sample = ch->next_sample;
if (ch->sample_pointer >= SOUND_DECODE_LENGTH)
{
if (JUST_PLAYED_LAST_SAMPLE(ch))
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
uint8 *dir = &IAPU.RAM[(uint32)((((APU.DSP[APU_DIR] << 8) + (ch->sample_number << 2)) & 0xffff))];
do
{
ch->sample_pointer -= SOUND_DECODE_LENGTH;
if (ch->last_block)
{
if (!ch->loop)
{
ch->sample_pointer = LAST_SAMPLE;
ch->next_sample = ch->sample;
break;
}
else
{
// S9xAPUSetEndX (J);
APU.DSP [APU_ENDX] |= 1 << J;
ch->last_block = FALSE;
// uint8 *dir = S9xGetSampleAddress (ch->sample_number);
ch->block_pointer = READ_WORD(dir + 2);
}
}
DecodeBlock (ch);
} while (ch->sample_pointer >= SOUND_DECODE_LENGTH);
if (!JUST_PLAYED_LAST_SAMPLE (ch))
ch->next_sample = ch->block [ch->sample_pointer];
}
else
ch->next_sample = ch->block [ch->sample_pointer];
if (ch->type != SOUND_SAMPLE)
{
for (;VL > 0; VL--)
if ((so.noise_gen <<= 1) & 0x80000000L)
so.noise_gen ^= 0x0040001L;
ch->sample = (so.noise_gen << 17) >> 17;
}
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
}
if (pitch_mod & (1 << (J + 1)))
//wave [I / 2] = ch->sample * envx;
wave [I >> 1] = ch->sample * envx;
MixBuffer [I ] += VL;
MixBuffer [I + 1] += VR;
ch->echo_buf_ptr [I ] += VL;
ch->echo_buf_ptr [I + 1] += VR;
}
stereo_exit: ;
ch->envx = envx;
ch->envxx = envxx;
}
}
#else
void MixStereo (int sample_count)
{
static int wave[SOUND_BUFFER_SIZE];
 
int pitch_mod = SoundData.pitch_mod & ~APU.DSP[APU_NON];
for (uint32 J = 0; J < NUM_CHANNELS; J++)
{
int32 VL, VR;
Channel *ch = &SoundData.channels[J];
unsigned long freq0 = ch->frequency;
if (ch->state == SOUND_SILENT || !(so.sound_switch & (1 << J)))
continue;
#ifndef PSP
freq0 = (unsigned long) ((double) freq0 * 0.985);//uncommented by jonathan gevaryahu, as it is necessary for most cards in linux
#endif // PSP
bool8 mod = pitch_mod & (1 << J);
if (ch->needs_decode)
{
DecodeBlock(ch);
ch->needs_decode = FALSE;
ch->sample = ch->block[0];
ch->sample_pointer = freq0 >> FIXED_POINT_SHIFT;
if (ch->sample_pointer == 0)
ch->sample_pointer = 1;
if (ch->sample_pointer > SOUND_DECODE_LENGTH)
ch->sample_pointer = SOUND_DECODE_LENGTH - 1;
 
ch->next_sample=ch->block[ch->sample_pointer];
#ifndef OPTI
ch->interpolate = 0;
if (Settings.InterpolatedSound && freq0 < FIXED_POINT && !mod)
ch->interpolate = ((ch->next_sample - ch->sample) *
(long) freq0) / (long) FIXED_POINT;
#endif // OPTI
}
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
for (uint32 I = 0; I < (uint32) sample_count; I += 2)
{
unsigned long freq = freq0;
if (mod)
//freq = PITCH_MOD(freq, wave [I / 2]);
freq = PITCH_MOD(freq, wave [I >> 1]);
ch->env_error += ch->erate;
if (ch->env_error >= FIXED_POINT)
{
uint32 step = ch->env_error >> FIXED_POINT_SHIFT;
switch (ch->state)
{
case SOUND_ATTACK:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_DECAY;
if (ch->sustain_level != 8)
{
S9xSetEnvRate (ch, ch->decay_rate, -1,
(MAX_ENVELOPE_HEIGHT * ch->sustain_level)
>> 3);
break;
}
ch->state = SOUND_SUSTAIN;
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
}
break;
case SOUND_DECAY:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= ch->envx_target)
{
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
ch->state = SOUND_SUSTAIN;
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
}
break;
case SOUND_SUSTAIN:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_RELEASE:
while (ch->env_error >= FIXED_POINT)
{
//ch->envxx -= (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
ch->envxx -= ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_INCREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_GAIN;
ch->mode = MODE_GAIN;
S9xSetEnvRate (ch, 0, -1, 0);
}
break;
case SOUND_INCREASE_BENT_LINE:
//if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) / 4)
if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) >> 2)
{
while (ch->env_error >= FIXED_POINT)
{
//ch->envxx += (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
ch->envxx += ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
}
else
{
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
}
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_GAIN;
ch->mode = MODE_GAIN;
S9xSetEnvRate (ch, 0, -1, 0);
}
break;
case SOUND_DECREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx -= step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_DECREASE_EXPONENTIAL:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
break;
case SOUND_GAIN:
S9xSetEnvRate (ch, 0, -1, 0);
break;
}
//ch-> left_vol_level = (ch->envx * ch->volume_left) / 128;
//ch->right_vol_level = (ch->envx * ch->volume_right) / 128;
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
ch-> left_vol_level = ((ch->envx * ch->volume_left) >> 7);
ch->right_vol_level = ((ch->envx * ch->volume_right) >> 7);
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
}
 
ch->count += freq;
if (ch->count >= FIXED_POINT)
{
VL = ch->count >> FIXED_POINT_SHIFT;
ch->sample_pointer += VL;
ch->count &= FIXED_POINT_REMAINDER;
 
ch->sample = ch->next_sample;
if (ch->sample_pointer >= SOUND_DECODE_LENGTH)
{
if (JUST_PLAYED_LAST_SAMPLE(ch))
{
S9xAPUSetEndOfSample (J, ch);
goto stereo_exit;
}
do
{
ch->sample_pointer -= SOUND_DECODE_LENGTH;
if (ch->last_block)
{
if (!ch->loop)
{
ch->sample_pointer = LAST_SAMPLE;
ch->next_sample = ch->sample;
break;
}
else
{
S9xAPUSetEndX (J);
ch->last_block = FALSE;
uint8 *dir = S9xGetSampleAddress (ch->sample_number);
ch->block_pointer = READ_WORD(dir + 2);
}
}
DecodeBlock (ch);
} while (ch->sample_pointer >= SOUND_DECODE_LENGTH);
if (!JUST_PLAYED_LAST_SAMPLE (ch))
ch->next_sample = ch->block [ch->sample_pointer];
}
else
ch->next_sample = ch->block [ch->sample_pointer];
if (ch->type == SOUND_SAMPLE)
{
#ifndef OPTI
if (Settings.InterpolatedSound && freq < FIXED_POINT && !mod)
{
ch->interpolate = ((ch->next_sample - ch->sample) *
(long) freq) / (long) FIXED_POINT;
ch->sample = (int16) (ch->sample + (((ch->next_sample - ch->sample) *
(long) (ch->count)) / (long) FIXED_POINT));
}
else
ch->interpolate = 0;
#endif // OPTI
}
else
{
for (;VL > 0; VL--)
if ((so.noise_gen <<= 1) & 0x80000000L)
so.noise_gen ^= 0x0040001L;
ch->sample = (so.noise_gen << 17) >> 17;
#ifndef OPTI
ch->interpolate = 0;
#endif // OPTI
}
//VL = (ch->sample * ch-> left_vol_level) / 128;
//VR = (ch->sample * ch->right_vol_level) / 128;
VL = ((ch->sample * ch-> left_vol_level) >> 7);
VR = ((ch->sample * ch->right_vol_level) >> 7);
}
else
{
#ifndef OPTI
if (ch->interpolate)
{
int32 s = (int32) ch->sample + ch->interpolate;
CLIP16(s);
ch->sample = (int16) s;
VL = (ch->sample * ch-> left_vol_level) / 128;
VR = (ch->sample * ch->right_vol_level) / 128;
}
#endif // OPTI
}
if (pitch_mod & (1 << (J + 1)))
//wave [I / 2] = ch->sample * ch->envx;
wave [I >> 1] = ch->sample * ch->envx;
#ifdef OPTI
MixBuffer [I ] += VL;
MixBuffer [I + 1] += VR;
ch->echo_buf_ptr [I ] += VL;
ch->echo_buf_ptr [I + 1] += VR;
#else
MixBuffer [I ^ Settings.ReverseStereo] += VL;
MixBuffer [I + (1 ^ Settings.ReverseStereo)] += VR;
ch->echo_buf_ptr [I ^ Settings.ReverseStereo] += VL;
ch->echo_buf_ptr [I + (1 ^ Settings.ReverseStereo)] += VR;
#endif // OPTI
}
stereo_exit: ;
}
}
#endif // OPTI
 
#ifdef __DJGPP
END_OF_FUNCTION(MixStereo);
#endif
 
#ifndef OPTI
void MixMono (int sample_count)
{
static int wave[SOUND_BUFFER_SIZE];
 
int pitch_mod = SoundData.pitch_mod & (~APU.DSP[APU_NON]);
for (uint32 J = 0; J < NUM_CHANNELS; J++)
{
Channel *ch = &SoundData.channels[J];
unsigned long freq0 = ch->frequency;
if (ch->state == SOUND_SILENT || !(so.sound_switch & (1 << J)))
continue;
// freq0 = (unsigned long) ((double) freq0 * 0.985);
bool8 mod = pitch_mod & (1 << J);
if (ch->needs_decode)
{
DecodeBlock(ch);
ch->needs_decode = FALSE;
ch->sample = ch->block[0];
ch->sample_pointer = freq0 >> FIXED_POINT_SHIFT;
if (ch->sample_pointer == 0)
ch->sample_pointer = 1;
if (ch->sample_pointer > SOUND_DECODE_LENGTH)
ch->sample_pointer = SOUND_DECODE_LENGTH - 1;
ch->next_sample = ch->block[ch->sample_pointer];
#ifndef OPTI
ch->interpolate = 0;
if (Settings.InterpolatedSound && freq0 < FIXED_POINT && !mod)
ch->interpolate = ((ch->next_sample - ch->sample) *
(long) freq0) / (long) FIXED_POINT;
#endif // OPTI
}
//int32 V = (ch->sample * ch->left_vol_level) / 128;
int32 V = ((ch->sample * ch->left_vol_level) >> 7);
for (uint32 I = 0; I < (uint32) sample_count; I++)
{
unsigned long freq = freq0;
if (mod)
freq = PITCH_MOD(freq, wave [I]);
ch->env_error += ch->erate;
if (ch->env_error >= FIXED_POINT)
{
uint32 step = ch->env_error >> FIXED_POINT_SHIFT;
switch (ch->state)
{
case SOUND_ATTACK:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_DECAY;
if (ch->sustain_level != 8)
{
S9xSetEnvRate (ch, ch->decay_rate, -1,
(MAX_ENVELOPE_HEIGHT * ch->sustain_level)
>> 3);
break;
}
ch->state = SOUND_SUSTAIN;
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
}
break;
case SOUND_DECAY:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= ch->envx_target)
{
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
ch->state = SOUND_SUSTAIN;
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
}
break;
case SOUND_SUSTAIN:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
break;
case SOUND_RELEASE:
while (ch->env_error >= FIXED_POINT)
{
//ch->envxx -= (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
ch->envxx -= ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
break;
case SOUND_INCREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_GAIN;
ch->mode = MODE_GAIN;
S9xSetEnvRate (ch, 0, -1, 0);
}
break;
case SOUND_INCREASE_BENT_LINE:
//if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) / 4)
if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) >> 2)
{
while (ch->env_error >= FIXED_POINT)
{
//ch->envxx += (MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) / 256;
ch->envxx += ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8);
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
}
else
{
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx += step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
}
if (ch->envx >= 126)
{
ch->envx = 127;
ch->envxx = 127 << ENVX_SHIFT;
ch->state = SOUND_GAIN;
ch->mode = MODE_GAIN;
S9xSetEnvRate (ch, 0, -1, 0);
}
break;
case SOUND_DECREASE_LINEAR:
ch->env_error &= FIXED_POINT_REMAINDER;
ch->envx -= step << 1;
ch->envxx = ch->envx << ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
break;
case SOUND_DECREASE_EXPONENTIAL:
while (ch->env_error >= FIXED_POINT)
{
ch->envxx = (ch->envxx >> 8) * 255;
ch->env_error -= FIXED_POINT;
}
ch->envx = ch->envxx >> ENVX_SHIFT;
if (ch->envx <= 0)
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
break;
case SOUND_GAIN:
S9xSetEnvRate (ch, 0, -1, 0);
break;
}
//ch->left_vol_level = (ch->envx * ch->volume_left) / 128;
//V = (ch->sample * ch->left_vol_level) / 128;
ch->left_vol_level = ((ch->envx * ch->volume_left) >> 7);
V = ((ch->sample * ch->left_vol_level) >> 7);
}
ch->count += freq;
if (ch->count >= FIXED_POINT)
{
V = ch->count >> FIXED_POINT_SHIFT;
ch->sample_pointer += V;
ch->count &= FIXED_POINT_REMAINDER;
ch->sample = ch->next_sample;
if (ch->sample_pointer >= SOUND_DECODE_LENGTH)
{
if (JUST_PLAYED_LAST_SAMPLE(ch))
{
S9xAPUSetEndOfSample (J, ch);
goto mono_exit;
}
do
{
ch->sample_pointer -= SOUND_DECODE_LENGTH;
if (ch->last_block)
{
if (!ch->loop)
{
ch->sample_pointer = LAST_SAMPLE;
ch->next_sample = ch->sample;
break;
}
else
{
ch->last_block = FALSE;
uint8 *dir = S9xGetSampleAddress (ch->sample_number);
ch->block_pointer = READ_WORD(dir + 2);
S9xAPUSetEndX (J);
}
}
DecodeBlock (ch);
} while (ch->sample_pointer >= SOUND_DECODE_LENGTH);
if (!JUST_PLAYED_LAST_SAMPLE (ch))
ch->next_sample = ch->block [ch->sample_pointer];
}
else
ch->next_sample = ch->block [ch->sample_pointer];
if (ch->type == SOUND_SAMPLE)
{
#ifndef OPTI
if (Settings.InterpolatedSound && freq < FIXED_POINT && !mod)
{
ch->interpolate = ((ch->next_sample - ch->sample) *
(long) freq) / (long) FIXED_POINT;
ch->sample = (int16) (ch->sample + (((ch->next_sample - ch->sample) *
(long) (ch->count)) / (long) FIXED_POINT));
}
else
ch->interpolate = 0;
#endif // OPTI
}
else
{
for (;V > 0; V--)
if ((so.noise_gen <<= 1) & 0x80000000L)
so.noise_gen ^= 0x0040001L;
ch->sample = (so.noise_gen << 17) >> 17;
ch->interpolate = 0;
}
//V = (ch->sample * ch-> left_vol_level) / 128;
V = ((ch->sample * ch-> left_vol_level) >> 7);
}
else
{
#ifndef OPTI
if (ch->interpolate)
{
int32 s = (int32) ch->sample + ch->interpolate;
CLIP16(s);
ch->sample = (int16) s;
//V = (ch->sample * ch-> left_vol_level) / 128;
V = ((ch->sample * ch-> left_vol_level) >> 7);
}
#endif // OPTI
}
MixBuffer [I] += V;
ch->echo_buf_ptr [I] += V;
if (pitch_mod & (1 << (J + 1)))
wave [I] = ch->sample * ch->envx;
}
mono_exit: ;
}
}
#ifdef __DJGPP
END_OF_FUNCTION(MixMono);
#endif
#endif // OPTI
 
#ifdef __sun
extern uint8 int2ulaw (int);
#endif
 
// For backwards compatibility with older port specific code
void S9xMixSamplesO (uint8 *buffer, int sample_count, int byte_offset)
{
S9xMixSamples (buffer+byte_offset, sample_count);
}
#ifdef __DJGPP
END_OF_FUNCTION(S9xMixSamplesO);
#endif
 
void S9xMixSamples (uint8 *buffer, int sample_count)
{
int J;
int I;
#ifdef PSP
int Jmul;
int byte_count = sample_count << 1;
#endif // PSP
if (!so.mute_sound)
{
#ifdef OPTI
memset (MixBuffer, 0, sample_count * sizeof (MixBuffer [0]));
#else
memset (MixBuffer, 0, sample_count * sizeof (MixBuffer [0]));
#endif // OPTI
if (SoundData.echo_enable)
memset (EchoBuffer, 0, sample_count * sizeof (EchoBuffer [0]));
#ifdef OPTI
#ifdef PSP
sample_count >>= s_iSoundMulRate;
#endif // PSP
MixStereo (sample_count);
#else
if (so.stereo)
MixStereo (sample_count);
else
MixMono (sample_count);
#endif // OPTI
}
/* Mix and convert waveforms */
#ifndef OPTI
if (so.sixteen_bit)
#endif // OPTI
{
#ifndef PSP
int byte_count = sample_count << 1;
#endif // PSP
// 16-bit sound
if (so.mute_sound)
{
memset (buffer, 0, byte_count);
}
else
{
if (SoundData.echo_enable && SoundData.echo_buffer_size)
{
#ifndef OPTI
if (so.stereo)
#endif // OPTI
{
// 16-bit stereo sound with echo enabled ...
if (SoundData.no_filter)
{
// ... but no filter defined.
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1] +
// E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1] +
E * SoundData.echo_volume [J & 1]) >> 7;
CLIP16(I);
#ifdef PSP
if (s_iSoundMulRate==0) {
((signed short *) buffer)[J] = I;
} else if (s_iSoundMulRate==1) {
Jmul = J << 1;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
}
} else if (s_iSoundMulRate==2) {
Jmul = J << 2;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 3] = I;
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
((signed short *) buffer)[Jmul + 3] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
((signed short *) buffer)[Jmul + 4] = I;
((signed short *) buffer)[Jmul + 6] = I;
}
}
#else
((signed short *) buffer)[J] = I;
#endif // PSP
}
}
else
{
// ... with filter defined.
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Loop [(Z - 0) & 15] = E;
E = E * FilterTaps [0];
E += Loop [(Z - 2) & 15] * FilterTaps [1];
E += Loop [(Z - 4) & 15] * FilterTaps [2];
E += Loop [(Z - 6) & 15] * FilterTaps [3];
E += Loop [(Z - 8) & 15] * FilterTaps [4];
E += Loop [(Z - 10) & 15] * FilterTaps [5];
E += Loop [(Z - 12) & 15] * FilterTaps [6];
E += Loop [(Z - 14) & 15] * FilterTaps [7];
E /= 128;
Z++;
//Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
// EchoBuffer [J];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1] +
// E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1] +
E * SoundData.echo_volume [J & 1]) >> 7;
CLIP16(I);
#ifdef PSP
if (s_iSoundMulRate==0) {
((signed short *) buffer)[J] = I;
} else if (s_iSoundMulRate==1) {
Jmul = J << 1;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
}
} else if (s_iSoundMulRate==2) {
Jmul = J << 2;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 3] = I;
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
((signed short *) buffer)[Jmul + 3] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
((signed short *) buffer)[Jmul + 4] = I;
((signed short *) buffer)[Jmul + 6] = I;
}
}
#else
((signed short *) buffer)[J] = I;
#endif // PSP
}
}
}
#ifndef OPTI
else
{
// 16-bit mono sound with echo enabled...
if (SoundData.no_filter)
{
// ... no filter defined
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
I = (MixBuffer [J] *
SoundData.master_volume [0] +
E * SoundData.echo_volume [0]) / VOL_DIV16;
CLIP16(I);
((signed short *) buffer)[J] = I;
}
}
else
{
// ... with filter defined
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Loop [(Z - 0) & 7] = E;
E = E * FilterTaps [0];
E += Loop [(Z - 1) & 7] * FilterTaps [1];
E += Loop [(Z - 2) & 7] * FilterTaps [2];
E += Loop [(Z - 3) & 7] * FilterTaps [3];
E += Loop [(Z - 4) & 7] * FilterTaps [4];
E += Loop [(Z - 5) & 7] * FilterTaps [5];
E += Loop [(Z - 6) & 7] * FilterTaps [6];
E += Loop [(Z - 7) & 7] * FilterTaps [7];
E /= 128;
Z++;
Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
I = (MixBuffer [J] * SoundData.master_volume [0] +
E * SoundData.echo_volume [0]) / VOL_DIV16;
CLIP16(I);
((signed short *) buffer)[J] = I;
}
}
}
#endif // OPTI
}
else
{
// 16-bit mono or stereo sound, no echo
for (J = 0; J < sample_count; J++)
{
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1]) / VOL_DIV16;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1]) >> 7;
CLIP16(I);
#ifdef PSP
if (s_iSoundMulRate==0) {
((signed short *) buffer)[J] = I;
} else if (s_iSoundMulRate==1) {
Jmul = J << 1;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
}
} else if (s_iSoundMulRate==2) {
Jmul = J << 2;
if ( J & 1 ) {
((signed short *) buffer)[Jmul - 3] = I;
((signed short *) buffer)[Jmul - 1] = I;
((signed short *) buffer)[Jmul + 1] = I;
((signed short *) buffer)[Jmul + 3] = I;
} else {
((signed short *) buffer)[Jmul ] = I;
((signed short *) buffer)[Jmul + 2] = I;
((signed short *) buffer)[Jmul + 4] = I;
((signed short *) buffer)[Jmul + 6] = I;
}
}
#else
((signed short *) buffer)[J] = I;
#endif // PSP
}
}
}
}
#ifndef OPTI
else
{
// 8-bit sound
if (so.mute_sound)
{
memset (buffer, 128, sample_count);
}
else
#ifdef __sun
if (so.encoded)
{
for (J = 0; J < sample_count; J++)
{
//I = (MixBuffer [J] * SoundData.master_volume_left) / VOL_DIV16;
I = (MixBuffer [J] * SoundData.master_volume_left) >> 7;
CLIP16(I);
buffer[J] = int2ulaw (I);
}
}
else
#endif
{
if (SoundData.echo_enable && SoundData.echo_buffer_size)
{
if (so.stereo)
{
// 8-bit stereo sound with echo enabled...
if (SoundData.no_filter)
{
// ... but no filter
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
//Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
// EchoBuffer [J];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1] +
// E * SoundData.echo_volume [J & 1]) / VOL_DIV8;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1] +
E * SoundData.echo_volume [J & 1]) >> 15;
CLIP8(I);
buffer [J] = I + 128;
}
}
else
{
// ... with filter
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Loop [(Z - 0) & 15] = E;
E = E * FilterTaps [0];
E += Loop [(Z - 2) & 15] * FilterTaps [1];
E += Loop [(Z - 4) & 15] * FilterTaps [2];
E += Loop [(Z - 6) & 15] * FilterTaps [3];
E += Loop [(Z - 8) & 15] * FilterTaps [4];
E += Loop [(Z - 10) & 15] * FilterTaps [5];
E += Loop [(Z - 12) & 15] * FilterTaps [6];
E += Loop [(Z - 14) & 15] * FilterTaps [7];
E /= 128;
Z++;
//Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
// EchoBuffer [J];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1] +
// E * SoundData.echo_volume [J & 1]) / VOL_DIV8;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1] +
E * SoundData.echo_volume [J & 1]) >> 15;
CLIP8(I);
buffer [J] = I + 128;
}
}
}
else
{
// 8-bit mono sound with echo enabled...
if (SoundData.no_filter)
{
// ... but no filter.
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
//Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
// EchoBuffer [J];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] * SoundData.master_volume [0] +
// E * SoundData.echo_volume [0]) / VOL_DIV8;
I = (MixBuffer [J] * SoundData.master_volume [0] +
E * SoundData.echo_volume [0]) >> 15;
CLIP8(I);
buffer [J] = I + 128;
}
}
else
{
// ... with filter.
for (J = 0; J < sample_count; J++)
{
int E = Echo [SoundData.echo_ptr];
Loop [(Z - 0) & 7] = E;
E = E * FilterTaps [0];
E += Loop [(Z - 1) & 7] * FilterTaps [1];
E += Loop [(Z - 2) & 7] * FilterTaps [2];
E += Loop [(Z - 3) & 7] * FilterTaps [3];
E += Loop [(Z - 4) & 7] * FilterTaps [4];
E += Loop [(Z - 5) & 7] * FilterTaps [5];
E += Loop [(Z - 6) & 7] * FilterTaps [6];
E += Loop [(Z - 7) & 7] * FilterTaps [7];
E /= 128;
Z++;
//Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 +
// EchoBuffer [J];
Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) +
EchoBuffer [J];
if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size)
SoundData.echo_ptr = 0;
//I = (MixBuffer [J] * SoundData.master_volume [0] +
// E * SoundData.echo_volume [0]) / VOL_DIV8;
I = (MixBuffer [J] * SoundData.master_volume [0] +
E * SoundData.echo_volume [0]) >> 15;
CLIP8(I);
buffer [J] = I + 128;
}
}
}
}
else
{
// 8-bit mono or stereo sound, no echo
for (J = 0; J < sample_count; J++)
{
//I = (MixBuffer [J] *
// SoundData.master_volume [J & 1]) / VOL_DIV8;
I = (MixBuffer [J] *
SoundData.master_volume [J & 1]) >> 15;
CLIP8(I);
buffer [J] = I + 128;
}
}
}
}
#endif // OPTI
}
 
#ifdef __DJGPP
END_OF_FUNCTION(S9xMixSamples);
#endif
 
void S9xResetSound (bool8 full)
{
for (int i = 0; i < 8; i++)
{
SoundData.channels[i].state = SOUND_SILENT;
SoundData.channels[i].mode = MODE_NONE;
SoundData.channels[i].type = SOUND_SAMPLE;
SoundData.channels[i].volume_left = 0;
SoundData.channels[i].volume_right = 0;
SoundData.channels[i].hertz = 0;
SoundData.channels[i].count = 0;
SoundData.channels[i].loop = FALSE;
SoundData.channels[i].envx_target = 0;
SoundData.channels[i].env_error = 0;
SoundData.channels[i].erate = 0;
SoundData.channels[i].envx = 0;
SoundData.channels[i].envxx = 0;
SoundData.channels[i].left_vol_level = 0;
SoundData.channels[i].right_vol_level = 0;
SoundData.channels[i].direction = 0;
SoundData.channels[i].attack_rate = 0;
SoundData.channels[i].decay_rate = 0;
SoundData.channels[i].sustain_rate = 0;
SoundData.channels[i].release_rate = 0;
SoundData.channels[i].sustain_level = 0;
SoundData.echo_ptr = 0;
SoundData.echo_feedback = 0;
SoundData.echo_buffer_size = 1;
}
FilterTaps [0] = 127;
FilterTaps [1] = 0;
FilterTaps [2] = 0;
FilterTaps [3] = 0;
FilterTaps [4] = 0;
FilterTaps [5] = 0;
FilterTaps [6] = 0;
FilterTaps [7] = 0;
so.mute_sound = TRUE;
so.noise_gen = 1;
#ifndef OPTI
so.sound_switch = 255;
#endif // OPTI
so.samples_mixed_so_far = 0;
so.play_position = 0;
so.err_counter = 0;
if (full)
{
SoundData.master_volume_left = 0;
SoundData.master_volume_right = 0;
SoundData.echo_volume_left = 0;
SoundData.echo_volume_right = 0;
SoundData.echo_enable = 0;
SoundData.echo_write_enabled = 0;
SoundData.echo_channel_enable = 0;
SoundData.pitch_mod = 0;
SoundData.dummy[0] = 0;
SoundData.dummy[1] = 0;
SoundData.dummy[2] = 0;
SoundData.master_volume[0] = 0;
SoundData.master_volume[1] = 0;
SoundData.echo_volume[0] = 0;
SoundData.echo_volume[1] = 0;
SoundData.noise_hertz = 0;
}
SoundData.master_volume_left = 127;
SoundData.master_volume_right = 127;
SoundData.master_volume [0] = SoundData.master_volume [1] = 127;
#ifdef PSP
// so.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME / (1.0 / PSP_PLAYBACK_RATE));
#else
if (so.playback_rate)
so.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME / (1.0 / so.playback_rate));
else
so.err_rate = 0;
#endif // PSP
SoundData.no_filter = TRUE;
}
 
void S9xSetPlaybackRate (uint32 playback_rate)
{
#ifdef PSP
s_iSoundMulRate = 0;
if (playback_rate == 11025) s_iSoundMulRate = 2;
else if (playback_rate == 22050) s_iSoundMulRate = 1;
// so.err_rate = (uint32) (SNES_SCANLINE_TIME * FIXED_POINT / (1.0 / PSP_PLAYBACK_RATE));
#else
so.playback_rate = playback_rate;
so.err_rate = (uint32) (SNES_SCANLINE_TIME * FIXED_POINT / (1.0 / (double) so.playback_rate));
#endif // PSP
S9xSetEchoDelay (APU.DSP [APU_EDL] & 0xf);
for (int i = 0; i < 8; i++)
S9xSetSoundFrequency (i, SoundData.channels [i].hertz);
}
 
bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size)
{
so.sound_fd = -1;
#ifndef OPTI
so.sound_switch = 255;
#endif // OPTI
so.buffer_size = 0;
#ifndef OPTI
so.playback_rate = 0;
so.stereo = stereo;
so.sixteen_bit = Settings.SixteenBitSound;
#endif // OPTI
so.encoded = FALSE;
S9xResetSound (TRUE);
if (!(mode & 7))
return (1);
S9xSetSoundMute (TRUE);
if (!S9xOpenSoundDevice (mode, stereo, buffer_size))
{
#ifdef NOSOUND
S9xMessage (S9X_WARNING, S9X_SOUND_NOT_BUILT,
"No sound support compiled in");
#else
S9xMessage (S9X_ERROR, S9X_SOUND_DEVICE_OPEN_FAILED,
"Sound device open failed");
#endif
return (0);
}
return (1);
}
 
bool8 S9xSetSoundMode (int channel, int mode)
{
Channel *ch = &SoundData.channels[channel];
switch (mode)
{
case MODE_RELEASE:
if (ch->mode != MODE_NONE)
{
ch->mode = MODE_RELEASE;
return (TRUE);
}
break;
case MODE_DECREASE_LINEAR:
case MODE_DECREASE_EXPONENTIAL:
case MODE_GAIN:
if (ch->mode != MODE_RELEASE)
{
ch->mode = mode;
if (ch->state != SOUND_SILENT)
ch->state = mode;
return (TRUE);
}
break;
case MODE_INCREASE_LINEAR:
case MODE_INCREASE_BENT_LINE:
if (ch->mode != MODE_RELEASE)
{
ch->mode = mode;
if (ch->state != SOUND_SILENT)
ch->state = mode;
return (TRUE);
}
break;
case MODE_ADSR:
if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR)
{
ch->mode = mode;
return (TRUE);
}
}
return (FALSE);
}
 
#ifndef OPTI
void S9xSetSoundControl (int sound_switch)
{
so.sound_switch = sound_switch;
}
#endif // OPTI
 
void S9xPlaySample (int channel)
{
Channel *ch = &SoundData.channels[channel];
ch->state = SOUND_SILENT;
ch->mode = MODE_NONE;
ch->envx = 0;
ch->envxx = 0;
S9xFixEnvelope (channel,
APU.DSP [APU_GAIN + (channel << 4)],
APU.DSP [APU_ADSR1 + (channel << 4)],
APU.DSP [APU_ADSR2 + (channel << 4)]);
ch->sample_number = APU.DSP [APU_SRCN + channel * 0x10];
if (APU.DSP [APU_NON] & (1 << channel))
ch->type = SOUND_NOISE;
else
ch->type = SOUND_SAMPLE;
S9xSetSoundFrequency (channel, ch->hertz);
ch->loop = FALSE;
ch->needs_decode = TRUE;
ch->last_block = FALSE;
ch->previous [0] = ch->previous[1] = 0;
uint8 *dir = S9xGetSampleAddress (ch->sample_number);
ch->block_pointer = READ_WORD (dir);
ch->sample_pointer = 0;
ch->env_error = 0;
ch->next_sample = 0;
#ifndef OPTI
ch->interpolate = 0;
#endif // OPTI
switch (ch->mode)
{
case MODE_ADSR:
if (ch->attack_rate == 0)
{
if (ch->decay_rate == 0 || ch->sustain_level == 8)
{
ch->state = SOUND_SUSTAIN;
ch->envx = (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3;
S9xSetEnvRate (ch, ch->sustain_rate, -1, 0);
}
else
{
ch->state = SOUND_DECAY;
ch->envx = MAX_ENVELOPE_HEIGHT;
S9xSetEnvRate (ch, ch->decay_rate, -1,
(MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3);
}
//ch-> left_vol_level = (ch->envx * ch->volume_left) / 128;
//ch->right_vol_level = (ch->envx * ch->volume_right) / 128;
ch-> left_vol_level = ((ch->envx * ch->volume_left) >> 7);
ch->right_vol_level = ((ch->envx * ch->volume_right) >> 7);
}
else
{
ch->state = SOUND_ATTACK;
ch->envx = 0;
ch->left_vol_level = 0;
ch->right_vol_level = 0;
S9xSetEnvRate (ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT);
}
ch->envxx = ch->envx << ENVX_SHIFT;
break;
case MODE_GAIN:
ch->state = SOUND_GAIN;
break;
case MODE_INCREASE_LINEAR:
ch->state = SOUND_INCREASE_LINEAR;
break;
case MODE_INCREASE_BENT_LINE:
ch->state = SOUND_INCREASE_BENT_LINE;
break;
case MODE_DECREASE_LINEAR:
ch->state = SOUND_DECREASE_LINEAR;
break;
case MODE_DECREASE_EXPONENTIAL:
ch->state = SOUND_DECREASE_EXPONENTIAL;
break;
default:
break;
}
S9xFixEnvelope (channel,
APU.DSP [APU_GAIN + (channel << 4)],
APU.DSP [APU_ADSR1 + (channel << 4)],
APU.DSP [APU_ADSR2 + (channel << 4)]);
}
 
 
/tags/initial/snes9x/cpuops.cpp
New file
0,0 → 1,4458
/*******************************************************************************
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
 
#include "cpuexec.h"
#include "cpuaddr.h"
#include "cpuops.h"
#include "cpumacro.h"
#include "apu.h"
 
/* 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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 += CPU.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 += CPU.MemSpeedx2;
#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 (!Settings.SoundSkipMethod)\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
}
 
#define BranchCheck1()\
if( CPU.BranchSkip)\
{\
CPU.BranchSkip = FALSE;\
if (!Settings.SoundSkipMethod) {\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
} else \
if (Settings.SoundSkipMethod == 1)\
return;\
if (Settings.SoundSkipMethod == 3)\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
else\
CPU.PC = CPU.PCBase + OpAddress;\
}
 
#define BranchCheck2()\
if( CPU.BranchSkip)\
{\
CPU.BranchSkip = FALSE;\
if (!Settings.SoundSkipMethod) {\
if( CPU.PC - CPU.PCBase > OpAddress)\
return;\
} else \
if (Settings.SoundSkipMethod == 1)\
CPU.PC = CPU.PCBase + OpAddress;\
if (Settings.SoundSkipMethod == 3)\
if (CPU.PC - CPU.PCBase > OpAddress)\
return;\
else\
CPU.PC = CPU.PCBase + OpAddress;\
}
#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 */
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
#ifndef OPTI
missing.decimal_mode = 1;
#endif // OPTI
}
 
/* 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;
#ifndef OPTI
missing.emulate6502 = 1;
#endif // OPTI
}
if (CheckIndex ())
{
Registers.XH = 0;
Registers.YH = 0;
}
S9xFixCycles();
}
/**********************************************************************************************/
 
/* BRK *************************************************************************************** */
static void Op00 (void)
{
#ifdef DEBUGGER
if (CPU.Flags & TRACE_FLAG)
S9xTraceMessage ("*** BRK");
#endif
 
#ifndef SA1_OPCODES
CPU.BRKTriggered = TRUE;
#endif
 
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)
{
#ifdef DEBUGGER
if (CPU.Flags & TRACE_FLAG)
S9xTraceMessage ("*** IRQ");
#endif
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 (Memory.FillRAM [0x2207] |
(Memory.FillRAM [0x2208] << 8));
#else
if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40))
S9xSetPCBase (Memory.FillRAM [0x220e] |
(Memory.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 (Memory.FillRAM [0x2207] |
(Memory.FillRAM [0x2208] << 8));
#else
if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x40))
S9xSetPCBase (Memory.FillRAM [0x220e] |
(Memory.FillRAM [0x220f] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFFE));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
 
/**********************************************************************************************/
 
/* NMI *************************************************************************************** */
void S9xOpcode_NMI (void)
{
#ifdef DEBUGGER
if (CPU.Flags & TRACE_FLAG)
S9xTraceMessage ("*** NMI");
#endif
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 (Memory.FillRAM [0x2205] |
(Memory.FillRAM [0x2206] << 8));
#else
if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x20))
S9xSetPCBase (Memory.FillRAM [0x220c] |
(Memory.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 (Memory.FillRAM [0x2205] |
(Memory.FillRAM [0x2206] << 8));
#else
if (Settings.SA1 && (Memory.FillRAM [0x2209] & 0x20))
S9xSetPCBase (Memory.FillRAM [0x220c] |
(Memory.FillRAM [0x220d] << 8));
else
S9xSetPCBase (S9xGetWord (0xFFFA));
#endif
#ifndef SA1_OPCODES
CPU.Cycles += ONE_CYCLE;
#endif
}
}
/**********************************************************************************************/
 
/* COP *************************************************************************************** */
static void Op02 (void)
{
#ifdef DEBUGGER
if (CPU.Flags & TRACE_FLAG)
S9xTraceMessage ("*** COP");
#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 (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 += CPU.MemSpeedx2 + 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 += CPU.MemSpeedx2 + 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 += CPU.MemSpeedx2 + 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 += CPU.MemSpeedx2 + 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 += CPU.MemSpeed + ONE_CYCLE;
#endif
if (CheckEmulation())
{
SetFlags (MemoryFlag | IndexFlag);
#ifndef OPTI
missing.emulate6502 = 1;
#endif // OPTI
}
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 += CPU.MemSpeed + ONE_CYCLE;
#endif
if (CheckEmulation())
{
SetFlags (MemoryFlag | IndexFlag);
#ifndef OPTI
missing.emulate6502 = 1;
#endif // OPTI
}
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);
#ifndef OPTI
missing.emulate6502 = 1;
#endif // OPTI
}
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 0
 
 
if (CPU.IRQActive)
{
#ifndef SA1_OPCODES
CPU.Cycles += TWO_CYCLES;
#endif
}
else
#endif
{
if (DSP1.version == 3) return;
 
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},
{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}, {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 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}
};
 
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},
{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}, {Op44X1}, {Op45M0},
{Op46M0}, {Op47M0}, {Op48M0}, {Op49M0}, {Op4AM0},
{Op4B}, {Op4C}, {Op4DM0}, {Op4EM0}, {Op4FM0},
{Op50}, {Op51M0}, {Op52M0}, {Op53M0}, {Op54X1},
{Op55M0}, {Op56M0}, {Op57M0}, {Op58}, {Op59M0},
{Op5AX1}, {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}, {Op7AX1}, {Op7B}, {Op7C},
{Op7DM0}, {Op7EM0}, {Op7FM0}, {Op80}, {Op81M0},
{Op82}, {Op83M0}, {Op84X1}, {Op85M0}, {Op86X1},
{Op87M0}, {Op88X1}, {Op89M0}, {Op8AM0}, {Op8B},
{Op8CX1}, {Op8DM0}, {Op8EX1}, {Op8FM0}, {Op90},
{Op91M0}, {Op92M0}, {Op93M0}, {Op94X1}, {Op95M0},
{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}
};
 
/tags/initial/snes9x/display.h
New file
0,0 → 1,137
/*******************************************************************************
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.
*******************************************************************************/
 
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
 
START_EXTERN_C
// Routines the port specific code has to implement
void S9xSetPalette ();
void S9xTextMode ();
void S9xGraphicsMode ();
char *S9xParseArgs (char **argv, int argc);
void S9xParseArg (char **argv, int &index, int argc);
void S9xExtraUsage ();
uint32 S9xReadJoypad (int which1_0_to_4);
bool8 S9xReadMousePosition (int which1_0_to_1, int &x, int &y, uint32 &buttons);
bool8 S9xReadSuperScopePosition (int &x, int &y, uint32 &buttons);
 
void S9xUsage ();
void S9xInitDisplay (int argc, char **argv);
void S9xDeinitDisplay ();
void S9xInitInputDevices ();
void S9xSetTitle (const char *title);
void S9xProcessEvents (bool8 block);
void S9xPutImage (int width, int height);
void S9xParseDisplayArg (char **argv, int &index, int argc);
void S9xToggleSoundChannel (int channel);
void S9xSetInfoString (const char *string);
int S9xMinCommandLineArgs ();
void S9xNextController ();
bool8 S9xLoadROMImage (const char *string);
const char *S9xSelectFilename (const char *def, const char *dir,
const char *ext, const char *title);
 
const char *S9xChooseFilename (bool8 read_only);
bool8 S9xOpenSnapshotFile (const char *base, bool8 read_only, STREAM *file);
void S9xCloseSnapshotFile (STREAM file);
 
const char *S9xBasename (const char *filename);
 
int S9xFStrcmp (FILE *, const char *);
const char *S9xGetHomeDirectory ();
const char *S9xGetSnapshotDirectory ();
const char *S9xGetROMDirectory ();
const char *S9xGetSRAMFilename ();
const char *S9xGetFilename (const char *extension);
const char *S9xGetFilenameInc (const char *);
END_EXTERN_C
 
#endif
 
/tags/initial/snes9x/3d.h
New file
0,0 → 1,150
/*******************************************************************************
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.
*******************************************************************************/
 
#ifndef _3D_H_
#define _3D_H_
 
#if defined(USE_OPENGL)
#include <GL/gl.h>
#include <GL/glu.h>
 
#ifdef __linux__
#include <GL/glx.h>
#endif
 
typedef struct
{
bool8 packed_pixels_extension_present;
bool8 draw_cube;
uint32 version;
// Texture format
GLint internal_format;
GLint format;
GLint type;
 
GLint max_texture_size;// 256 or 512
GLint texture_size;
uint32 num_textures; // 1 if max_texture_size == 256, 2 otherwise
GLuint textures [2];
} OpenGLData;
 
extern OpenGLData OpenGL;
 
bool8 S9xOpenGLInit ();
bool8 S9xOpenGLInit2 ();
void S9xOpenGLPutImage (int width, int height);
void S9xOpenGLDeinit ();
 
#endif
 
#ifdef USE_GLIDE
#include <glide.h>
 
typedef struct
{
bool8 voodoo_present;
GrVertex sq[4];
GrTexInfo texture;
int32 texture_mem_size;
int32 texture_mem_start;
float x_offset, y_offset;
float x_scale, y_scale;
float voodoo_width;
float voodoo_height;
} GlideData;
 
extern GlideData Glide;
bool8 S9xGlideEnable (bool8 enable);
void S9xGlideDeinit ();
bool8 S9xGlideInit ();
bool8 S9xVoodooInitialise ();
#endif
 
#endif
 
/tags/initial/snes9x/c4.h
New file
0,0 → 1,124
/*******************************************************************************
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.
*******************************************************************************/
#ifndef _C4_H_
#define _C4_H_
 
#include "port.h"
 
extern "C" {
 
extern int16 C4WFXVal;
extern int16 C4WFYVal;
extern int16 C4WFZVal;
extern int16 C4WFX2Val;
extern int16 C4WFY2Val;
extern int16 C4WFDist;
extern int16 C4WFScale;
 
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
 
extern int16 C41FXVal;
extern int16 C41FYVal;
extern int16 C41FAngleRes;
extern int16 C41FDist;
extern int16 C41FDistVal;
 
void C4Op1F();
void C4Op15();
void C4Op0D();
 
extern int16 C4CosTable[];
extern int16 C4SinTable[];
 
}
 
#endif
 
/tags/initial/snes9x/fxinst.cpp
New file
0,0 → 1,1916
/*******************************************************************************
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.
*******************************************************************************/
#define FX_DO_ROMBUFFER
 
#include "fxemu.h"
#include "fxinst.h"
#include <string.h>
#include <stdio.h>
 
extern struct FxRegs_s GSU;
int gsu_bank [512] = {0};
 
/* Set this define if you wish the plot instruction to check for y-pos limits */
/* (I don't think it's nessecary) */
#define CHECK_LIMITS
 
/* Codes used:
*
* rn = a GSU register (r0-r15)
* #n = 4 bit immediate value
* #pp = 8 bit immediate value
* (yy) = 8 bit word address (0x0000 - 0x01fe)
* #xx = 16 bit immediate value
* (xx) = 16 bit address (0x0000 - 0xffff)
*
*/
 
/* 00 - stop - stop GSU execution (and maybe generate an IRQ) */
static void fx_stop()
{
CF(G);
GSU.vCounter = 0;
GSU.vInstCount = GSU.vCounter;
 
/* Check if we need to generate an IRQ */
if(!(GSU.pvRegisters[GSU_CFGR] & 0x80))
SF(IRQ);
 
GSU.vPlotOptionReg = 0;
GSU.vPipe = 1;
CLRFLAGS;
R15++;
}
 
/* 01 - nop - no operation */
static void fx_nop() { CLRFLAGS; R15++; }
 
extern void fx_flushCache();
 
/* 02 - cache - reintialize GSU cache */
static void fx_cache()
{
uint32 c = R15 & 0xfff0;
if(GSU.vCacheBaseReg != c || !GSU.bCacheActive)
{
fx_flushCache();
GSU.vCacheBaseReg = c;
GSU.bCacheActive = TRUE;
#if 0
if(c < (0x10000-512))
{
uint8 const* t = &ROM(c);
memcpy(GSU.pvCache,t,512);
}
else
{
uint8 const* t1;
uint8 const* t2;
uint32 i = 0x10000 - c;
t1 = &ROM(c);
t2 = &ROM(0);
memcpy(GSU.pvCache,t1,i);
memcpy(&GSU.pvCache[i],t2,512-i);
}
#endif
}
R15++;
CLRFLAGS;
}
 
/* 03 - lsr - logic shift right */
static void fx_lsr()
{
uint32 v;
GSU.vCarry = SREG & 1;
v = USEX16(SREG) >> 1;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 04 - rol - rotate left */
static void fx_rol()
{
uint32 v = USEX16((SREG << 1) + GSU.vCarry);
GSU.vCarry = (SREG >> 15) & 1;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 05 - bra - branch always */
static void fx_bra() { uint8 v = PIPE; R15++; FETCHPIPE; R15 += SEX8(v); }
 
/* Branch on condition */
#define BRA_COND(cond) uint8 v = PIPE; R15++; FETCHPIPE; if(cond) R15 += SEX8(v); else R15++;
 
#define TEST_S (GSU.vSign & 0x8000)
#define TEST_Z (USEX16(GSU.vZero) == 0)
#define TEST_OV (GSU.vOverflow >= 0x8000 || GSU.vOverflow < -0x8000)
#define TEST_CY (GSU.vCarry & 1)
 
/* 06 - blt - branch on less than */
static void fx_blt() { BRA_COND( (TEST_S!=0) != (TEST_OV!=0) ); }
 
/* 07 - bge - branch on greater or equals */
static void fx_bge() { BRA_COND( (TEST_S!=0) == (TEST_OV!=0)); }
 
/* 08 - bne - branch on not equal */
static void fx_bne() { BRA_COND( !TEST_Z ); }
 
/* 09 - beq - branch on equal */
static void fx_beq() { BRA_COND( TEST_Z ); }
 
/* 0a - bpl - branch on plus */
static void fx_bpl() { BRA_COND( !TEST_S ); }
 
/* 0b - bmi - branch on minus */
static void fx_bmi() { BRA_COND( TEST_S ); }
 
/* 0c - bcc - branch on carry clear */
static void fx_bcc() { BRA_COND( !TEST_CY ); }
 
/* 0d - bcs - branch on carry set */
static void fx_bcs() { BRA_COND( TEST_CY ); }
 
/* 0e - bvc - branch on overflow clear */
static void fx_bvc() { BRA_COND( !TEST_OV ); }
 
/* 0f - bvs - branch on overflow set */
static void fx_bvs() { BRA_COND( TEST_OV ); }
 
/* 10-1f - to rn - set register n as destination register */
/* 10-1f(B) - move rn - move one register to another (if B flag is set) */
#define FX_TO(reg) \
if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; } \
else { GSU.pvDreg = &GSU.avReg[reg]; } R15++;
#define FX_TO_R14(reg) \
if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; READR14; } \
else { GSU.pvDreg = &GSU.avReg[reg]; } R15++;
#define FX_TO_R15(reg) \
if(TF(B)) { GSU.avReg[(reg)] = SREG; CLRFLAGS; } \
else { GSU.pvDreg = &GSU.avReg[reg]; R15++; }
static void fx_to_r0() { FX_TO(0); }
static void fx_to_r1() { FX_TO(1); }
static void fx_to_r2() { FX_TO(2); }
static void fx_to_r3() { FX_TO(3); }
static void fx_to_r4() { FX_TO(4); }
static void fx_to_r5() { FX_TO(5); }
static void fx_to_r6() { FX_TO(6); }
static void fx_to_r7() { FX_TO(7); }
static void fx_to_r8() { FX_TO(8); }
static void fx_to_r9() { FX_TO(9); }
static void fx_to_r10() { FX_TO(10); }
static void fx_to_r11() { FX_TO(11); }
static void fx_to_r12() { FX_TO(12); }
static void fx_to_r13() { FX_TO(13); }
static void fx_to_r14() { FX_TO_R14(14); }
static void fx_to_r15() { FX_TO_R15(15); }
 
/* 20-2f - to rn - set register n as source and destination register */
#define FX_WITH(reg) SF(B); GSU.pvSreg = GSU.pvDreg = &GSU.avReg[reg]; R15++;
static void fx_with_r0() { FX_WITH(0); }
static void fx_with_r1() { FX_WITH(1); }
static void fx_with_r2() { FX_WITH(2); }
static void fx_with_r3() { FX_WITH(3); }
static void fx_with_r4() { FX_WITH(4); }
static void fx_with_r5() { FX_WITH(5); }
static void fx_with_r6() { FX_WITH(6); }
static void fx_with_r7() { FX_WITH(7); }
static void fx_with_r8() { FX_WITH(8); }
static void fx_with_r9() { FX_WITH(9); }
static void fx_with_r10() { FX_WITH(10); }
static void fx_with_r11() { FX_WITH(11); }
static void fx_with_r12() { FX_WITH(12); }
static void fx_with_r13() { FX_WITH(13); }
static void fx_with_r14() { FX_WITH(14); }
static void fx_with_r15() { FX_WITH(15); }
 
/* 30-3b - stw (rn) - store word */
#define FX_STW(reg) \
GSU.vLastRamAdr = GSU.avReg[reg]; \
RAM(GSU.avReg[reg]) = (uint8)SREG; \
RAM(GSU.avReg[reg]^1) = (uint8)(SREG>>8); \
CLRFLAGS; R15++
static void fx_stw_r0() { FX_STW(0); }
static void fx_stw_r1() { FX_STW(1); }
static void fx_stw_r2() { FX_STW(2); }
static void fx_stw_r3() { FX_STW(3); }
static void fx_stw_r4() { FX_STW(4); }
static void fx_stw_r5() { FX_STW(5); }
static void fx_stw_r6() { FX_STW(6); }
static void fx_stw_r7() { FX_STW(7); }
static void fx_stw_r8() { FX_STW(8); }
static void fx_stw_r9() { FX_STW(9); }
static void fx_stw_r10() { FX_STW(10); }
static void fx_stw_r11() { FX_STW(11); }
 
/* 30-3b(ALT1) - stb (rn) - store byte */
#define FX_STB(reg) \
GSU.vLastRamAdr = GSU.avReg[reg]; \
RAM(GSU.avReg[reg]) = (uint8)SREG; \
CLRFLAGS; R15++
static void fx_stb_r0() { FX_STB(0); }
static void fx_stb_r1() { FX_STB(1); }
static void fx_stb_r2() { FX_STB(2); }
static void fx_stb_r3() { FX_STB(3); }
static void fx_stb_r4() { FX_STB(4); }
static void fx_stb_r5() { FX_STB(5); }
static void fx_stb_r6() { FX_STB(6); }
static void fx_stb_r7() { FX_STB(7); }
static void fx_stb_r8() { FX_STB(8); }
static void fx_stb_r9() { FX_STB(9); }
static void fx_stb_r10() { FX_STB(10); }
static void fx_stb_r11() { FX_STB(11); }
 
/* 3c - loop - decrement loop counter, and branch on not zero */
static void fx_loop()
{
GSU.vSign = GSU.vZero = --R12;
if( (uint16) R12 != 0 )
R15 = R13;
else
R15++;
 
CLRFLAGS;
}
 
/* 3d - alt1 - set alt1 mode */
static void fx_alt1() { SF(ALT1); CF(B); R15++; }
 
/* 3e - alt2 - set alt2 mode */
static void fx_alt2() { SF(ALT2); CF(B); R15++; }
 
/* 3f - alt3 - set alt3 mode */
static void fx_alt3() { SF(ALT1); SF(ALT2); CF(B); R15++; }
/* 40-4b - ldw (rn) - load word from RAM */
#define FX_LDW(reg) uint32 v; \
GSU.vLastRamAdr = GSU.avReg[reg]; \
v = (uint32)RAM(GSU.avReg[reg]); \
v |= ((uint32)RAM(GSU.avReg[reg]^1))<<8; \
R15++; DREG = v; \
TESTR14; \
CLRFLAGS
static void fx_ldw_r0() { FX_LDW(0); }
static void fx_ldw_r1() { FX_LDW(1); }
static void fx_ldw_r2() { FX_LDW(2); }
static void fx_ldw_r3() { FX_LDW(3); }
static void fx_ldw_r4() { FX_LDW(4); }
static void fx_ldw_r5() { FX_LDW(5); }
static void fx_ldw_r6() { FX_LDW(6); }
static void fx_ldw_r7() { FX_LDW(7); }
static void fx_ldw_r8() { FX_LDW(8); }
static void fx_ldw_r9() { FX_LDW(9); }
static void fx_ldw_r10() { FX_LDW(10); }
static void fx_ldw_r11() { FX_LDW(11); }
 
/* 40-4b(ALT1) - ldb (rn) - load byte */
#define FX_LDB(reg) uint32 v; \
GSU.vLastRamAdr = GSU.avReg[reg]; \
v = (uint32)RAM(GSU.avReg[reg]); \
R15++; DREG = v; \
TESTR14; \
CLRFLAGS
static void fx_ldb_r0() { FX_LDB(0); }
static void fx_ldb_r1() { FX_LDB(1); }
static void fx_ldb_r2() { FX_LDB(2); }
static void fx_ldb_r3() { FX_LDB(3); }
static void fx_ldb_r4() { FX_LDB(4); }
static void fx_ldb_r5() { FX_LDB(5); }
static void fx_ldb_r6() { FX_LDB(6); }
static void fx_ldb_r7() { FX_LDB(7); }
static void fx_ldb_r8() { FX_LDB(8); }
static void fx_ldb_r9() { FX_LDB(9); }
static void fx_ldb_r10() { FX_LDB(10); }
static void fx_ldb_r11() { FX_LDB(11); }
 
/* 4c - plot - plot pixel with R1,R2 as x,y and the color register as the color */
static void fx_plot_2bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v,c;
 
R15++;
CLRFLAGS;
R1++;
 
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
if(GSU.vPlotOptionReg & 0x02)
c = (x^y)&1 ? (uint8)(GSU.vColorReg>>4) : (uint8)GSU.vColorReg;
else
c = (uint8)GSU.vColorReg;
if( !(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return;
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
if(c & 0x01) a[0] |= v;
else a[0] &= ~v;
if(c & 0x02) a[1] |= v;
else a[1] &= ~v;
}
 
/* 2c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */
static void fx_rpix_2bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v;
 
R15++;
CLRFLAGS;
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
 
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
DREG = 0;
DREG |= ((uint32)((a[0] & v) != 0)) << 0;
DREG |= ((uint32)((a[1] & v) != 0)) << 1;
TESTR14;
}
 
/* 4c - plot - plot pixel with R1,R2 as x,y and the color register as the color */
static void fx_plot_4bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v,c;
 
R15++;
CLRFLAGS;
R1++;
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
if(GSU.vPlotOptionReg & 0x02)
c = (x^y)&1 ? (uint8)(GSU.vColorReg>>4) : (uint8)GSU.vColorReg;
else
c = (uint8)GSU.vColorReg;
 
if( !(GSU.vPlotOptionReg & 0x01) && !(c & 0xf)) return;
 
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
if(c & 0x01) a[0x00] |= v;
else a[0x00] &= ~v;
if(c & 0x02) a[0x01] |= v;
else a[0x01] &= ~v;
if(c & 0x04) a[0x10] |= v;
else a[0x10] &= ~v;
if(c & 0x08) a[0x11] |= v;
else a[0x11] &= ~v;
}
 
/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */
static void fx_rpix_4bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v;
 
R15++;
CLRFLAGS;
 
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
 
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
DREG = 0;
DREG |= ((uint32)((a[0x00] & v) != 0)) << 0;
DREG |= ((uint32)((a[0x01] & v) != 0)) << 1;
DREG |= ((uint32)((a[0x10] & v) != 0)) << 2;
DREG |= ((uint32)((a[0x11] & v) != 0)) << 3;
TESTR14;
}
 
/* 8c - plot - plot pixel with R1,R2 as x,y and the color register as the color */
static void fx_plot_8bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v,c;
 
R15++;
CLRFLAGS;
R1++;
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
c = (uint8)GSU.vColorReg;
if( !(GSU.vPlotOptionReg & 0x10) )
{
if( !(GSU.vPlotOptionReg & 0x01) && !(c&0xf)) return;
}
else
if( !(GSU.vPlotOptionReg & 0x01) && !c) return;
 
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
if(c & 0x01) a[0x00] |= v;
else a[0x00] &= ~v;
if(c & 0x02) a[0x01] |= v;
else a[0x01] &= ~v;
if(c & 0x04) a[0x10] |= v;
else a[0x10] &= ~v;
if(c & 0x08) a[0x11] |= v;
else a[0x11] &= ~v;
if(c & 0x10) a[0x20] |= v;
else a[0x20] &= ~v;
if(c & 0x20) a[0x21] |= v;
else a[0x21] &= ~v;
if(c & 0x40) a[0x30] |= v;
else a[0x30] &= ~v;
if(c & 0x80) a[0x31] |= v;
else a[0x31] &= ~v;
}
 
/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */
static void fx_rpix_8bit()
{
uint32 x = USEX8(R1);
uint32 y = USEX8(R2);
uint8 *a;
uint8 v;
 
R15++;
CLRFLAGS;
 
#ifdef CHECK_LIMITS
if(y >= GSU.vScreenHeight) return;
#endif
a = GSU.apvScreen[y >> 3] + GSU.x[x >> 3] + ((y & 7) << 1);
v = 128 >> (x&7);
 
DREG = 0;
DREG |= ((uint32)((a[0x00] & v) != 0)) << 0;
DREG |= ((uint32)((a[0x01] & v) != 0)) << 1;
DREG |= ((uint32)((a[0x10] & v) != 0)) << 2;
DREG |= ((uint32)((a[0x11] & v) != 0)) << 3;
DREG |= ((uint32)((a[0x20] & v) != 0)) << 4;
DREG |= ((uint32)((a[0x21] & v) != 0)) << 5;
DREG |= ((uint32)((a[0x30] & v) != 0)) << 6;
DREG |= ((uint32)((a[0x31] & v) != 0)) << 7;
GSU.vZero = DREG;
TESTR14;
}
 
/* 4o - plot - plot pixel with R1,R2 as x,y and the color register as the color */
static void fx_plot_obj()
{
printf ("ERROR fx_plot_obj called\n");
}
 
/* 4c(ALT1) - rpix - read color of the pixel with R1,R2 as x,y */
static void fx_rpix_obj()
{
printf ("ERROR fx_rpix_obj called\n");
}
 
/* 4d - swap - swap upper and lower byte of a register */
static void fx_swap()
{
uint8 c = (uint8)SREG;
uint8 d = (uint8)(SREG>>8);
uint32 v = (((uint32)c)<<8)|((uint32)d);
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 4e - color - copy source register to color register */
static void fx_color()
{
uint8 c = (uint8)SREG;
if(GSU.vPlotOptionReg & 0x04)
c = (c&0xf0) | (c>>4);
if(GSU.vPlotOptionReg & 0x08)
{
GSU.vColorReg &= 0xf0;
GSU.vColorReg |= c & 0x0f;
}
else
GSU.vColorReg = USEX8(c);
CLRFLAGS;
R15++;
}
 
/* 4e(ALT1) - cmode - set plot option register */
static void fx_cmode()
{
GSU.vPlotOptionReg = SREG;
 
if(GSU.vPlotOptionReg & 0x10)
{
/* OBJ Mode (for drawing into sprites) */
GSU.vScreenHeight = 256;
}
else
GSU.vScreenHeight = GSU.vScreenRealHeight;
 
fx_computeScreenPointers ();
CLRFLAGS;
R15++;
}
 
/* 4f - not - perform exclusive exor with 1 on all bits */
static void fx_not()
{
uint32 v = ~SREG;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 50-5f - add rn - add, register + register */
#define FX_ADD(reg) \
int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]); \
GSU.vCarry = s >= 0x10000; \
GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_add_r0() { FX_ADD(0); }
static void fx_add_r1() { FX_ADD(1); }
static void fx_add_r2() { FX_ADD(2); }
static void fx_add_r3() { FX_ADD(3); }
static void fx_add_r4() { FX_ADD(4); }
static void fx_add_r5() { FX_ADD(5); }
static void fx_add_r6() { FX_ADD(6); }
static void fx_add_r7() { FX_ADD(7); }
static void fx_add_r8() { FX_ADD(8); }
static void fx_add_r9() { FX_ADD(9); }
static void fx_add_r10() { FX_ADD(10); }
static void fx_add_r11() { FX_ADD(11); }
static void fx_add_r12() { FX_ADD(12); }
static void fx_add_r13() { FX_ADD(13); }
static void fx_add_r14() { FX_ADD(14); }
static void fx_add_r15() { FX_ADD(15); }
 
/* 50-5f(ALT1) - adc rn - add with carry, register + register */
#define FX_ADC(reg) \
int32 s = SUSEX16(SREG) + SUSEX16(GSU.avReg[reg]) + SEX16(GSU.vCarry); \
GSU.vCarry = s >= 0x10000; \
GSU.vOverflow = ~(SREG ^ GSU.avReg[reg]) & (GSU.avReg[reg] ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_adc_r0() { FX_ADC(0); }
static void fx_adc_r1() { FX_ADC(1); }
static void fx_adc_r2() { FX_ADC(2); }
static void fx_adc_r3() { FX_ADC(3); }
static void fx_adc_r4() { FX_ADC(4); }
static void fx_adc_r5() { FX_ADC(5); }
static void fx_adc_r6() { FX_ADC(6); }
static void fx_adc_r7() { FX_ADC(7); }
static void fx_adc_r8() { FX_ADC(8); }
static void fx_adc_r9() { FX_ADC(9); }
static void fx_adc_r10() { FX_ADC(10); }
static void fx_adc_r11() { FX_ADC(11); }
static void fx_adc_r12() { FX_ADC(12); }
static void fx_adc_r13() { FX_ADC(13); }
static void fx_adc_r14() { FX_ADC(14); }
static void fx_adc_r15() { FX_ADC(15); }
 
/* 50-5f(ALT2) - add #n - add, register + immediate */
#define FX_ADD_I(imm) \
int32 s = SUSEX16(SREG) + imm; \
GSU.vCarry = s >= 0x10000; \
GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_add_i0() { FX_ADD_I(0); }
static void fx_add_i1() { FX_ADD_I(1); }
static void fx_add_i2() { FX_ADD_I(2); }
static void fx_add_i3() { FX_ADD_I(3); }
static void fx_add_i4() { FX_ADD_I(4); }
static void fx_add_i5() { FX_ADD_I(5); }
static void fx_add_i6() { FX_ADD_I(6); }
static void fx_add_i7() { FX_ADD_I(7); }
static void fx_add_i8() { FX_ADD_I(8); }
static void fx_add_i9() { FX_ADD_I(9); }
static void fx_add_i10() { FX_ADD_I(10); }
static void fx_add_i11() { FX_ADD_I(11); }
static void fx_add_i12() { FX_ADD_I(12); }
static void fx_add_i13() { FX_ADD_I(13); }
static void fx_add_i14() { FX_ADD_I(14); }
static void fx_add_i15() { FX_ADD_I(15); }
 
/* 50-5f(ALT3) - adc #n - add with carry, register + immediate */
#define FX_ADC_I(imm) \
int32 s = SUSEX16(SREG) + imm + SUSEX16(GSU.vCarry); \
GSU.vCarry = s >= 0x10000; \
GSU.vOverflow = ~(SREG ^ imm) & (imm ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_adc_i0() { FX_ADC_I(0); }
static void fx_adc_i1() { FX_ADC_I(1); }
static void fx_adc_i2() { FX_ADC_I(2); }
static void fx_adc_i3() { FX_ADC_I(3); }
static void fx_adc_i4() { FX_ADC_I(4); }
static void fx_adc_i5() { FX_ADC_I(5); }
static void fx_adc_i6() { FX_ADC_I(6); }
static void fx_adc_i7() { FX_ADC_I(7); }
static void fx_adc_i8() { FX_ADC_I(8); }
static void fx_adc_i9() { FX_ADC_I(9); }
static void fx_adc_i10() { FX_ADC_I(10); }
static void fx_adc_i11() { FX_ADC_I(11); }
static void fx_adc_i12() { FX_ADC_I(12); }
static void fx_adc_i13() { FX_ADC_I(13); }
static void fx_adc_i14() { FX_ADC_I(14); }
static void fx_adc_i15() { FX_ADC_I(15); }
 
/* 60-6f - sub rn - subtract, register - register */
#define FX_SUB(reg) \
int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \
GSU.vCarry = s >= 0; \
GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_sub_r0() { FX_SUB(0); }
static void fx_sub_r1() { FX_SUB(1); }
static void fx_sub_r2() { FX_SUB(2); }
static void fx_sub_r3() { FX_SUB(3); }
static void fx_sub_r4() { FX_SUB(4); }
static void fx_sub_r5() { FX_SUB(5); }
static void fx_sub_r6() { FX_SUB(6); }
static void fx_sub_r7() { FX_SUB(7); }
static void fx_sub_r8() { FX_SUB(8); }
static void fx_sub_r9() { FX_SUB(9); }
static void fx_sub_r10() { FX_SUB(10); }
static void fx_sub_r11() { FX_SUB(11); }
static void fx_sub_r12() { FX_SUB(12); }
static void fx_sub_r13() { FX_SUB(13); }
static void fx_sub_r14() { FX_SUB(14); }
static void fx_sub_r15() { FX_SUB(15); }
 
/* 60-6f(ALT1) - sbc rn - subtract with carry, register - register */
#define FX_SBC(reg) \
int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]) - (SUSEX16(GSU.vCarry^1)); \
GSU.vCarry = s >= 0; \
GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_sbc_r0() { FX_SBC(0); }
static void fx_sbc_r1() { FX_SBC(1); }
static void fx_sbc_r2() { FX_SBC(2); }
static void fx_sbc_r3() { FX_SBC(3); }
static void fx_sbc_r4() { FX_SBC(4); }
static void fx_sbc_r5() { FX_SBC(5); }
static void fx_sbc_r6() { FX_SBC(6); }
static void fx_sbc_r7() { FX_SBC(7); }
static void fx_sbc_r8() { FX_SBC(8); }
static void fx_sbc_r9() { FX_SBC(9); }
static void fx_sbc_r10() { FX_SBC(10); }
static void fx_sbc_r11() { FX_SBC(11); }
static void fx_sbc_r12() { FX_SBC(12); }
static void fx_sbc_r13() { FX_SBC(13); }
static void fx_sbc_r14() { FX_SBC(14); }
static void fx_sbc_r15() { FX_SBC(15); }
 
/* 60-6f(ALT2) - sub #n - subtract, register - immediate */
#define FX_SUB_I(imm) \
int32 s = SUSEX16(SREG) - imm; \
GSU.vCarry = s >= 0; \
GSU.vOverflow = (SREG ^ imm) & (SREG ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; DREG = s; \
TESTR14; \
CLRFLAGS
static void fx_sub_i0() { FX_SUB_I(0); }
static void fx_sub_i1() { FX_SUB_I(1); }
static void fx_sub_i2() { FX_SUB_I(2); }
static void fx_sub_i3() { FX_SUB_I(3); }
static void fx_sub_i4() { FX_SUB_I(4); }
static void fx_sub_i5() { FX_SUB_I(5); }
static void fx_sub_i6() { FX_SUB_I(6); }
static void fx_sub_i7() { FX_SUB_I(7); }
static void fx_sub_i8() { FX_SUB_I(8); }
static void fx_sub_i9() { FX_SUB_I(9); }
static void fx_sub_i10() { FX_SUB_I(10); }
static void fx_sub_i11() { FX_SUB_I(11); }
static void fx_sub_i12() { FX_SUB_I(12); }
static void fx_sub_i13() { FX_SUB_I(13); }
static void fx_sub_i14() { FX_SUB_I(14); }
static void fx_sub_i15() { FX_SUB_I(15); }
 
/* 60-6f(ALT3) - cmp rn - compare, register, register */
#define FX_CMP(reg) \
int32 s = SUSEX16(SREG) - SUSEX16(GSU.avReg[reg]); \
GSU.vCarry = s >= 0; \
GSU.vOverflow = (SREG ^ GSU.avReg[reg]) & (SREG ^ s) & 0x8000; \
GSU.vSign = s; \
GSU.vZero = s; \
R15++; \
CLRFLAGS;
static void fx_cmp_r0() { FX_CMP(0); }
static void fx_cmp_r1() { FX_CMP(1); }
static void fx_cmp_r2() { FX_CMP(2); }
static void fx_cmp_r3() { FX_CMP(3); }
static void fx_cmp_r4() { FX_CMP(4); }
static void fx_cmp_r5() { FX_CMP(5); }
static void fx_cmp_r6() { FX_CMP(6); }
static void fx_cmp_r7() { FX_CMP(7); }
static void fx_cmp_r8() { FX_CMP(8); }
static void fx_cmp_r9() { FX_CMP(9); }
static void fx_cmp_r10() { FX_CMP(10); }
static void fx_cmp_r11() { FX_CMP(11); }
static void fx_cmp_r12() { FX_CMP(12); }
static void fx_cmp_r13() { FX_CMP(13); }
static void fx_cmp_r14() { FX_CMP(14); }
static void fx_cmp_r15() { FX_CMP(15); }
 
/* 70 - merge - R7 as upper byte, R8 as lower byte (used for texture-mapping) */
static void fx_merge()
{
uint32 v = (R7&0xff00) | ((R8&0xff00)>>8);
R15++; DREG = v;
GSU.vOverflow = (v & 0xc0c0) << 16;
GSU.vZero = !(v & 0xf0f0);
GSU.vSign = ((v | (v<<8)) & 0x8000);
GSU.vCarry = (v & 0xe0e0) != 0;
TESTR14;
CLRFLAGS;
}
 
/* 71-7f - and rn - reister & register */
#define FX_AND(reg) \
uint32 v = SREG & GSU.avReg[reg]; \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_and_r1() { FX_AND(1); }
static void fx_and_r2() { FX_AND(2); }
static void fx_and_r3() { FX_AND(3); }
static void fx_and_r4() { FX_AND(4); }
static void fx_and_r5() { FX_AND(5); }
static void fx_and_r6() { FX_AND(6); }
static void fx_and_r7() { FX_AND(7); }
static void fx_and_r8() { FX_AND(8); }
static void fx_and_r9() { FX_AND(9); }
static void fx_and_r10() { FX_AND(10); }
static void fx_and_r11() { FX_AND(11); }
static void fx_and_r12() { FX_AND(12); }
static void fx_and_r13() { FX_AND(13); }
static void fx_and_r14() { FX_AND(14); }
static void fx_and_r15() { FX_AND(15); }
 
/* 71-7f(ALT1) - bic rn - reister & ~register */
#define FX_BIC(reg) \
uint32 v = SREG & ~GSU.avReg[reg]; \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_bic_r1() { FX_BIC(1); }
static void fx_bic_r2() { FX_BIC(2); }
static void fx_bic_r3() { FX_BIC(3); }
static void fx_bic_r4() { FX_BIC(4); }
static void fx_bic_r5() { FX_BIC(5); }
static void fx_bic_r6() { FX_BIC(6); }
static void fx_bic_r7() { FX_BIC(7); }
static void fx_bic_r8() { FX_BIC(8); }
static void fx_bic_r9() { FX_BIC(9); }
static void fx_bic_r10() { FX_BIC(10); }
static void fx_bic_r11() { FX_BIC(11); }
static void fx_bic_r12() { FX_BIC(12); }
static void fx_bic_r13() { FX_BIC(13); }
static void fx_bic_r14() { FX_BIC(14); }
static void fx_bic_r15() { FX_BIC(15); }
 
/* 71-7f(ALT2) - and #n - reister & immediate */
#define FX_AND_I(imm) \
uint32 v = SREG & imm; \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_and_i1() { FX_AND_I(1); }
static void fx_and_i2() { FX_AND_I(2); }
static void fx_and_i3() { FX_AND_I(3); }
static void fx_and_i4() { FX_AND_I(4); }
static void fx_and_i5() { FX_AND_I(5); }
static void fx_and_i6() { FX_AND_I(6); }
static void fx_and_i7() { FX_AND_I(7); }
static void fx_and_i8() { FX_AND_I(8); }
static void fx_and_i9() { FX_AND_I(9); }
static void fx_and_i10() { FX_AND_I(10); }
static void fx_and_i11() { FX_AND_I(11); }
static void fx_and_i12() { FX_AND_I(12); }
static void fx_and_i13() { FX_AND_I(13); }
static void fx_and_i14() { FX_AND_I(14); }
static void fx_and_i15() { FX_AND_I(15); }
 
/* 71-7f(ALT3) - bic #n - reister & ~immediate */
#define FX_BIC_I(imm) \
uint32 v = SREG & ~imm; \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_bic_i1() { FX_BIC_I(1); }
static void fx_bic_i2() { FX_BIC_I(2); }
static void fx_bic_i3() { FX_BIC_I(3); }
static void fx_bic_i4() { FX_BIC_I(4); }
static void fx_bic_i5() { FX_BIC_I(5); }
static void fx_bic_i6() { FX_BIC_I(6); }
static void fx_bic_i7() { FX_BIC_I(7); }
static void fx_bic_i8() { FX_BIC_I(8); }
static void fx_bic_i9() { FX_BIC_I(9); }
static void fx_bic_i10() { FX_BIC_I(10); }
static void fx_bic_i11() { FX_BIC_I(11); }
static void fx_bic_i12() { FX_BIC_I(12); }
static void fx_bic_i13() { FX_BIC_I(13); }
static void fx_bic_i14() { FX_BIC_I(14); }
static void fx_bic_i15() { FX_BIC_I(15); }
 
/* 80-8f - mult rn - 8 bit to 16 bit signed multiply, register * register */
#define FX_MULT(reg) \
uint32 v = (uint32)(SEX8(SREG) * SEX8(GSU.avReg[reg])); \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_mult_r0() { FX_MULT(0); }
static void fx_mult_r1() { FX_MULT(1); }
static void fx_mult_r2() { FX_MULT(2); }
static void fx_mult_r3() { FX_MULT(3); }
static void fx_mult_r4() { FX_MULT(4); }
static void fx_mult_r5() { FX_MULT(5); }
static void fx_mult_r6() { FX_MULT(6); }
static void fx_mult_r7() { FX_MULT(7); }
static void fx_mult_r8() { FX_MULT(8); }
static void fx_mult_r9() { FX_MULT(9); }
static void fx_mult_r10() { FX_MULT(10); }
static void fx_mult_r11() { FX_MULT(11); }
static void fx_mult_r12() { FX_MULT(12); }
static void fx_mult_r13() { FX_MULT(13); }
static void fx_mult_r14() { FX_MULT(14); }
static void fx_mult_r15() { FX_MULT(15); }
 
/* 80-8f(ALT1) - umult rn - 8 bit to 16 bit unsigned multiply, register * register */
#define FX_UMULT(reg) \
uint32 v = USEX8(SREG) * USEX8(GSU.avReg[reg]); \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_umult_r0() { FX_UMULT(0); }
static void fx_umult_r1() { FX_UMULT(1); }
static void fx_umult_r2() { FX_UMULT(2); }
static void fx_umult_r3() { FX_UMULT(3); }
static void fx_umult_r4() { FX_UMULT(4); }
static void fx_umult_r5() { FX_UMULT(5); }
static void fx_umult_r6() { FX_UMULT(6); }
static void fx_umult_r7() { FX_UMULT(7); }
static void fx_umult_r8() { FX_UMULT(8); }
static void fx_umult_r9() { FX_UMULT(9); }
static void fx_umult_r10() { FX_UMULT(10); }
static void fx_umult_r11() { FX_UMULT(11); }
static void fx_umult_r12() { FX_UMULT(12); }
static void fx_umult_r13() { FX_UMULT(13); }
static void fx_umult_r14() { FX_UMULT(14); }
static void fx_umult_r15() { FX_UMULT(15); }
/* 80-8f(ALT2) - mult #n - 8 bit to 16 bit signed multiply, register * immediate */
#define FX_MULT_I(imm) \
uint32 v = (uint32) (SEX8(SREG) * ((int32)imm)); \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_mult_i0() { FX_MULT_I(0); }
static void fx_mult_i1() { FX_MULT_I(1); }
static void fx_mult_i2() { FX_MULT_I(2); }
static void fx_mult_i3() { FX_MULT_I(3); }
static void fx_mult_i4() { FX_MULT_I(4); }
static void fx_mult_i5() { FX_MULT_I(5); }
static void fx_mult_i6() { FX_MULT_I(6); }
static void fx_mult_i7() { FX_MULT_I(7); }
static void fx_mult_i8() { FX_MULT_I(8); }
static void fx_mult_i9() { FX_MULT_I(9); }
static void fx_mult_i10() { FX_MULT_I(10); }
static void fx_mult_i11() { FX_MULT_I(11); }
static void fx_mult_i12() { FX_MULT_I(12); }
static void fx_mult_i13() { FX_MULT_I(13); }
static void fx_mult_i14() { FX_MULT_I(14); }
static void fx_mult_i15() { FX_MULT_I(15); }
/* 80-8f(ALT3) - umult #n - 8 bit to 16 bit unsigned multiply, register * immediate */
#define FX_UMULT_I(imm) \
uint32 v = USEX8(SREG) * ((uint32)imm); \
R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_umult_i0() { FX_UMULT_I(0); }
static void fx_umult_i1() { FX_UMULT_I(1); }
static void fx_umult_i2() { FX_UMULT_I(2); }
static void fx_umult_i3() { FX_UMULT_I(3); }
static void fx_umult_i4() { FX_UMULT_I(4); }
static void fx_umult_i5() { FX_UMULT_I(5); }
static void fx_umult_i6() { FX_UMULT_I(6); }
static void fx_umult_i7() { FX_UMULT_I(7); }
static void fx_umult_i8() { FX_UMULT_I(8); }
static void fx_umult_i9() { FX_UMULT_I(9); }
static void fx_umult_i10() { FX_UMULT_I(10); }
static void fx_umult_i11() { FX_UMULT_I(11); }
static void fx_umult_i12() { FX_UMULT_I(12); }
static void fx_umult_i13() { FX_UMULT_I(13); }
static void fx_umult_i14() { FX_UMULT_I(14); }
static void fx_umult_i15() { FX_UMULT_I(15); }
/* 90 - sbk - store word to last accessed RAM address */
static void fx_sbk()
{
RAM(GSU.vLastRamAdr) = (uint8)SREG;
RAM(GSU.vLastRamAdr^1) = (uint8)(SREG>>8);
CLRFLAGS;
R15++;
}
 
/* 91-94 - link #n - R11 = R15 + immediate */
#define FX_LINK_I(lkn) R11 = R15 + lkn; CLRFLAGS; R15++
static void fx_link_i1() { FX_LINK_I(1); }
static void fx_link_i2() { FX_LINK_I(2); }
static void fx_link_i3() { FX_LINK_I(3); }
static void fx_link_i4() { FX_LINK_I(4); }
 
/* 95 - sex - sign extend 8 bit to 16 bit */
static void fx_sex()
{
uint32 v = (uint32)SEX8(SREG);
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 96 - asr - aritmetric shift right by one */
static void fx_asr()
{
uint32 v;
GSU.vCarry = SREG & 1;
v = (uint32)(SEX16(SREG)>>1);
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 96(ALT1) - div2 - aritmetric shift right by one */
static void fx_div2()
{
uint32 v;
int32 s = SEX16(SREG);
GSU.vCarry = s & 1;
if(s == -1)
v = 0;
else
v = (uint32)(s>>1);
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 97 - ror - rotate right by one */
static void fx_ror()
{
uint32 v = (USEX16(SREG)>>1) | (GSU.vCarry<<15);
GSU.vCarry = SREG & 1;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
TESTR14;
CLRFLAGS;
}
 
/* 98-9d - jmp rn - jump to address of register */
#define FX_JMP(reg) \
R15 = GSU.avReg[reg]; \
CLRFLAGS;
static void fx_jmp_r8() { FX_JMP(8); }
static void fx_jmp_r9() { FX_JMP(9); }
static void fx_jmp_r10() { FX_JMP(10); }
static void fx_jmp_r11() { FX_JMP(11); }
static void fx_jmp_r12() { FX_JMP(12); }
static void fx_jmp_r13() { FX_JMP(13); }
 
/* 98-9d(ALT1) - ljmp rn - set program bank to source register and jump to address of register */
#define FX_LJMP(reg) \
GSU.vPrgBankReg = GSU.avReg[reg] & 0x7f; \
GSU.pvPrgBank = GSU.apvRomBank[GSU.vPrgBankReg]; \
R15 = SREG; \
GSU.bCacheActive = FALSE; fx_cache(); R15--;
static void fx_ljmp_r8() { FX_LJMP(8); }
static void fx_ljmp_r9() { FX_LJMP(9); }
static void fx_ljmp_r10() { FX_LJMP(10); }
static void fx_ljmp_r11() { FX_LJMP(11); }
static void fx_ljmp_r12() { FX_LJMP(12); }
static void fx_ljmp_r13() { FX_LJMP(13); }
 
/* 9e - lob - set upper byte to zero (keep low byte) */
static void fx_lob()
{
uint32 v = USEX8(SREG);
R15++; DREG = v;
GSU.vSign = v<<8;
GSU.vZero = v<<8;
TESTR14;
CLRFLAGS;
}
 
/* 9f - fmult - 16 bit to 32 bit signed multiplication, upper 16 bits only */
static void fx_fmult()
{
uint32 v;
uint32 c = (uint32) (SEX16(SREG) * SEX16(R6));
v = c >> 16;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
GSU.vCarry = (c >> 15) & 1;
TESTR14;
CLRFLAGS;
}
 
/* 9f(ALT1) - lmult - 16 bit to 32 bit signed multiplication */
static void fx_lmult()
{
uint32 v;
uint32 c = (uint32) (SEX16(SREG) * SEX16(R6));
R4 = c;
v = c >> 16;
R15++; DREG = v;
GSU.vSign = v;
GSU.vZero = v;
/* XXX R6 or R4? */
GSU.vCarry = (R4 >> 15) & 1; /* should it be bit 15 of R4 instead? */
TESTR14;
CLRFLAGS;
}
 
/* a0-af - ibt rn,#pp - immediate byte transfer */
#define FX_IBT(reg) \
uint8 v = PIPE; R15++; \
FETCHPIPE; R15++; \
GSU.avReg[reg] = SEX8(v); \
CLRFLAGS;
static void fx_ibt_r0() { FX_IBT(0); }
static void fx_ibt_r1() { FX_IBT(1); }
static void fx_ibt_r2() { FX_IBT(2); }
static void fx_ibt_r3() { FX_IBT(3); }
static void fx_ibt_r4() { FX_IBT(4); }
static void fx_ibt_r5() { FX_IBT(5); }
static void fx_ibt_r6() { FX_IBT(6); }
static void fx_ibt_r7() { FX_IBT(7); }
static void fx_ibt_r8() { FX_IBT(8); }
static void fx_ibt_r9() { FX_IBT(9); }
static void fx_ibt_r10() { FX_IBT(10); }
static void fx_ibt_r11() { FX_IBT(11); }
static void fx_ibt_r12() { FX_IBT(12); }
static void fx_ibt_r13() { FX_IBT(13); }
static void fx_ibt_r14() { FX_IBT(14); READR14; }
static void fx_ibt_r15() { FX_IBT(15); }
 
/* a0-af(ALT1) - lms rn,(yy) - load word from RAM (short address) */
#define FX_LMS(reg) \
GSU.vLastRamAdr = ((uint32)PIPE) << 1; \
R15++; FETCHPIPE; R15++; \
GSU.avReg[reg] = (uint32)RAM(GSU.vLastRamAdr); \
GSU.avReg[reg] |= ((uint32)RAM(GSU.vLastRamAdr+1))<<8; \
CLRFLAGS;
static void fx_lms_r0() { FX_LMS(0); }
static void fx_lms_r1() { FX_LMS(1); }
static void fx_lms_r2() { FX_LMS(2); }
static void fx_lms_r3() { FX_LMS(3); }
static void fx_lms_r4() { FX_LMS(4); }
static void fx_lms_r5() { FX_LMS(5); }
static void fx_lms_r6() { FX_LMS(6); }
static void fx_lms_r7() { FX_LMS(7); }
static void fx_lms_r8() { FX_LMS(8); }
static void fx_lms_r9() { FX_LMS(9); }
static void fx_lms_r10() { FX_LMS(10); }
static void fx_lms_r11() { FX_LMS(11); }
static void fx_lms_r12() { FX_LMS(12); }
static void fx_lms_r13() { FX_LMS(13); }
static void fx_lms_r14() { FX_LMS(14); READR14; }
static void fx_lms_r15() { FX_LMS(15); }
 
/* a0-af(ALT2) - sms (yy),rn - store word in RAM (short address) */
/* If rn == r15, is the value of r15 before or after the extra byte is read? */
#define FX_SMS(reg) \
uint32 v = GSU.avReg[reg]; \
GSU.vLastRamAdr = ((uint32)PIPE) << 1; \
R15++; FETCHPIPE; \
RAM(GSU.vLastRamAdr) = (uint8)v; \
RAM(GSU.vLastRamAdr+1) = (uint8)(v>>8); \
CLRFLAGS; R15++;
static void fx_sms_r0() { FX_SMS(0); }
static void fx_sms_r1() { FX_SMS(1); }
static void fx_sms_r2() { FX_SMS(2); }
static void fx_sms_r3() { FX_SMS(3); }
static void fx_sms_r4() { FX_SMS(4); }
static void fx_sms_r5() { FX_SMS(5); }
static void fx_sms_r6() { FX_SMS(6); }
static void fx_sms_r7() { FX_SMS(7); }
static void fx_sms_r8() { FX_SMS(8); }
static void fx_sms_r9() { FX_SMS(9); }
static void fx_sms_r10() { FX_SMS(10); }
static void fx_sms_r11() { FX_SMS(11); }
static void fx_sms_r12() { FX_SMS(12); }
static void fx_sms_r13() { FX_SMS(13); }
static void fx_sms_r14() { FX_SMS(14); }
static void fx_sms_r15() { FX_SMS(15); }
 
/* b0-bf - from rn - set source register */
/* b0-bf(B) - moves rn - move register to register, and set flags, (if B flag is set) */
#define FX_FROM(reg) \
if(TF(B)) { uint32 v = GSU.avReg[reg]; R15++; DREG = v; \
GSU.vOverflow = (v&0x80) << 16; GSU.vSign = v; GSU.vZero = v; TESTR14; CLRFLAGS; } \
else { GSU.pvSreg = &GSU.avReg[reg]; R15++; }
static void fx_from_r0() { FX_FROM(0); }
static void fx_from_r1() { FX_FROM(1); }
static void fx_from_r2() { FX_FROM(2); }
static void fx_from_r3() { FX_FROM(3); }
static void fx_from_r4() { FX_FROM(4); }
static void fx_from_r5() { FX_FROM(5); }
static void fx_from_r6() { FX_FROM(6); }
static void fx_from_r7() { FX_FROM(7); }
static void fx_from_r8() { FX_FROM(8); }
static void fx_from_r9() { FX_FROM(9); }
static void fx_from_r10() { FX_FROM(10); }
static void fx_from_r11() { FX_FROM(11); }
static void fx_from_r12() { FX_FROM(12); }
static void fx_from_r13() { FX_FROM(13); }
static void fx_from_r14() { FX_FROM(14); }
static void fx_from_r15() { FX_FROM(15); }
 
/* c0 - hib - move high-byte to low-byte */
static void fx_hib()
{
uint32 v = USEX8(SREG>>8);
R15++; DREG = v;
GSU.vSign = v<<8;
GSU.vZero = v<<8;
TESTR14;
CLRFLAGS;
}
 
/* c1-cf - or rn */
#define FX_OR(reg) \
uint32 v = SREG | GSU.avReg[reg]; R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_or_r1() { FX_OR(1); }
static void fx_or_r2() { FX_OR(2); }
static void fx_or_r3() { FX_OR(3); }
static void fx_or_r4() { FX_OR(4); }
static void fx_or_r5() { FX_OR(5); }
static void fx_or_r6() { FX_OR(6); }
static void fx_or_r7() { FX_OR(7); }
static void fx_or_r8() { FX_OR(8); }
static void fx_or_r9() { FX_OR(9); }
static void fx_or_r10() { FX_OR(10); }
static void fx_or_r11() { FX_OR(11); }
static void fx_or_r12() { FX_OR(12); }
static void fx_or_r13() { FX_OR(13); }
static void fx_or_r14() { FX_OR(14); }
static void fx_or_r15() { FX_OR(15); }
 
/* c1-cf(ALT1) - xor rn */
#define FX_XOR(reg) \
uint32 v = SREG ^ GSU.avReg[reg]; R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_xor_r1() { FX_XOR(1); }
static void fx_xor_r2() { FX_XOR(2); }
static void fx_xor_r3() { FX_XOR(3); }
static void fx_xor_r4() { FX_XOR(4); }
static void fx_xor_r5() { FX_XOR(5); }
static void fx_xor_r6() { FX_XOR(6); }
static void fx_xor_r7() { FX_XOR(7); }
static void fx_xor_r8() { FX_XOR(8); }
static void fx_xor_r9() { FX_XOR(9); }
static void fx_xor_r10() { FX_XOR(10); }
static void fx_xor_r11() { FX_XOR(11); }
static void fx_xor_r12() { FX_XOR(12); }
static void fx_xor_r13() { FX_XOR(13); }
static void fx_xor_r14() { FX_XOR(14); }
static void fx_xor_r15() { FX_XOR(15); }
 
/* c1-cf(ALT2) - or #n */
#define FX_OR_I(imm) \
uint32 v = SREG | imm; R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_or_i1() { FX_OR_I(1); }
static void fx_or_i2() { FX_OR_I(2); }
static void fx_or_i3() { FX_OR_I(3); }
static void fx_or_i4() { FX_OR_I(4); }
static void fx_or_i5() { FX_OR_I(5); }
static void fx_or_i6() { FX_OR_I(6); }
static void fx_or_i7() { FX_OR_I(7); }
static void fx_or_i8() { FX_OR_I(8); }
static void fx_or_i9() { FX_OR_I(9); }
static void fx_or_i10() { FX_OR_I(10); }
static void fx_or_i11() { FX_OR_I(11); }
static void fx_or_i12() { FX_OR_I(12); }
static void fx_or_i13() { FX_OR_I(13); }
static void fx_or_i14() { FX_OR_I(14); }
static void fx_or_i15() { FX_OR_I(15); }
 
/* c1-cf(ALT3) - xor #n */
#define FX_XOR_I(imm) \
uint32 v = SREG ^ imm; R15++; DREG = v; \
GSU.vSign = v; \
GSU.vZero = v; \
TESTR14; \
CLRFLAGS;
static void fx_xor_i1() { FX_XOR_I(1); }
static void fx_xor_i2() { FX_XOR_I(2); }
static void fx_xor_i3() { FX_XOR_I(3); }
static void fx_xor_i4() { FX_XOR_I(4); }
static void fx_xor_i5() { FX_XOR_I(5); }
static void fx_xor_i6() { FX_XOR_I(6); }
static void fx_xor_i7() { FX_XOR_I(7); }
static void fx_xor_i8() { FX_XOR_I(8); }
static void fx_xor_i9() { FX_XOR_I(9); }
static void fx_xor_i10() { FX_XOR_I(10); }
static void fx_xor_i11() { FX_XOR_I(11); }
static void fx_xor_i12() { FX_XOR_I(12); }
static void fx_xor_i13() { FX_XOR_I(13); }
static void fx_xor_i14() { FX_XOR_I(14); }
static void fx_xor_i15() { FX_XOR_I(15); }
 
/* d0-de - inc rn - increase by one */
#define FX_INC(reg) \
GSU.avReg[reg] += 1; \
GSU.vSign = GSU.avReg[reg]; \
GSU.vZero = GSU.avReg[reg]; \
CLRFLAGS; R15++;
static void fx_inc_r0() { FX_INC(0); }
static void fx_inc_r1() { FX_INC(1); }
static void fx_inc_r2() { FX_INC(2); }
static void fx_inc_r3() { FX_INC(3); }
static void fx_inc_r4() { FX_INC(4); }
static void fx_inc_r5() { FX_INC(5); }
static void fx_inc_r6() { FX_INC(6); }
static void fx_inc_r7() { FX_INC(7); }
static void fx_inc_r8() { FX_INC(8); }
static void fx_inc_r9() { FX_INC(9); }
static void fx_inc_r10() { FX_INC(10); }
static void fx_inc_r11() { FX_INC(11); }
static void fx_inc_r12() { FX_INC(12); }
static void fx_inc_r13() { FX_INC(13); }
static void fx_inc_r14() { FX_INC(14); READR14; }
 
/* df - getc - transfer ROM buffer to color register */
static void fx_getc()
{
#ifndef FX_DO_ROMBUFFER
uint8 c;
c = ROM(R14);
#else
uint8 c = GSU.vRomBuffer;
#endif
if(GSU.vPlotOptionReg & 0x04)
c = (c&0xf0) | (c>>4);
if(GSU.vPlotOptionReg & 0x08)
{
GSU.vColorReg &= 0xf0;
GSU.vColorReg |= c & 0x0f;
}
else
GSU.vColorReg = USEX8(c);
CLRFLAGS;
R15++;
}
 
/* df(ALT2) - ramb - set current RAM bank */
static void fx_ramb()
{
GSU.vRamBankReg = SREG & (FX_RAM_BANKS-1);
GSU.pvRamBank = GSU.apvRamBank[GSU.vRamBankReg & 0x3];
CLRFLAGS;
R15++;
}
 
/* df(ALT3) - romb - set current ROM bank */
static void fx_romb()
{
GSU.vRomBankReg = USEX8(SREG) & 0x7f;
GSU.pvRomBank = GSU.apvRomBank[GSU.vRomBankReg];
CLRFLAGS;
R15++;
}
 
/* e0-ee - dec rn - decrement by one */
#define FX_DEC(reg) \
GSU.avReg[reg] -= 1; \
GSU.vSign = GSU.avReg[reg]; \
GSU.vZero = GSU.avReg[reg]; \
CLRFLAGS; R15++;
static void fx_dec_r0() { FX_DEC(0); }
static void fx_dec_r1() { FX_DEC(1); }
static void fx_dec_r2() { FX_DEC(2); }
static void fx_dec_r3() { FX_DEC(3); }
static void fx_dec_r4() { FX_DEC(4); }
static void fx_dec_r5() { FX_DEC(5); }
static void fx_dec_r6() { FX_DEC(6); }
static void fx_dec_r7() { FX_DEC(7); }
static void fx_dec_r8() { FX_DEC(8); }
static void fx_dec_r9() { FX_DEC(9); }
static void fx_dec_r10() { FX_DEC(10); }
static void fx_dec_r11() { FX_DEC(11); }
static void fx_dec_r12() { FX_DEC(12); }
static void fx_dec_r13() { FX_DEC(13); }
static void fx_dec_r14() { FX_DEC(14); READR14; }
 
/* ef - getb - get byte from ROM at address R14 */
static void fx_getb()
{
uint32 v;
#ifndef FX_DO_ROMBUFFER
v = (uint32)ROM(R14);
#else
v = (uint32)GSU.vRomBuffer;
#endif
R15++; DREG = v;
TESTR14;
CLRFLAGS;
}
 
/* ef(ALT1) - getbh - get high-byte from ROM at address R14 */
static void fx_getbh()
{
uint32 v;
#ifndef FX_DO_ROMBUFFER
uint32 c;
c = (uint32)ROM(R14);
#else
uint32 c = USEX8(GSU.vRomBuffer);
#endif
v = USEX8(SREG) | (c<<8);
R15++; DREG = v;
TESTR14;
CLRFLAGS;
}
 
/* ef(ALT2) - getbl - get low-byte from ROM at address R14 */
static void fx_getbl()
{
uint32 v;
#ifndef FX_DO_ROMBUFFER
uint32 c;
c = (uint32)ROM(R14);
#else
uint32 c = USEX8(GSU.vRomBuffer);
#endif
v = (SREG & 0xff00) | c;
R15++; DREG = v;
TESTR14;
CLRFLAGS;
}
 
/* ef(ALT3) - getbs - get sign extended byte from ROM at address R14 */
static void fx_getbs()
{
uint32 v;
#ifndef FX_DO_ROMBUFFER
int8 c;
c = ROM(R14);
v = SEX8(c);
#else
v = SEX8(GSU.vRomBuffer);
#endif
R15++; DREG = v;
TESTR14;
CLRFLAGS;
}
 
/* f0-ff - iwt rn,#xx - immediate word transfer to register */
#define FX_IWT(reg) \
uint32 v = PIPE; R15++; FETCHPIPE; R15++; \
v |= USEX8(PIPE) << 8; FETCHPIPE; R15++; \
GSU.avReg[reg] = v; \
CLRFLAGS;
static void fx_iwt_r0() { FX_IWT(0); }
static void fx_iwt_r1() { FX_IWT(1); }
static void fx_iwt_r2() { FX_IWT(2); }
static void fx_iwt_r3() { FX_IWT(3); }
static void fx_iwt_r4() { FX_IWT(4); }
static void fx_iwt_r5() { FX_IWT(5); }
static void fx_iwt_r6() { FX_IWT(6); }
static void fx_iwt_r7() { FX_IWT(7); }
static void fx_iwt_r8() { FX_IWT(8); }
static void fx_iwt_r9() { FX_IWT(9); }
static void fx_iwt_r10() { FX_IWT(10); }
static void fx_iwt_r11() { FX_IWT(11); }
static void fx_iwt_r12() { FX_IWT(12); }
static void fx_iwt_r13() { FX_IWT(13); }
static void fx_iwt_r14() { FX_IWT(14); READR14; }
static void fx_iwt_r15() { FX_IWT(15); }
 
/* f0-ff(ALT1) - lm rn,(xx) - load word from RAM */
#define FX_LM(reg) \
GSU.vLastRamAdr = PIPE; R15++; FETCHPIPE; R15++; \
GSU.vLastRamAdr |= USEX8(PIPE) << 8; FETCHPIPE; R15++; \
GSU.avReg[reg] = RAM(GSU.vLastRamAdr); \
GSU.avReg[reg] |= USEX8(RAM(GSU.vLastRamAdr^1)) << 8; \
CLRFLAGS;
static void fx_lm_r0() { FX_LM(0); }
static void fx_lm_r1() { FX_LM(1); }
static void fx_lm_r2() { FX_LM(2); }
static void fx_lm_r3() { FX_LM(3); }
static void fx_lm_r4() { FX_LM(4); }
static void fx_lm_r5() { FX_LM(5); }
static void fx_lm_r6() { FX_LM(6); }
static void fx_lm_r7() { FX_LM(7); }
static void fx_lm_r8() { FX_LM(8); }
static void fx_lm_r9() { FX_LM(9); }
static void fx_lm_r10() { FX_LM(10); }
static void fx_lm_r11() { FX_LM(11); }
static void fx_lm_r12() { FX_LM(12); }
static void fx_lm_r13() { FX_LM(13); }
static void fx_lm_r14() { FX_LM(14); READR14; }
static void fx_lm_r15() { FX_LM(15); }
 
/* f0-ff(ALT2) - sm (xx),rn - store word in RAM */
/* If rn == r15, is the value of r15 before or after the extra bytes are read? */
#define FX_SM(reg) \
uint32 v = GSU.avReg[reg]; \
GSU.vLastRamAdr = PIPE; R15++; FETCHPIPE; R15++; \
GSU.vLastRamAdr |= USEX8(PIPE) << 8; FETCHPIPE; \
RAM(GSU.vLastRamAdr) = (uint8)v; \
RAM(GSU.vLastRamAdr^1) = (uint8)(v>>8); \
CLRFLAGS; R15++;
static void fx_sm_r0() { FX_SM(0); }
static void fx_sm_r1() { FX_SM(1); }
static void fx_sm_r2() { FX_SM(2); }
static void fx_sm_r3() { FX_SM(3); }
static void fx_sm_r4() { FX_SM(4); }
static void fx_sm_r5() { FX_SM(5); }
static void fx_sm_r6() { FX_SM(6); }
static void fx_sm_r7() { FX_SM(7); }
static void fx_sm_r8() { FX_SM(8); }
static void fx_sm_r9() { FX_SM(9); }
static void fx_sm_r10() { FX_SM(10); }
static void fx_sm_r11() { FX_SM(11); }
static void fx_sm_r12() { FX_SM(12); }
static void fx_sm_r13() { FX_SM(13); }
static void fx_sm_r14() { FX_SM(14); }
static void fx_sm_r15() { FX_SM(15); }
 
/*** GSU executions functions ***/
 
static uint32 fx_run(uint32 nInstructions)
{
GSU.vCounter = nInstructions;
READR14;
while( TF(G) && (GSU.vCounter-- > 0) )
FX_STEP;
/*
#ifndef FX_ADDRESS_CHECK
GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16);
#endif
*/
return (nInstructions - GSU.vInstCount);
}
 
static uint32 fx_run_to_breakpoint(uint32 nInstructions)
{
uint32 vCounter = 0;
while(TF(G) && vCounter < nInstructions)
{
vCounter++;
FX_STEP;
if(USEX16(R15) == GSU.vBreakPoint)
{
GSU.vErrorCode = FX_BREAKPOINT;
break;
}
}
/*
#ifndef FX_ADDRESS_CHECK
GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16);
#endif
*/
return vCounter;
}
 
static uint32 fx_step_over(uint32 nInstructions)
{
uint32 vCounter = 0;
while(TF(G) && vCounter < nInstructions)
{
vCounter++;
FX_STEP;
if(USEX16(R15) == GSU.vBreakPoint)
{
GSU.vErrorCode = FX_BREAKPOINT;
break;
}
if(USEX16(R15) == GSU.vStepPoint)
break;
}
/*
#ifndef FX_ADDRESS_CHECK
GSU.vPipeAdr = USEX16(R15-1) | (USEX8(GSU.vPrgBankReg)<<16);
#endif
*/
return vCounter;
}
 
#ifdef FX_FUNCTION_TABLE
uint32 (*FX_FUNCTION_TABLE[])(uint32) =
#else
uint32 (*fx_apfFunctionTable[])(uint32) =
#endif
{
&fx_run,
&fx_run_to_breakpoint,
&fx_step_over,
};
 
/*** Special table for the different plot configurations ***/
 
#ifdef FX_PLOT_TABLE
void (*FX_PLOT_TABLE[])() =
#else
void (*fx_apfPlotTable[])() =
#endif
{
&fx_plot_2bit, &fx_plot_4bit, &fx_plot_4bit, &fx_plot_8bit, &fx_plot_obj,
&fx_rpix_2bit, &fx_rpix_4bit, &fx_rpix_4bit, &fx_rpix_8bit, &fx_rpix_obj,
};
 
/*** Opcode table ***/
 
#ifdef FX_OPCODE_TABLE
void (*FX_OPCODE_TABLE[])() =
#else
void (*fx_apfOpcodeTable[])() =
#endif
{
/*
* ALT0 Table
*/
/* 00 - 0f */
&fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt,
&fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs,
/* 10 - 1f */
&fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7,
&fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15,
/* 20 - 2f */
&fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7,
&fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15,
/* 30 - 3f */
&fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7,
&fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3,
/* 40 - 4f */
&fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7,
&fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit,&fx_swap, &fx_color, &fx_not,
/* 50 - 5f */
&fx_add_r0, &fx_add_r1, &fx_add_r2, &fx_add_r3, &fx_add_r4, &fx_add_r5, &fx_add_r6, &fx_add_r7,
&fx_add_r8, &fx_add_r9, &fx_add_r10, &fx_add_r11, &fx_add_r12, &fx_add_r13, &fx_add_r14, &fx_add_r15,
/* 60 - 6f */
&fx_sub_r0, &fx_sub_r1, &fx_sub_r2, &fx_sub_r3, &fx_sub_r4, &fx_sub_r5, &fx_sub_r6, &fx_sub_r7,
&fx_sub_r8, &fx_sub_r9, &fx_sub_r10, &fx_sub_r11, &fx_sub_r12, &fx_sub_r13, &fx_sub_r14, &fx_sub_r15,
/* 70 - 7f */
&fx_merge, &fx_and_r1, &fx_and_r2, &fx_and_r3, &fx_and_r4, &fx_and_r5, &fx_and_r6, &fx_and_r7,
&fx_and_r8, &fx_and_r9, &fx_and_r10, &fx_and_r11, &fx_and_r12, &fx_and_r13, &fx_and_r14, &fx_and_r15,
/* 80 - 8f */
&fx_mult_r0, &fx_mult_r1, &fx_mult_r2, &fx_mult_r3, &fx_mult_r4, &fx_mult_r5, &fx_mult_r6, &fx_mult_r7,
&fx_mult_r8, &fx_mult_r9, &fx_mult_r10, &fx_mult_r11, &fx_mult_r12, &fx_mult_r13, &fx_mult_r14, &fx_mult_r15,
/* 90 - 9f */
&fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror,
&fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult,
/* a0 - af */
&fx_ibt_r0, &fx_ibt_r1, &fx_ibt_r2, &fx_ibt_r3, &fx_ibt_r4, &fx_ibt_r5, &fx_ibt_r6, &fx_ibt_r7,
&fx_ibt_r8, &fx_ibt_r9, &fx_ibt_r10, &fx_ibt_r11, &fx_ibt_r12, &fx_ibt_r13, &fx_ibt_r14, &fx_ibt_r15,
/* b0 - bf */
&fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7,
&fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15,
/* c0 - cf */
&fx_hib, &fx_or_r1, &fx_or_r2, &fx_or_r3, &fx_or_r4, &fx_or_r5, &fx_or_r6, &fx_or_r7,
&fx_or_r8, &fx_or_r9, &fx_or_r10, &fx_or_r11, &fx_or_r12, &fx_or_r13, &fx_or_r14, &fx_or_r15,
/* d0 - df */
&fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7,
&fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc,
/* e0 - ef */
&fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7,
&fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getb,
/* f0 - ff */
&fx_iwt_r0, &fx_iwt_r1, &fx_iwt_r2, &fx_iwt_r3, &fx_iwt_r4, &fx_iwt_r5, &fx_iwt_r6, &fx_iwt_r7,
&fx_iwt_r8, &fx_iwt_r9, &fx_iwt_r10, &fx_iwt_r11, &fx_iwt_r12, &fx_iwt_r13, &fx_iwt_r14, &fx_iwt_r15,
 
/*
* ALT1 Table
*/
 
/* 00 - 0f */
&fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt,
&fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs,
/* 10 - 1f */
&fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7,
&fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15,
/* 20 - 2f */
&fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7,
&fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15,
/* 30 - 3f */
&fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7,
&fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3,
/* 40 - 4f */
&fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7,
&fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit,&fx_swap, &fx_cmode, &fx_not,
/* 50 - 5f */
&fx_adc_r0, &fx_adc_r1, &fx_adc_r2, &fx_adc_r3, &fx_adc_r4, &fx_adc_r5, &fx_adc_r6, &fx_adc_r7,
&fx_adc_r8, &fx_adc_r9, &fx_adc_r10, &fx_adc_r11, &fx_adc_r12, &fx_adc_r13, &fx_adc_r14, &fx_adc_r15,
/* 60 - 6f */
&fx_sbc_r0, &fx_sbc_r1, &fx_sbc_r2, &fx_sbc_r3, &fx_sbc_r4, &fx_sbc_r5, &fx_sbc_r6, &fx_sbc_r7,
&fx_sbc_r8, &fx_sbc_r9, &fx_sbc_r10, &fx_sbc_r11, &fx_sbc_r12, &fx_sbc_r13, &fx_sbc_r14, &fx_sbc_r15,
/* 70 - 7f */
&fx_merge, &fx_bic_r1, &fx_bic_r2, &fx_bic_r3, &fx_bic_r4, &fx_bic_r5, &fx_bic_r6, &fx_bic_r7,
&fx_bic_r8, &fx_bic_r9, &fx_bic_r10, &fx_bic_r11, &fx_bic_r12, &fx_bic_r13, &fx_bic_r14, &fx_bic_r15,
/* 80 - 8f */
&fx_umult_r0,&fx_umult_r1,&fx_umult_r2, &fx_umult_r3, &fx_umult_r4, &fx_umult_r5, &fx_umult_r6, &fx_umult_r7,
&fx_umult_r8,&fx_umult_r9,&fx_umult_r10,&fx_umult_r11,&fx_umult_r12,&fx_umult_r13,&fx_umult_r14,&fx_umult_r15,
/* 90 - 9f */
&fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_div2, &fx_ror,
&fx_ljmp_r8, &fx_ljmp_r9, &fx_ljmp_r10, &fx_ljmp_r11, &fx_ljmp_r12, &fx_ljmp_r13, &fx_lob, &fx_lmult,
/* a0 - af */
&fx_lms_r0, &fx_lms_r1, &fx_lms_r2, &fx_lms_r3, &fx_lms_r4, &fx_lms_r5, &fx_lms_r6, &fx_lms_r7,
&fx_lms_r8, &fx_lms_r9, &fx_lms_r10, &fx_lms_r11, &fx_lms_r12, &fx_lms_r13, &fx_lms_r14, &fx_lms_r15,
/* b0 - bf */
&fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7,
&fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15,
/* c0 - cf */
&fx_hib, &fx_xor_r1, &fx_xor_r2, &fx_xor_r3, &fx_xor_r4, &fx_xor_r5, &fx_xor_r6, &fx_xor_r7,
&fx_xor_r8, &fx_xor_r9, &fx_xor_r10, &fx_xor_r11, &fx_xor_r12, &fx_xor_r13, &fx_xor_r14, &fx_xor_r15,
/* d0 - df */
&fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7,
&fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_getc,
/* e0 - ef */
&fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7,
&fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbh,
/* f0 - ff */
&fx_lm_r0, &fx_lm_r1, &fx_lm_r2, &fx_lm_r3, &fx_lm_r4, &fx_lm_r5, &fx_lm_r6, &fx_lm_r7,
&fx_lm_r8, &fx_lm_r9, &fx_lm_r10, &fx_lm_r11, &fx_lm_r12, &fx_lm_r13, &fx_lm_r14, &fx_lm_r15,
 
/*
* ALT2 Table
*/
 
/* 00 - 0f */
&fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt,
&fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs,
/* 10 - 1f */
&fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7,
&fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15,
/* 20 - 2f */
&fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7,
&fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15,
/* 30 - 3f */
&fx_stw_r0, &fx_stw_r1, &fx_stw_r2, &fx_stw_r3, &fx_stw_r4, &fx_stw_r5, &fx_stw_r6, &fx_stw_r7,
&fx_stw_r8, &fx_stw_r9, &fx_stw_r10, &fx_stw_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3,
/* 40 - 4f */
&fx_ldw_r0, &fx_ldw_r1, &fx_ldw_r2, &fx_ldw_r3, &fx_ldw_r4, &fx_ldw_r5, &fx_ldw_r6, &fx_ldw_r7,
&fx_ldw_r8, &fx_ldw_r9, &fx_ldw_r10, &fx_ldw_r11, &fx_plot_2bit,&fx_swap, &fx_color, &fx_not,
/* 50 - 5f */
&fx_add_i0, &fx_add_i1, &fx_add_i2, &fx_add_i3, &fx_add_i4, &fx_add_i5, &fx_add_i6, &fx_add_i7,
&fx_add_i8, &fx_add_i9, &fx_add_i10, &fx_add_i11, &fx_add_i12, &fx_add_i13, &fx_add_i14, &fx_add_i15,
/* 60 - 6f */
&fx_sub_i0, &fx_sub_i1, &fx_sub_i2, &fx_sub_i3, &fx_sub_i4, &fx_sub_i5, &fx_sub_i6, &fx_sub_i7,
&fx_sub_i8, &fx_sub_i9, &fx_sub_i10, &fx_sub_i11, &fx_sub_i12, &fx_sub_i13, &fx_sub_i14, &fx_sub_i15,
/* 70 - 7f */
&fx_merge, &fx_and_i1, &fx_and_i2, &fx_and_i3, &fx_and_i4, &fx_and_i5, &fx_and_i6, &fx_and_i7,
&fx_and_i8, &fx_and_i9, &fx_and_i10, &fx_and_i11, &fx_and_i12, &fx_and_i13, &fx_and_i14, &fx_and_i15,
/* 80 - 8f */
&fx_mult_i0, &fx_mult_i1, &fx_mult_i2, &fx_mult_i3, &fx_mult_i4, &fx_mult_i5, &fx_mult_i6, &fx_mult_i7,
&fx_mult_i8, &fx_mult_i9, &fx_mult_i10, &fx_mult_i11, &fx_mult_i12, &fx_mult_i13, &fx_mult_i14, &fx_mult_i15,
/* 90 - 9f */
&fx_sbk, &fx_link_i1, &fx_link_i2, &fx_link_i3, &fx_link_i4, &fx_sex, &fx_asr, &fx_ror,
&fx_jmp_r8, &fx_jmp_r9, &fx_jmp_r10, &fx_jmp_r11, &fx_jmp_r12, &fx_jmp_r13, &fx_lob, &fx_fmult,
/* a0 - af */
&fx_sms_r0, &fx_sms_r1, &fx_sms_r2, &fx_sms_r3, &fx_sms_r4, &fx_sms_r5, &fx_sms_r6, &fx_sms_r7,
&fx_sms_r8, &fx_sms_r9, &fx_sms_r10, &fx_sms_r11, &fx_sms_r12, &fx_sms_r13, &fx_sms_r14, &fx_sms_r15,
/* b0 - bf */
&fx_from_r0, &fx_from_r1, &fx_from_r2, &fx_from_r3, &fx_from_r4, &fx_from_r5, &fx_from_r6, &fx_from_r7,
&fx_from_r8, &fx_from_r9, &fx_from_r10, &fx_from_r11, &fx_from_r12, &fx_from_r13, &fx_from_r14, &fx_from_r15,
/* c0 - cf */
&fx_hib, &fx_or_i1, &fx_or_i2, &fx_or_i3, &fx_or_i4, &fx_or_i5, &fx_or_i6, &fx_or_i7,
&fx_or_i8, &fx_or_i9, &fx_or_i10, &fx_or_i11, &fx_or_i12, &fx_or_i13, &fx_or_i14, &fx_or_i15,
/* d0 - df */
&fx_inc_r0, &fx_inc_r1, &fx_inc_r2, &fx_inc_r3, &fx_inc_r4, &fx_inc_r5, &fx_inc_r6, &fx_inc_r7,
&fx_inc_r8, &fx_inc_r9, &fx_inc_r10, &fx_inc_r11, &fx_inc_r12, &fx_inc_r13, &fx_inc_r14, &fx_ramb,
/* e0 - ef */
&fx_dec_r0, &fx_dec_r1, &fx_dec_r2, &fx_dec_r3, &fx_dec_r4, &fx_dec_r5, &fx_dec_r6, &fx_dec_r7,
&fx_dec_r8, &fx_dec_r9, &fx_dec_r10, &fx_dec_r11, &fx_dec_r12, &fx_dec_r13, &fx_dec_r14, &fx_getbl,
/* f0 - ff */
&fx_sm_r0, &fx_sm_r1, &fx_sm_r2, &fx_sm_r3, &fx_sm_r4, &fx_sm_r5, &fx_sm_r6, &fx_sm_r7,
&fx_sm_r8, &fx_sm_r9, &fx_sm_r10, &fx_sm_r11, &fx_sm_r12, &fx_sm_r13, &fx_sm_r14, &fx_sm_r15,
 
/*
* ALT3 Table
*/
 
/* 00 - 0f */
&fx_stop, &fx_nop, &fx_cache, &fx_lsr, &fx_rol, &fx_bra, &fx_bge, &fx_blt,
&fx_bne, &fx_beq, &fx_bpl, &fx_bmi, &fx_bcc, &fx_bcs, &fx_bvc, &fx_bvs,
/* 10 - 1f */
&fx_to_r0, &fx_to_r1, &fx_to_r2, &fx_to_r3, &fx_to_r4, &fx_to_r5, &fx_to_r6, &fx_to_r7,
&fx_to_r8, &fx_to_r9, &fx_to_r10, &fx_to_r11, &fx_to_r12, &fx_to_r13, &fx_to_r14, &fx_to_r15,
/* 20 - 2f */
&fx_with_r0, &fx_with_r1, &fx_with_r2, &fx_with_r3, &fx_with_r4, &fx_with_r5, &fx_with_r6, &fx_with_r7,
&fx_with_r8, &fx_with_r9, &fx_with_r10, &fx_with_r11, &fx_with_r12, &fx_with_r13, &fx_with_r14, &fx_with_r15,
/* 30 - 3f */
&fx_stb_r0, &fx_stb_r1, &fx_stb_r2, &fx_stb_r3, &fx_stb_r4, &fx_stb_r5, &fx_stb_r6, &fx_stb_r7,
&fx_stb_r8, &fx_stb_r9, &fx_stb_r10, &fx_stb_r11, &fx_loop, &fx_alt1, &fx_alt2, &fx_alt3,
/* 40 - 4f */
&fx_ldb_r0, &fx_ldb_r1, &fx_ldb_r2, &fx_ldb_r3, &fx_ldb_r4, &fx_ldb_r5, &fx_ldb_r6, &fx_ldb_r7,
&fx_ldb_r8, &fx_ldb_r9, &fx_ldb_r10, &fx_ldb_r11, &fx_rpix_2bit,&fx_swap, &fx_cmode, &fx_not,
/* 50 - 5f */
&fx_adc_i0, &fx_adc_i1, &fx_adc_i2, &fx_adc_i3, &fx_adc_i4, &fx_adc_i5, &fx_adc_i6, &fx_adc_i7,
&fx_adc_i8, &fx_adc_i9, &fx_adc_i10, &fx_adc_i11, &fx_adc_i12, &fx_adc_i13, &fx_adc_i14, &fx_adc_i15,
/* 60 - 6f */
&a